create static method

Future<LocordaGraph> create({
  1. required WorkerSetup workerSetup,
  2. void onWorkerSpawn()?,
  3. required SyncEngineConfig config,
  4. required StorageMainHandler storage,
  5. String jsScript = 'worker.dart.js',
  6. List<RemoteIntegration> remotes = const [],
  7. List<MainHandlerFactory> plugins = const [],
  8. IriTermFactory? iriTermFactory,
  9. RdfCore? rdfCore,
  10. String? debugName,
})

Creates LocordaGraph with SyncEngine running in a separate worker thread.

This is the graph-based alternative to Locorda.create(), providing direct RDF graph access without automatic object mapping.

Complete Example

1. Main thread:

import 'package:locorda_flutter_core/locorda_flutter_core.dart';
import 'package:locorda_rdf_core/core.dart';

// Initialize auth
final solidAuth = SolidAuth(...);
await solidAuth.init();

// Create LocordaGraph with worker architecture
final locordaGraph = await LocordaGraph.create(
  workerSetup: setupWorkerEngine,
  onWorkerSpawn: setupWorkerLogging,

  // Main thread handlers
  remotes: [SolidMainIntegration(solidAuth: solidAuth)],
  storage: DriftMainHandler(),

  // Low-level configuration with RDF IRIs
  config: SyncEngineConfig(
    resources: [
      ResourceTypeConfig(
        typeIri: IriTerm.validated('https://example.org/Note'),
        crdtMapping: Uri.parse('https://example.org/mappings/note-v1.ttl'),
        indices: [
          IndexConfig(
            name: 'notes_by_month',
            type: IndexType.group,
            rootResourceFetchPolicy: RootResourceFetchPolicy.prefetch,
          ),
        ],
      ),
    ],
  ),
);

// Work with RDF graphs directly
final noteGraph = RdfGraph.fromTriples([
  Triple(
    subject: IriTerm.validated('https://example.org/notes/123#it'),
    predicate: IriTerm.validated('http://schema.org/name'),
    object: LiteralTerm.string('My Note'),
  )]);

// Save to sync system
final noteTypeIri = IriTerm.validated('https://example.org/Note');
locordaGraph.syncEngine.save(noteTypeIri, noteGraph);

// Stream graph updates
locordaGraph.syncEngine.hydrateStream(
  typeIri: noteTypeIri,
).listen((batch) {
  for (final (iri, graph) in batch.updates) {
    // Process RdfGraph directly
    print('Updated: $iri');
    for (final triple in graph.triples) {
      print('  $triple');
    }
  }
});

2. Worker thread (same as Locorda):

import 'package:locorda/worker.dart';

void main() {
  workerMain(setupWorkerEngine, onWorkerSpawn: setupWorkerLogging);
}

Future<WorkerParams> setupWorkerEngine() async => WorkerParams(
  remotes: [SolidWorkerHandler()],
  storage: DriftWorkerHandler(...),
);

Architecture

Same worker architecture as Locorda, but without object mapping layer:

Main Thread:                    Worker Thread:
  ├─ LocordaGraph                 ├─ SyncEngine
  │  ├─ RdfGraph operations       │  ├─ CRDT merge
  │  │  (manual)                  │  ├─ Database I/O
  │  └─ ProxySyncEngine ─────────>│  ├─ HTTP requests
  │     (forwards calls)          │  └─ DPoP signing
  └─ UI                           └─ (heavy work here)

Key Differences from Locorda.create()

  • No mapperInitializer: You work with raw RDF graphs
  • Uses SyncEngineConfig: Direct IRI-based configuration instead of LocordaConfig
  • Manual serialization: You control RDF graph creation and parsing
  • Lower-level API: More control, less convenience

When to Use

  • Building RDF tools or editors
  • Dynamic schemas determined at runtime
  • Working with non-standard RDF patterns

For most applications, prefer Locorda.create() for type-safe Dart objects.

Parameters

  • workerSetup: Function that configures worker-side handlers
  • onWorkerSpawn: Optional callback for worker initialization
  • remotes: Main thread handlers for remote backends (Solid, GDrive, etc.)
  • storage: Main thread handler for storage backend
  • config: Low-level sync engine configuration with RDF IRIs
  • jsScript: Web worker JS filename (default: 'worker.dart.js')
  • plugins: Additional worker plugins for custom functionality
  • debugName: Optional name for debugging worker communication

Throws SyncConfigValidationException if the configuration is invalid.

Implementation

static Future<LocordaGraph> create({
  required WorkerSetup workerSetup,
  void onWorkerSpawn()?,
  required SyncEngineConfig config,
  required StorageMainHandler storage,
  String jsScript = 'worker.dart.js',
  List<RemoteIntegration> remotes = const [],
  List<MainHandlerFactory> plugins = const [],
  IriTermFactory? iriTermFactory,
  RdfCore? rdfCore,
  String? debugName,
}) async {
  final syncEngine = await SyncEngineWithWorker.create(
    jsScript: jsScript,
    workerSetup: workerSetup,
    remotes: remotes,
    storage: storage,
    plugins: plugins,
    syncEngineConfig: config,
    debugName: debugName,
    onWorkerSpawn: onWorkerSpawn,
  );
  return LocordaGraph._(
    syncEngine: syncEngine,
    uiAdapterRegistry: UiAdapterRegistry.withRemotes(remotes),
  );
}