Skip to content

API overview ​

Core surface of worker-sync-db. Types are inferred from your schema via defineSchema.

createDatabase(options) ​

typescript
function createDatabase<S extends CollectionSchema>(
  options: CreateDatabaseOptions<S>,
): Promise<DatabaseClient<S>>;

CreateDatabaseOptions ​

OptionTypeRequiredDescription
schemaS extends CollectionSchemayesCollection definitions
dbNamestringyesSharedWorker name + IndexedDB name
sharedWorkerstring | URLrecommendedURL to shared-worker bundle
dedicatedWorkerstring | URLrecommendedURL to dedicated-worker bundle
mode'auto' | 'shared' | 'dedicated'noDefault 'auto'
remoteRemoteSyncAdapter | FetchSyncConfignoEnables sync
onConflict(conflict) => voidnoPush conflicts (delegate adapter)

Throws if window is undefined (SSR).

Worker URL exports ​

typescript
import { sharedWorkerUrl, dedicatedWorkerUrl } from 'worker-sync-db';

URL objects pointing at dist/shared-worker/entry.js and dist/dedicated-worker/entry.js. Used as defaults when sharedWorker / dedicatedWorker are omitted.

DatabaseClient<S> ​

get(collection, id) ​

typescript
get<C extends keyof S & string>(
  collection: C,
  id: string,
): Promise<InferDoc<S, C> | null>;

Returns the document or null if missing or soft-deleted.

put(collection, doc) ​

typescript
put<C extends keyof S & string>(
  collection: C,
  doc: Record<string, unknown> & { id: string },
): Promise<InferDoc<S, C>>;

Upserts a document. Adds _version, _updatedAt. Enqueues a sync op when remote is set. Notifies all subscribed tabs.

delete(collection, id) ​

typescript
delete<C extends keyof S & string>(
  collection: C,
  id: string,
): Promise<InferDoc<S, C>>;

Soft-deletes (_deleted: true). Returns the updated document or throws NotFound.

query(collection, opts?) ​

typescript
query<C extends keyof S & string>(
  collection: C,
  opts?: QueryOptions,
): Promise<InferDoc<S, C>[]>;
QueryOptionsDescription
indexIndex name from schema
rangeIDBKeyRangeInit: both bounds → only/bound; only lower → lowerBound; only upper → upperBound
limitMaximum number of results
includeDeletedInclude soft-deleted documents

subscribe(collection, listener, filter?) ​

typescript
subscribe<C extends keyof S & string>(
  collection: C,
  listener: (event: ChangeEvent<InferDoc<S, C>>) => void,
  filter?: { field: string; value: unknown },
): () => void;

ChangeEvent:

typescript
{
  type: 'put' | 'delete';
  collection: string;
  doc: T | null;  // null on delete
  id: string;
}

Returns an unsubscribe function. Register in every tab that should receive live updates.

Optional filter limits worker fan-out to puts where doc[field] === value (deletes are not delivered when a filter is set). The filter is taken from the first subscriber for that collection in the tab.

Also receives changes applied from remote pull (not only local multi-tab writes).

syncNow() ​

typescript
syncNow(): Promise<SyncStatus>;

Pushes pending operations, then pulls remote changes. No-op queue flush if remote is not configured.

getSyncStatus() / onSyncStatusChange(listener) ​

typescript
interface SyncStatus {
  pending: number;
  lastSyncAt: number | null;
  lastError: string | null;
  online: boolean;
}

close() ​

Sends disconnect, closes the port, rejects in-flight RPCs.

Types ​

defineSchema / CollectionSchema ​

typescript
type CollectionSchema = Record<
  string,
  { keyPath: string; indexes?: Record<string, string> }
>;

function defineSchema<S extends CollectionSchema>(schema: S): S;

DocumentMeta ​

typescript
interface DocumentMeta {
  id: string;
  _version: number;
  _updatedAt: number;
  _deleted?: boolean;
}

Sync adapters ​

typescript
interface RemoteSyncAdapter {
  pull(cursor: string | null): Promise<{
    changes: RemoteChange[];
    nextCursor: string | null;
  }>;
  push(ops: PendingOp[]): Promise<{
    applied: string[];
    conflicts?: Conflict[];
  }>;
}

interface FetchSyncConfig {
  pullUrl: string;
  pushUrl: string;
  headers?: Record<string, string>;
}

Errors ​

DatabaseError with code:

CodeMeaning
NotFoundDocument missing on delete
WorkerDeadSharedWorker / Worker failed to load
SchemaMismatchDifferent schema for same dbName
NotConnectedPort closed
TimeoutRPC exceeded timeout (default 30s)
InvalidRequestUnknown request or aborted
StorageErrorIndexedDB / sync failure

Low-level API ​

For advanced integration without createDatabase:

  • connectSharedWorker(options) → PortBridge
  • connectDedicatedWorker(options) → PortBridge
  • PortBridge.call(request) — typed RPC
  • PortBridge.onEvent(listener) — worker events

See src/client/PortBridge.ts and src/shared/protocol.ts in the repository.

MIT License · offline-first IndexedDB with SharedWorker sync