syncorejs 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/_vendor/cli/app.d.mts.map +1 -1
- package/dist/_vendor/cli/app.mjs +330 -46
- package/dist/_vendor/cli/app.mjs.map +1 -1
- package/dist/_vendor/cli/context.mjs +27 -9
- package/dist/_vendor/cli/context.mjs.map +1 -1
- package/dist/_vendor/cli/dev-session.mjs.map +1 -1
- package/dist/_vendor/cli/doctor.mjs +513 -46
- package/dist/_vendor/cli/doctor.mjs.map +1 -1
- package/dist/_vendor/cli/errors.mjs.map +1 -1
- package/dist/_vendor/cli/help.mjs.map +1 -1
- package/dist/_vendor/cli/index.mjs +9 -2
- package/dist/_vendor/cli/index.mjs.map +1 -1
- package/dist/_vendor/cli/messages.mjs +5 -4
- package/dist/_vendor/cli/messages.mjs.map +1 -1
- package/dist/_vendor/cli/preflight.mjs.map +1 -1
- package/dist/_vendor/cli/project.mjs +125 -27
- package/dist/_vendor/cli/project.mjs.map +1 -1
- package/dist/_vendor/cli/render.mjs +57 -9
- package/dist/_vendor/cli/render.mjs.map +1 -1
- package/dist/_vendor/cli/targets.mjs +4 -3
- package/dist/_vendor/cli/targets.mjs.map +1 -1
- package/dist/_vendor/core/cli.d.mts +20 -4
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +458 -133
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/devtools-auth.mjs +60 -0
- package/dist/_vendor/core/devtools-auth.mjs.map +1 -0
- package/dist/_vendor/core/index.d.mts +5 -3
- package/dist/_vendor/core/index.mjs +22 -2
- package/dist/_vendor/core/index.mjs.map +1 -1
- package/dist/_vendor/core/runtime/components.d.mts +111 -0
- package/dist/_vendor/core/runtime/components.d.mts.map +1 -0
- package/dist/_vendor/core/runtime/components.mjs +186 -0
- package/dist/_vendor/core/runtime/components.mjs.map +1 -0
- package/dist/_vendor/core/runtime/devtools.d.mts +4 -4
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +178 -60
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.d.mts +398 -16
- package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs +74 -3
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
- package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/id.mjs.map +1 -1
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +83 -0
- package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +720 -0
- package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +234 -0
- package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +255 -0
- package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +200 -0
- package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs +252 -0
- package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +145 -0
- package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +221 -0
- package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs +32 -0
- package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs +61 -0
- package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +41 -0
- package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -0
- package/dist/_vendor/core/runtime/runtime.d.mts +1187 -202
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +73 -1365
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/core/transport.d.mts +113 -0
- package/dist/_vendor/core/transport.d.mts.map +1 -0
- package/dist/_vendor/core/transport.mjs +428 -0
- package/dist/_vendor/core/transport.mjs.map +1 -0
- package/dist/_vendor/devtools-protocol/index.d.ts +187 -4
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js +25 -9
- package/dist/_vendor/devtools-protocol/index.js.map +1 -1
- package/dist/_vendor/next/config.d.ts +3 -4
- package/dist/_vendor/next/config.d.ts.map +1 -1
- package/dist/_vendor/next/config.js +37 -19
- package/dist/_vendor/next/config.js.map +1 -1
- package/dist/_vendor/next/index.d.ts +109 -29
- package/dist/_vendor/next/index.d.ts.map +1 -1
- package/dist/_vendor/next/index.js +104 -26
- package/dist/_vendor/next/index.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +156 -37
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +80 -12
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/react.js +11 -10
- package/dist/_vendor/platform-expo/react.js.map +1 -1
- package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
- package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
- package/dist/_vendor/platform-node/index.d.mts +192 -24
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +236 -97
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs +15 -2
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc.d.mts +11 -35
- package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
- package/dist/_vendor/platform-node/ipc.mjs +3 -273
- package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +43 -1
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
- package/dist/_vendor/platform-web/external-change.js +32 -1
- package/dist/_vendor/platform-web/external-change.js.map +1 -1
- package/dist/_vendor/platform-web/index.d.ts +323 -51
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +233 -30
- package/dist/_vendor/platform-web/index.js.map +1 -1
- package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
- package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
- package/dist/_vendor/platform-web/indexeddb.js +10 -0
- package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
- package/dist/_vendor/platform-web/opfs.d.ts +13 -0
- package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
- package/dist/_vendor/platform-web/opfs.js +12 -0
- package/dist/_vendor/platform-web/opfs.js.map +1 -1
- package/dist/_vendor/platform-web/persistence.d.ts +54 -0
- package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
- package/dist/_vendor/platform-web/persistence.js +15 -0
- package/dist/_vendor/platform-web/persistence.js.map +1 -1
- package/dist/_vendor/platform-web/react.d.ts +1 -2
- package/dist/_vendor/platform-web/react.d.ts.map +1 -1
- package/dist/_vendor/platform-web/react.js +27 -13
- package/dist/_vendor/platform-web/react.js.map +1 -1
- package/dist/_vendor/platform-web/sqljs.js +10 -1
- package/dist/_vendor/platform-web/sqljs.js.map +1 -1
- package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
- package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
- package/dist/_vendor/platform-web/worker.d.ts +71 -44
- package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
- package/dist/_vendor/platform-web/worker.js +40 -271
- package/dist/_vendor/platform-web/worker.js.map +1 -1
- package/dist/_vendor/react/index.d.ts +222 -23
- package/dist/_vendor/react/index.d.ts.map +1 -1
- package/dist/_vendor/react/index.js +476 -63
- package/dist/_vendor/react/index.js.map +1 -1
- package/dist/_vendor/schema/definition.d.ts +151 -37
- package/dist/_vendor/schema/definition.d.ts.map +1 -1
- package/dist/_vendor/schema/definition.js +102 -20
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/index.d.ts +4 -4
- package/dist/_vendor/schema/index.js +2 -2
- package/dist/_vendor/schema/planner.d.ts +19 -2
- package/dist/_vendor/schema/planner.d.ts.map +1 -1
- package/dist/_vendor/schema/planner.js +79 -3
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.d.ts +279 -83
- package/dist/_vendor/schema/validators.d.ts.map +1 -1
- package/dist/_vendor/schema/validators.js +330 -38
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/_vendor/svelte/index.d.ts +245 -19
- package/dist/_vendor/svelte/index.d.ts.map +1 -1
- package/dist/_vendor/svelte/index.js +443 -20
- package/dist/_vendor/svelte/index.js.map +1 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/components.d.ts +2 -0
- package/dist/components.js +2 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -1
- package/package.json +29 -21
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc.mjs","names":[],"sources":["../src/ipc.ts"],"sourcesContent":["import {\n generateId,\n type AnySyncoreSchema,\n type FunctionReference,\n type JsonObject,\n type SyncoreClient,\n type SyncoreRuntime,\n type SyncoreWatch\n} from \"@syncore/core\";\n\nexport type NodeIpcSyncoreSchema = AnySyncoreSchema;\n\nexport interface SyncoreIpcMessageEndpoint {\n postMessage(message: unknown): void;\n addEventListener(\n type: \"message\",\n listener: (event: MessageEvent<unknown>) => void\n ): void;\n removeEventListener(\n type: \"message\",\n listener: (event: MessageEvent<unknown>) => void\n ): void;\n}\n\ntype SyncoreIpcRequest =\n | {\n type: \"invoke\";\n requestId: string;\n kind: \"query\";\n reference: FunctionReference<\"query\", unknown, unknown>;\n args: JsonObject;\n }\n | {\n type: \"invoke\";\n requestId: string;\n kind: \"mutation\";\n reference: FunctionReference<\"mutation\", unknown, unknown>;\n args: JsonObject;\n }\n | {\n type: \"invoke\";\n requestId: string;\n kind: \"action\";\n reference: FunctionReference<\"action\", unknown, unknown>;\n args: JsonObject;\n }\n | {\n type: \"watch.subscribe\";\n subscriptionId: string;\n reference: FunctionReference<\"query\", unknown, unknown>;\n args: JsonObject;\n }\n | {\n type: \"watch.unsubscribe\";\n subscriptionId: string;\n };\n\ntype SyncoreIpcResponse =\n | {\n type: \"runtime.ready\";\n }\n | {\n type: \"runtime.error\";\n error: string;\n }\n | {\n type: \"invoke.result\";\n requestId: string;\n success: true;\n value: unknown;\n }\n | {\n type: \"invoke.result\";\n requestId: string;\n success: false;\n error: string;\n }\n | {\n type: \"watch.update\";\n subscriptionId: string;\n success: true;\n value: unknown;\n }\n | {\n type: \"watch.update\";\n subscriptionId: string;\n success: false;\n error: string;\n };\n\ninterface PendingRequest {\n resolve(value: unknown): void;\n reject(error: Error): void;\n}\n\ninterface WatchRecord {\n subscriptionId: string;\n listeners: Set<() => void>;\n consumers: number;\n result: unknown;\n error: Error | undefined;\n}\n\nexport type RendererQueryWatch<TValue> = SyncoreWatch<TValue> & {\n dispose(): void;\n};\n\ntype OptionalArgsTuple<TArgs> =\n Record<never, never> extends TArgs ? [args?: TArgs] : [args: TArgs];\n\nexport class SyncoreRendererClient implements SyncoreClient {\n private readonly pendingRequests = new Map<string, PendingRequest>();\n private readonly watchRecordsByKey = new Map<string, WatchRecord>();\n private readonly watchKeyBySubscriptionId = new Map<string, string>();\n private disposed = false;\n\n private readonly handleMessage = (event: MessageEvent<unknown>) => {\n const message = event.data as SyncoreIpcResponse;\n if (!message || typeof message !== \"object\" || !(\"type\" in message)) {\n return;\n }\n\n switch (message.type) {\n case \"runtime.ready\":\n return;\n case \"runtime.error\":\n this.rejectAllPending(new Error(message.error));\n return;\n case \"invoke.result\": {\n const pending = this.pendingRequests.get(message.requestId);\n if (!pending) {\n return;\n }\n this.pendingRequests.delete(message.requestId);\n if (message.success) {\n pending.resolve(message.value);\n } else {\n pending.reject(new Error(message.error));\n }\n return;\n }\n case \"watch.update\": {\n const watchKey = this.watchKeyBySubscriptionId.get(\n message.subscriptionId\n );\n if (!watchKey) {\n return;\n }\n const watchRecord = this.watchRecordsByKey.get(watchKey);\n if (!watchRecord) {\n return;\n }\n if (message.success) {\n watchRecord.result = message.value;\n watchRecord.error = undefined;\n } else {\n watchRecord.error = new Error(message.error);\n }\n for (const listener of watchRecord.listeners) {\n listener();\n }\n }\n }\n };\n\n constructor(private readonly endpoint: SyncoreIpcMessageEndpoint) {\n this.endpoint.addEventListener(\"message\", this.handleMessage);\n }\n\n query<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs>\n ): Promise<TResult> {\n return this.invoke(\n \"query\",\n reference,\n normalizeOptionalArgs(args) as JsonObject\n );\n }\n\n mutation<TArgs, TResult>(\n reference: FunctionReference<\"mutation\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs>\n ): Promise<TResult> {\n return this.invoke(\n \"mutation\",\n reference,\n normalizeOptionalArgs(args) as JsonObject\n );\n }\n\n action<TArgs, TResult>(\n reference: FunctionReference<\"action\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs>\n ): Promise<TResult> {\n return this.invoke(\n \"action\",\n reference,\n normalizeOptionalArgs(args) as JsonObject\n );\n }\n\n watchQuery<TArgs, TResult>(\n reference: FunctionReference<\"query\", TArgs, TResult>,\n ...args: OptionalArgsTuple<TArgs>\n ): RendererQueryWatch<TResult> {\n this.ensureNotDisposed();\n const normalizedArgs = normalizeOptionalArgs(args) as JsonObject;\n const watchKey = createWatchKey(reference, normalizedArgs);\n let watchRecord = this.watchRecordsByKey.get(watchKey);\n if (!watchRecord) {\n watchRecord = {\n subscriptionId: generateId(),\n listeners: new Set<() => void>(),\n consumers: 0,\n result: undefined,\n error: undefined\n };\n this.watchRecordsByKey.set(watchKey, watchRecord);\n this.watchKeyBySubscriptionId.set(watchRecord.subscriptionId, watchKey);\n this.endpoint.postMessage({\n type: \"watch.subscribe\",\n subscriptionId: watchRecord.subscriptionId,\n reference,\n args: normalizedArgs\n } satisfies SyncoreIpcRequest);\n }\n\n watchRecord.consumers += 1;\n let disposed = false;\n const ownedListeners = new Set<() => void>();\n\n return {\n onUpdate: (callback) => {\n watchRecord.listeners.add(callback);\n ownedListeners.add(callback);\n queueMicrotask(callback);\n return () => {\n watchRecord.listeners.delete(callback);\n ownedListeners.delete(callback);\n };\n },\n localQueryResult: () => watchRecord.result as TResult | undefined,\n localQueryError: () => watchRecord.error,\n dispose: () => {\n if (disposed) {\n return;\n }\n disposed = true;\n for (const callback of ownedListeners) {\n watchRecord.listeners.delete(callback);\n }\n ownedListeners.clear();\n watchRecord.consumers = Math.max(0, watchRecord.consumers - 1);\n if (watchRecord.consumers > 0) {\n return;\n }\n this.endpoint.postMessage({\n type: \"watch.unsubscribe\",\n subscriptionId: watchRecord.subscriptionId\n } satisfies SyncoreIpcRequest);\n this.watchKeyBySubscriptionId.delete(watchRecord.subscriptionId);\n this.watchRecordsByKey.delete(watchKey);\n }\n };\n }\n\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.endpoint.removeEventListener(\"message\", this.handleMessage);\n for (const watchRecord of this.watchRecordsByKey.values()) {\n this.endpoint.postMessage({\n type: \"watch.unsubscribe\",\n subscriptionId: watchRecord.subscriptionId\n } satisfies SyncoreIpcRequest);\n }\n this.watchKeyBySubscriptionId.clear();\n this.watchRecordsByKey.clear();\n this.rejectAllPending(new Error(\"Syncore renderer client was disposed.\"));\n }\n\n private invoke<TArgs, TResult>(\n kind: \"query\",\n reference: FunctionReference<\"query\", TArgs, TResult>,\n args: JsonObject\n ): Promise<TResult>;\n private invoke<TArgs, TResult>(\n kind: \"mutation\",\n reference: FunctionReference<\"mutation\", TArgs, TResult>,\n args: JsonObject\n ): Promise<TResult>;\n private invoke<TArgs, TResult>(\n kind: \"action\",\n reference: FunctionReference<\"action\", TArgs, TResult>,\n args: JsonObject\n ): Promise<TResult>;\n private invoke<TArgs, TResult>(\n kind: \"query\" | \"mutation\" | \"action\",\n reference: FunctionReference<\n \"query\" | \"mutation\" | \"action\",\n TArgs,\n TResult\n >,\n args: JsonObject\n ): Promise<TResult> {\n this.ensureNotDisposed();\n const requestId = generateId();\n const promise = new Promise<TResult>((resolve, reject) => {\n this.pendingRequests.set(requestId, { resolve, reject });\n });\n\n switch (kind) {\n case \"query\":\n case \"mutation\":\n case \"action\":\n this.endpoint.postMessage(\n createInvokeRequest(requestId, kind, reference, args)\n );\n break;\n }\n\n return promise;\n }\n\n private rejectAllPending(error: Error): void {\n for (const pending of this.pendingRequests.values()) {\n pending.reject(error);\n }\n this.pendingRequests.clear();\n }\n\n private ensureNotDisposed(): void {\n if (this.disposed) {\n throw new Error(\"Syncore renderer client was disposed.\");\n }\n }\n}\n\nexport interface AttachNodeIpcRuntimeOptions {\n endpoint: SyncoreIpcMessageEndpoint;\n createRuntime:\n | (() => Promise<SyncoreRuntime<NodeIpcSyncoreSchema>>)\n | (() => SyncoreRuntime<NodeIpcSyncoreSchema>);\n}\n\nexport interface SyncoreRendererBridge {\n postMessage(message: unknown): void;\n onMessage(listener: (message: unknown) => void): () => void;\n}\n\nexport interface SyncoreWindowBridge {\n postMessage(message: unknown): void;\n onMessage(listener: (message: unknown) => void): () => void;\n}\n\nexport interface SyncoreMainProcessBridge {\n postMessage(message: unknown): void;\n onMessage(listener: (message: unknown) => void): () => void;\n}\n\n/**\n * Install the default Electron preload bridge used by Syncore renderer helpers.\n */\nexport function installSyncoreWindowBridge(options?: {\n bridgeName?: string;\n}): string {\n return `(function(){const bridgeName=${JSON.stringify(options?.bridgeName ?? \"syncoreBridge\")};const {contextBridge,ipcRenderer}=require(\"electron\");const channel=\"syncore:message\";const listeners=new Map();contextBridge.exposeInMainWorld(bridgeName,{postMessage(message){ipcRenderer.send(channel,message);},onMessage(listener){const wrapped=(_event,payload)=>{listener(payload);};listeners.set(listener,wrapped);ipcRenderer.on(channel,wrapped);return()=>{ipcRenderer.off(channel,wrapped);listeners.delete(listener);};}});})();`;\n}\n\nexport interface AttachedNodeIpcRuntime {\n ready: Promise<void>;\n dispose(): Promise<void>;\n}\n\n/**\n * Create a renderer client from a low-level IPC message endpoint.\n */\nexport function createRendererSyncoreClient(\n endpoint: SyncoreIpcMessageEndpoint\n): SyncoreRendererClient {\n return new SyncoreRendererClient(endpoint);\n}\n\n/**\n * Create a renderer client from a bridge object exposed by preload code.\n */\nexport function createRendererSyncoreBridgeClient(\n bridge: SyncoreRendererBridge\n): SyncoreRendererClient {\n const listeners = new Map<\n (event: MessageEvent<unknown>) => void,\n () => void\n >();\n\n return createRendererSyncoreClient({\n postMessage(message) {\n bridge.postMessage(message);\n },\n addEventListener(_type, listener) {\n listeners.set(\n listener,\n bridge.onMessage((message) => {\n listener({ data: message } as MessageEvent<unknown>);\n })\n );\n },\n removeEventListener(_type, listener) {\n listeners.get(listener)?.();\n listeners.delete(listener);\n }\n });\n}\n\n/**\n * Create a renderer client from `window.syncoreBridge` or another named bridge.\n */\nexport function createRendererSyncoreWindowClient(\n windowObject: Window & typeof globalThis,\n bridgeName = \"syncoreBridge\"\n): SyncoreRendererClient {\n const bridge = (\n windowObject as typeof windowObject & Record<string, unknown>\n )[bridgeName];\n if (!bridge || typeof bridge !== \"object\") {\n throw new Error(`Missing window.${bridgeName} bridge.`);\n }\n\n const candidate = bridge as SyncoreWindowBridge;\n if (\n typeof candidate.postMessage !== \"function\" ||\n typeof candidate.onMessage !== \"function\"\n ) {\n throw new Error(\n `window.${bridgeName} must expose postMessage() and onMessage().`\n );\n }\n\n return createRendererSyncoreBridgeClient(candidate);\n}\n\nexport function createNodeIpcMessageEndpoint(\n bridge: SyncoreMainProcessBridge\n): SyncoreIpcMessageEndpoint & { dispose(): void } {\n const listeners = new Map<\n (event: MessageEvent<unknown>) => void,\n () => void\n >();\n\n return {\n postMessage(message) {\n bridge.postMessage(message);\n },\n addEventListener(_type, listener) {\n listeners.set(\n listener,\n bridge.onMessage((message) => {\n listener({ data: message } as MessageEvent<unknown>);\n })\n );\n },\n removeEventListener(_type, listener) {\n listeners.get(listener)?.();\n listeners.delete(listener);\n },\n dispose() {\n for (const dispose of listeners.values()) {\n dispose();\n }\n listeners.clear();\n }\n };\n}\n\nexport function attachNodeIpcRuntime(\n options: AttachNodeIpcRuntimeOptions\n): AttachedNodeIpcRuntime {\n const subscriptions = new Map<\n string,\n {\n watch: SyncoreWatch<unknown>;\n unsubscribe: () => void;\n }\n >();\n\n const runtimePromise = Promise.resolve(options.createRuntime()).then(\n async (runtime) => {\n await runtime.start();\n return runtime;\n }\n );\n\n const clientPromise = runtimePromise.then((runtime) =>\n runtime.createClient()\n );\n\n const ready = clientPromise\n .then(() => {\n options.endpoint.postMessage({\n type: \"runtime.ready\"\n } satisfies SyncoreIpcResponse);\n })\n .catch((error) => {\n options.endpoint.postMessage({\n type: \"runtime.error\",\n error: error instanceof Error ? error.message : String(error)\n } satisfies SyncoreIpcResponse);\n throw error;\n });\n\n const handleMessage = (event: MessageEvent<unknown>) => {\n void (async () => {\n const message = event.data as SyncoreIpcRequest;\n if (!message || typeof message !== \"object\" || !(\"type\" in message)) {\n return;\n }\n\n try {\n const client = await clientPromise;\n switch (message.type) {\n case \"invoke\": {\n const value =\n message.kind === \"query\"\n ? await client.query(message.reference, message.args)\n : message.kind === \"mutation\"\n ? await client.mutation(message.reference, message.args)\n : await client.action(message.reference, message.args);\n options.endpoint.postMessage({\n type: \"invoke.result\",\n requestId: message.requestId,\n success: true,\n value\n } satisfies SyncoreIpcResponse);\n return;\n }\n case \"watch.subscribe\": {\n if (subscriptions.has(message.subscriptionId)) {\n return;\n }\n const watch = client.watchQuery(message.reference, message.args);\n const sendCurrentState = () => {\n const error = watch.localQueryError();\n if (error) {\n options.endpoint.postMessage({\n type: \"watch.update\",\n subscriptionId: message.subscriptionId,\n success: false,\n error: error.message\n } satisfies SyncoreIpcResponse);\n return;\n }\n options.endpoint.postMessage({\n type: \"watch.update\",\n subscriptionId: message.subscriptionId,\n success: true,\n value: watch.localQueryResult()\n } satisfies SyncoreIpcResponse);\n };\n const unsubscribe = watch.onUpdate(sendCurrentState);\n subscriptions.set(message.subscriptionId, { watch, unsubscribe });\n sendCurrentState();\n return;\n }\n case \"watch.unsubscribe\": {\n const subscription = subscriptions.get(message.subscriptionId);\n if (!subscription) {\n return;\n }\n subscription.unsubscribe();\n subscriptions.delete(message.subscriptionId);\n }\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n if (message.type === \"invoke\") {\n options.endpoint.postMessage({\n type: \"invoke.result\",\n requestId: message.requestId,\n success: false,\n error: errorMessage\n } satisfies SyncoreIpcResponse);\n }\n if (message.type === \"watch.subscribe\") {\n options.endpoint.postMessage({\n type: \"watch.update\",\n subscriptionId: message.subscriptionId,\n success: false,\n error: errorMessage\n } satisfies SyncoreIpcResponse);\n }\n }\n })();\n };\n\n options.endpoint.addEventListener(\"message\", handleMessage);\n\n return {\n ready,\n async dispose() {\n options.endpoint.removeEventListener(\"message\", handleMessage);\n for (const subscription of subscriptions.values()) {\n subscription.unsubscribe();\n }\n subscriptions.clear();\n const runtime = await runtimePromise;\n await runtime.stop();\n }\n };\n}\n\nfunction createInvokeRequest(\n requestId: string,\n kind: \"query\" | \"mutation\" | \"action\",\n reference:\n | FunctionReference<\"query\", unknown, unknown>\n | FunctionReference<\"mutation\", unknown, unknown>\n | FunctionReference<\"action\", unknown, unknown>,\n args: JsonObject\n): SyncoreIpcRequest {\n switch (kind) {\n case \"query\":\n return {\n type: \"invoke\",\n requestId,\n kind,\n reference: reference as FunctionReference<\"query\">,\n args\n };\n case \"mutation\":\n return {\n type: \"invoke\",\n requestId,\n kind,\n reference: reference as FunctionReference<\"mutation\">,\n args\n };\n case \"action\":\n return {\n type: \"invoke\",\n requestId,\n kind,\n reference: reference as FunctionReference<\"action\">,\n args\n };\n }\n}\n\nfunction createWatchKey(\n reference: FunctionReference<\"query\", unknown, unknown>,\n args: JsonObject\n): string {\n return `${reference.name}:${stableStringify(args)}`;\n}\n\nfunction normalizeOptionalArgs<TArgs>(\n args: [] | [TArgs] | readonly unknown[]\n): TArgs {\n return (args[0] ?? {}) as TArgs;\n}\n\nfunction stableStringify(value: unknown): string {\n return JSON.stringify(sortValue(value));\n}\n\nfunction sortValue(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortValue);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, nested]) => [key, sortValue(nested)])\n );\n }\n return value;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ipc.mjs","names":[],"sources":["../src/ipc.ts"],"sourcesContent":["import {\n attachRuntimeBridge,\n type AttachRuntimeBridgeOptions,\n type AttachedRuntimeBridge,\n type BridgeQueryWatch,\n SyncoreBridgeClient,\n type SyncoreBridgeMessageEndpoint,\n type SyncoreDataModel\n} from \"@syncore/core\";\n\nexport type NodeIpcSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = TSchema;\nexport type SyncoreIpcMessageEndpoint = SyncoreBridgeMessageEndpoint;\nexport type RendererQueryWatch<TValue> = BridgeQueryWatch<TValue>;\n\nexport class SyncoreRendererClient extends SyncoreBridgeClient {\n declare query: SyncoreBridgeClient[\"query\"];\n declare mutation: SyncoreBridgeClient[\"mutation\"];\n declare action: SyncoreBridgeClient[\"action\"];\n declare watchQuery: SyncoreBridgeClient[\"watchQuery\"];\n}\n\nexport type AttachNodeIpcRuntimeOptions<\n TSchema extends NodeIpcSyncoreSchema = NodeIpcSyncoreSchema\n> = AttachRuntimeBridgeOptions<TSchema>;\nexport type AttachedNodeIpcRuntime = AttachedRuntimeBridge;\n\nexport interface SyncoreRendererBridge {\n postMessage(message: unknown): void;\n onMessage(listener: (message: unknown) => void): () => void;\n}\n\nexport interface SyncoreWindowBridge {\n postMessage(message: unknown): void;\n onMessage(listener: (message: unknown) => void): () => void;\n}\n\nexport interface SyncoreMainProcessBridge {\n postMessage(message: unknown): void;\n onMessage(listener: (message: unknown) => void): () => void;\n}\n\n/**\n * Install the default Electron preload bridge used by Syncore renderer helpers.\n */\nexport function installSyncoreWindowBridge(options?: {\n bridgeName?: string;\n}): string {\n return `(function(){const bridgeName=${JSON.stringify(options?.bridgeName ?? \"syncoreBridge\")};const {contextBridge,ipcRenderer}=require(\"electron\");const channel=\"syncore:message\";const listeners=new Map();contextBridge.exposeInMainWorld(bridgeName,{postMessage(message){ipcRenderer.send(channel,message);},onMessage(listener){const wrapped=(_event,payload)=>{listener(payload);};listeners.set(listener,wrapped);ipcRenderer.on(channel,wrapped);return()=>{ipcRenderer.off(channel,wrapped);listeners.delete(listener);};}});})();`;\n}\n\n/**\n * Create a renderer client from a low-level IPC message endpoint.\n */\nexport function createRendererSyncoreClient(\n endpoint: SyncoreIpcMessageEndpoint\n): SyncoreRendererClient {\n return new SyncoreRendererClient(endpoint);\n}\n\n/**\n * Create a renderer client from a bridge object exposed by preload code.\n */\nexport function createRendererSyncoreBridgeClient(\n bridge: SyncoreRendererBridge\n): SyncoreRendererClient {\n const listeners = new Map<\n (event: MessageEvent<unknown>) => void,\n () => void\n >();\n\n return createRendererSyncoreClient({\n postMessage(message) {\n bridge.postMessage(message);\n },\n addEventListener(_type, listener) {\n listeners.set(\n listener,\n bridge.onMessage((message) => {\n listener({ data: message } as MessageEvent<unknown>);\n })\n );\n },\n removeEventListener(_type, listener) {\n listeners.get(listener)?.();\n listeners.delete(listener);\n }\n });\n}\n\n/**\n * Create a renderer client from `window.syncoreBridge` or another named bridge.\n */\nexport function createRendererSyncoreWindowClient(\n windowObject: Window & typeof globalThis,\n bridgeName = \"syncoreBridge\"\n): SyncoreRendererClient {\n const bridge = (\n windowObject as typeof windowObject & Record<string, unknown>\n )[bridgeName];\n if (!bridge || typeof bridge !== \"object\") {\n throw new Error(`Missing window.${bridgeName} bridge.`);\n }\n\n const candidate = bridge as SyncoreWindowBridge;\n if (\n typeof candidate.postMessage !== \"function\" ||\n typeof candidate.onMessage !== \"function\"\n ) {\n throw new Error(\n `window.${bridgeName} must expose postMessage() and onMessage().`\n );\n }\n\n return createRendererSyncoreBridgeClient(candidate);\n}\n\nexport function createNodeIpcMessageEndpoint(\n bridge: SyncoreMainProcessBridge\n): SyncoreIpcMessageEndpoint & { dispose(): void } {\n const listeners = new Map<\n (event: MessageEvent<unknown>) => void,\n () => void\n >();\n\n return {\n postMessage(message) {\n bridge.postMessage(message);\n },\n addEventListener(_type, listener) {\n listeners.set(\n listener,\n bridge.onMessage((message) => {\n listener({ data: message } as MessageEvent<unknown>);\n })\n );\n },\n removeEventListener(_type, listener) {\n listeners.get(listener)?.();\n listeners.delete(listener);\n },\n dispose() {\n for (const dispose of listeners.values()) {\n dispose();\n }\n listeners.clear();\n }\n };\n}\n\nexport function attachNodeIpcRuntime(\n options: AttachNodeIpcRuntimeOptions\n): AttachedNodeIpcRuntime {\n return attachRuntimeBridge(options);\n}\n"],"mappings":";;AAgBA,IAAa,wBAAb,cAA2C,oBAAoB,CAK/D;;;;AAyBA,SAAgB,2BAA2B,SAEhC;CACT,OAAO,gCAAgC,KAAK,UAAU,SAAS,cAAc,eAAe,EAAE;AAChG;;;;AAKA,SAAgB,4BACd,UACuB;CACvB,OAAO,IAAI,sBAAsB,QAAQ;AAC3C;;;;AAKA,SAAgB,kCACd,QACuB;CACvB,MAAM,4BAAY,IAAI,IAGpB;CAEF,OAAO,4BAA4B;EACjC,YAAY,SAAS;GACnB,OAAO,YAAY,OAAO;EAC5B;EACA,iBAAiB,OAAO,UAAU;GAChC,UAAU,IACR,UACA,OAAO,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,QAAQ,CAA0B;GACrD,CAAC,CACH;EACF;EACA,oBAAoB,OAAO,UAAU;GACnC,UAAU,IAAI,QAAQ,IAAI;GAC1B,UAAU,OAAO,QAAQ;EAC3B;CACF,CAAC;AACH;;;;AAKA,SAAgB,kCACd,cACA,aAAa,iBACU;CACvB,MAAM,SACJ,aACA;CACF,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,MAAM,IAAI,MAAM,kBAAkB,WAAW,SAAS;CAGxD,MAAM,YAAY;CAClB,IACE,OAAO,UAAU,gBAAgB,cACjC,OAAO,UAAU,cAAc,YAE/B,MAAM,IAAI,MACR,UAAU,WAAW,4CACvB;CAGF,OAAO,kCAAkC,SAAS;AACpD;AAEA,SAAgB,6BACd,QACiD;CACjD,MAAM,4BAAY,IAAI,IAGpB;CAEF,OAAO;EACL,YAAY,SAAS;GACnB,OAAO,YAAY,OAAO;EAC5B;EACA,iBAAiB,OAAO,UAAU;GAChC,UAAU,IACR,UACA,OAAO,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,QAAQ,CAA0B;GACrD,CAAC,CACH;EACF;EACA,oBAAoB,OAAO,UAAU;GACnC,UAAU,IAAI,QAAQ,IAAI;GAC1B,UAAU,OAAO,QAAQ;EAC3B;EACA,UAAU;GACR,KAAK,MAAM,WAAW,UAAU,OAAO,GACrC,QAAQ;GAEV,UAAU,MAAM;EAClB;CACF;AACF;AAEA,SAAgB,qBACd,SACwB;CACxB,OAAO,oBAAoB,OAAO;AACpC"}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
import { SyncoreWebPersistence } from "./persistence.js";
|
|
2
|
-
import { SyncoreExternalChangeApplier, SyncoreExternalChangeEvent, SyncoreExternalChangeSignal } from "../core/index.d.mts";
|
|
2
|
+
import { ImpactScope, SyncoreExternalChangeApplier, SyncoreExternalChangeEvent, SyncoreExternalChangeSignal } from "../core/index.d.mts";
|
|
3
3
|
import initSqlJs from "sql.js";
|
|
4
4
|
|
|
5
5
|
//#region src/external-change.d.ts
|
|
6
6
|
type SqlJsDatabase = initSqlJs.Database;
|
|
7
|
+
/** Options for constructing a {@link BroadcastChannelExternalChangeSignal}. */
|
|
7
8
|
interface BroadcastChannelExternalChangeSignalOptions {
|
|
9
|
+
/** Name of the `BroadcastChannel`, shared by all tabs with the same database. */
|
|
8
10
|
channelName: string;
|
|
9
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* A `BroadcastChannel`-based {@link SyncoreExternalChangeSignal} that
|
|
14
|
+
* propagates database-mutation events across all browser tabs sharing the same
|
|
15
|
+
* Syncore database.
|
|
16
|
+
*
|
|
17
|
+
* When a Syncore mutation commits, the runtime publishes a change event on this
|
|
18
|
+
* channel. Other tabs subscribed to the same channel reload their queries
|
|
19
|
+
* automatically, keeping all open tabs in sync without a server round-trip.
|
|
20
|
+
*
|
|
21
|
+
* Constructed automatically by `createWebSyncoreRuntime`. Exposed for
|
|
22
|
+
* advanced setups that build the persistence layer independently.
|
|
23
|
+
*/
|
|
10
24
|
declare class BroadcastChannelExternalChangeSignal implements SyncoreExternalChangeSignal {
|
|
11
25
|
private readonly channel;
|
|
12
26
|
private readonly listeners;
|
|
@@ -16,12 +30,32 @@ declare class BroadcastChannelExternalChangeSignal implements SyncoreExternalCha
|
|
|
16
30
|
close(): void;
|
|
17
31
|
private readonly messageListener;
|
|
18
32
|
}
|
|
33
|
+
/** Options for constructing a {@link SqlJsExternalChangeApplier}. */
|
|
19
34
|
interface SqlJsExternalChangeApplierOptions {
|
|
35
|
+
/** Logical name of the Syncore database, used to load the latest snapshot from persistence. */
|
|
20
36
|
databaseName: string;
|
|
37
|
+
/** The web persistence layer to read the updated database bytes from. */
|
|
21
38
|
persistence: SyncoreWebPersistence;
|
|
39
|
+
/**
|
|
40
|
+
* Factory that creates a new sql.js `Database` instance from optional
|
|
41
|
+
* initial bytes. Called whenever the database needs to be swapped after an
|
|
42
|
+
* external change.
|
|
43
|
+
*/
|
|
22
44
|
createDatabase: (bytes?: Uint8Array) => SqlJsDatabase;
|
|
45
|
+
/** Callback invoked with the newly created database so the runtime can swap its reference. */
|
|
23
46
|
replaceDatabase(database: SqlJsDatabase): void;
|
|
24
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* A {@link SyncoreExternalChangeApplier} for sql.js (in-memory) databases.
|
|
50
|
+
*
|
|
51
|
+
* When another tab commits a mutation and broadcasts the change event, this
|
|
52
|
+
* applier loads the latest database snapshot from web persistence (OPFS or
|
|
53
|
+
* IndexedDB) and swaps the in-memory `sql.js` database instance so the current
|
|
54
|
+
* tab reflects the new state.
|
|
55
|
+
*
|
|
56
|
+
* Constructed automatically by `createWebSyncoreRuntime` when using sql.js
|
|
57
|
+
* persistence. Exposed for advanced setups.
|
|
58
|
+
*/
|
|
25
59
|
declare class SqlJsExternalChangeApplier implements SyncoreExternalChangeApplier {
|
|
26
60
|
private readonly databaseName;
|
|
27
61
|
private readonly persistence;
|
|
@@ -31,8 +65,16 @@ declare class SqlJsExternalChangeApplier implements SyncoreExternalChangeApplier
|
|
|
31
65
|
applyExternalChange(event: SyncoreExternalChangeEvent): Promise<{
|
|
32
66
|
databaseChanged: boolean;
|
|
33
67
|
storageChanged: boolean;
|
|
68
|
+
changedScopes: ImpactScope[];
|
|
34
69
|
}>;
|
|
35
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Derive the canonical `BroadcastChannel` name for cross-tab sync from a
|
|
73
|
+
* logical database name.
|
|
74
|
+
*
|
|
75
|
+
* All Syncore runtimes sharing the same `databaseName` will use the same
|
|
76
|
+
* channel, ensuring mutations in one tab are visible to all others.
|
|
77
|
+
*/
|
|
36
78
|
declare function createDefaultSyncChannelName(databaseName: string): string;
|
|
37
79
|
//#endregion
|
|
38
80
|
export { BroadcastChannelExternalChangeSignal, BroadcastChannelExternalChangeSignalOptions, SqlJsExternalChangeApplier, SqlJsExternalChangeApplierOptions, createDefaultSyncChannelName };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-change.d.ts","names":[],"sources":["../src/external-change.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"external-change.d.ts","names":[],"sources":["../src/external-change.ts"],"mappings":";;;;;KASK,aAAA,GAAgB,SAAA,CAAU,QAAQ;;UAGtB,2CAAA;EAHC;EAKhB,WAAW;AAAA;AAL0B;AAGvC;;;;AAEa;AAeb;;;;;;AApBuC,cAoB1B,oCAAA,YAAgD,2BAAA;EAAA,iBAC1C,OAAA;EAAA,iBACA,SAAA;cAIL,OAAA,EAAS,2CAAA;EAOrB,SAAA,CAAU,QAAA,GAAW,KAAA,EAAO,0BAAA;EAO5B,OAAA,CAAQ,KAAA,EAAO,0BAAA;EAIf,KAAA,CAAA;EAAA,iBAKiB,eAAA;AAAA;;UAWF,iCAAA;EA3BM;EA6BrB,YAAA;EAtBA;EAwBA,WAAA,EAAa,qBAAA;EAxBL;;;;AASwB;EAqBhC,cAAA,GAAiB,KAAA,GAAQ,UAAA,KAAe,aAAA;EAVQ;EAYhD,eAAA,CAAgB,QAAA,EAAU,aAAA;AAAA;;;;;;;;;;;;cAcf,0BAAA,YAAsC,4BAAA;EAAA,iBAChC,YAAA;EAAA,iBACA,WAAA;EAAA,iBACA,cAAA;EAAA,iBACA,eAAA;cAEL,OAAA,EAAS,iCAAA;EAOf,mBAAA,CAAoB,KAAA,EAAO,0BAAA,GAA0B,OAAA;;;;;;;;;;;;;iBA4B7C,4BAAA,CAA6B,YAAoB"}
|
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
//#region src/external-change.ts
|
|
2
|
+
/**
|
|
3
|
+
* A `BroadcastChannel`-based {@link SyncoreExternalChangeSignal} that
|
|
4
|
+
* propagates database-mutation events across all browser tabs sharing the same
|
|
5
|
+
* Syncore database.
|
|
6
|
+
*
|
|
7
|
+
* When a Syncore mutation commits, the runtime publishes a change event on this
|
|
8
|
+
* channel. Other tabs subscribed to the same channel reload their queries
|
|
9
|
+
* automatically, keeping all open tabs in sync without a server round-trip.
|
|
10
|
+
*
|
|
11
|
+
* Constructed automatically by `createWebSyncoreRuntime`. Exposed for
|
|
12
|
+
* advanced setups that build the persistence layer independently.
|
|
13
|
+
*/
|
|
2
14
|
var BroadcastChannelExternalChangeSignal = class {
|
|
3
15
|
channel;
|
|
4
16
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -26,6 +38,17 @@ var BroadcastChannelExternalChangeSignal = class {
|
|
|
26
38
|
for (const listener of this.listeners) listener(event.data);
|
|
27
39
|
};
|
|
28
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* A {@link SyncoreExternalChangeApplier} for sql.js (in-memory) databases.
|
|
43
|
+
*
|
|
44
|
+
* When another tab commits a mutation and broadcasts the change event, this
|
|
45
|
+
* applier loads the latest database snapshot from web persistence (OPFS or
|
|
46
|
+
* IndexedDB) and swaps the in-memory `sql.js` database instance so the current
|
|
47
|
+
* tab reflects the new state.
|
|
48
|
+
*
|
|
49
|
+
* Constructed automatically by `createWebSyncoreRuntime` when using sql.js
|
|
50
|
+
* persistence. Exposed for advanced setups.
|
|
51
|
+
*/
|
|
29
52
|
var SqlJsExternalChangeApplier = class {
|
|
30
53
|
databaseName;
|
|
31
54
|
persistence;
|
|
@@ -45,10 +68,18 @@ var SqlJsExternalChangeApplier = class {
|
|
|
45
68
|
}
|
|
46
69
|
return {
|
|
47
70
|
databaseChanged,
|
|
48
|
-
storageChanged: event.scope === "storage" || event.scope === "all"
|
|
71
|
+
storageChanged: event.scope === "storage" || event.scope === "all",
|
|
72
|
+
changedScopes: event.changedScopes ?? [...(event.changedTables ?? []).map((tableName) => `table:${tableName}`), ...(event.storageIds ?? []).map((storageId) => `storage:${storageId}`)]
|
|
49
73
|
};
|
|
50
74
|
}
|
|
51
75
|
};
|
|
76
|
+
/**
|
|
77
|
+
* Derive the canonical `BroadcastChannel` name for cross-tab sync from a
|
|
78
|
+
* logical database name.
|
|
79
|
+
*
|
|
80
|
+
* All Syncore runtimes sharing the same `databaseName` will use the same
|
|
81
|
+
* channel, ensuring mutations in one tab are visible to all others.
|
|
82
|
+
*/
|
|
52
83
|
function createDefaultSyncChannelName(databaseName) {
|
|
53
84
|
return `syncore:external:${databaseName}`;
|
|
54
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-change.js","names":[],"sources":["../src/external-change.ts"],"sourcesContent":["import type {\n SyncoreExternalChangeApplier,\n SyncoreExternalChangeEvent,\n SyncoreExternalChangeSignal\n} from \"@syncore/core\";\nimport type initSqlJs from \"sql.js\";\nimport type { SyncoreWebPersistence } from \"./persistence.js\";\n\ntype SqlJsDatabase = initSqlJs.Database;\n\nexport interface BroadcastChannelExternalChangeSignalOptions {\n channelName: string;\n}\n\nexport class BroadcastChannelExternalChangeSignal implements SyncoreExternalChangeSignal {\n private readonly channel: BroadcastChannel | undefined;\n private readonly listeners = new Set<\n (event: SyncoreExternalChangeEvent) => void\n >();\n\n constructor(options: BroadcastChannelExternalChangeSignalOptions) {\n if (typeof BroadcastChannel !== \"undefined\") {\n this.channel = new BroadcastChannel(options.channelName);\n this.channel.addEventListener(\"message\", this.messageListener);\n }\n }\n\n subscribe(listener: (event: SyncoreExternalChangeEvent) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n publish(event: SyncoreExternalChangeEvent): void {\n this.channel?.postMessage(event);\n }\n\n close(): void {\n this.channel?.removeEventListener(\"message\", this.messageListener);\n this.channel?.close();\n }\n\n private readonly messageListener = (event: MessageEvent<unknown>) => {\n if (!isExternalChangeEvent(event.data)) {\n return;\n }\n for (const listener of this.listeners) {\n listener(event.data);\n }\n };\n}\n\nexport interface SqlJsExternalChangeApplierOptions {\n databaseName: string;\n persistence: SyncoreWebPersistence;\n createDatabase: (bytes?: Uint8Array) => SqlJsDatabase;\n replaceDatabase(database: SqlJsDatabase): void;\n}\n\nexport class SqlJsExternalChangeApplier implements SyncoreExternalChangeApplier {\n private readonly databaseName: string;\n private readonly persistence: SyncoreWebPersistence;\n private readonly createDatabase: (bytes?: Uint8Array) => SqlJsDatabase;\n private readonly replaceDatabase: (database: SqlJsDatabase) => void;\n\n constructor(options: SqlJsExternalChangeApplierOptions) {\n this.databaseName = options.databaseName;\n this.persistence = options.persistence;\n this.createDatabase = (bytes) => options.createDatabase(bytes);\n this.replaceDatabase = (database) => options.replaceDatabase(database);\n }\n\n async applyExternalChange(event: SyncoreExternalChangeEvent) {\n const databaseChanged = event.scope === \"database\" || event.scope === \"all\";\n if (databaseChanged) {\n const bytes = await this.persistence.loadDatabase(this.databaseName);\n if (bytes) {\n this.replaceDatabase(this.createDatabase(bytes));\n }\n }\n return {\n databaseChanged,\n storageChanged: event.scope === \"storage\" || event.scope === \"all\"\n };\n }\n}\n\nexport function createDefaultSyncChannelName(databaseName: string): string {\n return `syncore:external:${databaseName}`;\n}\n\nfunction isExternalChangeEvent(\n value: unknown\n): value is SyncoreExternalChangeEvent {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"sourceId\" in value &&\n \"scope\" in value &&\n \"reason\" in value &&\n \"timestamp\" in value\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"external-change.js","names":[],"sources":["../src/external-change.ts"],"sourcesContent":["import type {\n ImpactScope,\n SyncoreExternalChangeApplier,\n SyncoreExternalChangeEvent,\n SyncoreExternalChangeSignal\n} from \"@syncore/core\";\nimport type initSqlJs from \"sql.js\";\nimport type { SyncoreWebPersistence } from \"./persistence.js\";\n\ntype SqlJsDatabase = initSqlJs.Database;\n\n/** Options for constructing a {@link BroadcastChannelExternalChangeSignal}. */\nexport interface BroadcastChannelExternalChangeSignalOptions {\n /** Name of the `BroadcastChannel`, shared by all tabs with the same database. */\n channelName: string;\n}\n\n/**\n * A `BroadcastChannel`-based {@link SyncoreExternalChangeSignal} that\n * propagates database-mutation events across all browser tabs sharing the same\n * Syncore database.\n *\n * When a Syncore mutation commits, the runtime publishes a change event on this\n * channel. Other tabs subscribed to the same channel reload their queries\n * automatically, keeping all open tabs in sync without a server round-trip.\n *\n * Constructed automatically by `createWebSyncoreRuntime`. Exposed for\n * advanced setups that build the persistence layer independently.\n */\nexport class BroadcastChannelExternalChangeSignal implements SyncoreExternalChangeSignal {\n private readonly channel: BroadcastChannel | undefined;\n private readonly listeners = new Set<\n (event: SyncoreExternalChangeEvent) => void\n >();\n\n constructor(options: BroadcastChannelExternalChangeSignalOptions) {\n if (typeof BroadcastChannel !== \"undefined\") {\n this.channel = new BroadcastChannel(options.channelName);\n this.channel.addEventListener(\"message\", this.messageListener);\n }\n }\n\n subscribe(listener: (event: SyncoreExternalChangeEvent) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n publish(event: SyncoreExternalChangeEvent): void {\n this.channel?.postMessage(event);\n }\n\n close(): void {\n this.channel?.removeEventListener(\"message\", this.messageListener);\n this.channel?.close();\n }\n\n private readonly messageListener = (event: MessageEvent<unknown>) => {\n if (!isExternalChangeEvent(event.data)) {\n return;\n }\n for (const listener of this.listeners) {\n listener(event.data);\n }\n };\n}\n\n/** Options for constructing a {@link SqlJsExternalChangeApplier}. */\nexport interface SqlJsExternalChangeApplierOptions {\n /** Logical name of the Syncore database, used to load the latest snapshot from persistence. */\n databaseName: string;\n /** The web persistence layer to read the updated database bytes from. */\n persistence: SyncoreWebPersistence;\n /**\n * Factory that creates a new sql.js `Database` instance from optional\n * initial bytes. Called whenever the database needs to be swapped after an\n * external change.\n */\n createDatabase: (bytes?: Uint8Array) => SqlJsDatabase;\n /** Callback invoked with the newly created database so the runtime can swap its reference. */\n replaceDatabase(database: SqlJsDatabase): void;\n}\n\n/**\n * A {@link SyncoreExternalChangeApplier} for sql.js (in-memory) databases.\n *\n * When another tab commits a mutation and broadcasts the change event, this\n * applier loads the latest database snapshot from web persistence (OPFS or\n * IndexedDB) and swaps the in-memory `sql.js` database instance so the current\n * tab reflects the new state.\n *\n * Constructed automatically by `createWebSyncoreRuntime` when using sql.js\n * persistence. Exposed for advanced setups.\n */\nexport class SqlJsExternalChangeApplier implements SyncoreExternalChangeApplier {\n private readonly databaseName: string;\n private readonly persistence: SyncoreWebPersistence;\n private readonly createDatabase: (bytes?: Uint8Array) => SqlJsDatabase;\n private readonly replaceDatabase: (database: SqlJsDatabase) => void;\n\n constructor(options: SqlJsExternalChangeApplierOptions) {\n this.databaseName = options.databaseName;\n this.persistence = options.persistence;\n this.createDatabase = (bytes) => options.createDatabase(bytes);\n this.replaceDatabase = (database) => options.replaceDatabase(database);\n }\n\n async applyExternalChange(event: SyncoreExternalChangeEvent) {\n const databaseChanged = event.scope === \"database\" || event.scope === \"all\";\n if (databaseChanged) {\n const bytes = await this.persistence.loadDatabase(this.databaseName);\n if (bytes) {\n this.replaceDatabase(this.createDatabase(bytes));\n }\n }\n return {\n databaseChanged,\n storageChanged: event.scope === \"storage\" || event.scope === \"all\",\n changedScopes:\n event.changedScopes ??\n ([\n ...(event.changedTables ?? []).map((tableName) => `table:${tableName}`),\n ...(event.storageIds ?? []).map((storageId) => `storage:${storageId}`)\n ] as ImpactScope[])\n };\n }\n}\n\n/**\n * Derive the canonical `BroadcastChannel` name for cross-tab sync from a\n * logical database name.\n *\n * All Syncore runtimes sharing the same `databaseName` will use the same\n * channel, ensuring mutations in one tab are visible to all others.\n */\nexport function createDefaultSyncChannelName(databaseName: string): string {\n return `syncore:external:${databaseName}`;\n}\n\nfunction isExternalChangeEvent(\n value: unknown\n): value is SyncoreExternalChangeEvent {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"sourceId\" in value &&\n \"scope\" in value &&\n \"reason\" in value &&\n \"timestamp\" in value\n );\n}\n"],"mappings":";;;;;;;;;;;;;AA6BA,IAAa,uCAAb,MAAyF;CACvF;CACA,4BAA6B,IAAI,IAE/B;CAEF,YAAY,SAAsD;EAChE,IAAI,OAAO,qBAAqB,aAAa;GAC3C,KAAK,UAAU,IAAI,iBAAiB,QAAQ,WAAW;GACvD,KAAK,QAAQ,iBAAiB,WAAW,KAAK,eAAe;EAC/D;CACF;CAEA,UAAU,UAAmE;EAC3E,KAAK,UAAU,IAAI,QAAQ;EAC3B,aAAa;GACX,KAAK,UAAU,OAAO,QAAQ;EAChC;CACF;CAEA,QAAQ,OAAyC;EAC/C,KAAK,SAAS,YAAY,KAAK;CACjC;CAEA,QAAc;EACZ,KAAK,SAAS,oBAAoB,WAAW,KAAK,eAAe;EACjE,KAAK,SAAS,MAAM;CACtB;CAEA,mBAAoC,UAAiC;EACnE,IAAI,CAAC,sBAAsB,MAAM,IAAI,GACnC;EAEF,KAAK,MAAM,YAAY,KAAK,WAC1B,SAAS,MAAM,IAAI;CAEvB;AACF;;;;;;;;;;;;AA6BA,IAAa,6BAAb,MAAgF;CAC9E;CACA;CACA;CACA;CAEA,YAAY,SAA4C;EACtD,KAAK,eAAe,QAAQ;EAC5B,KAAK,cAAc,QAAQ;EAC3B,KAAK,kBAAkB,UAAU,QAAQ,eAAe,KAAK;EAC7D,KAAK,mBAAmB,aAAa,QAAQ,gBAAgB,QAAQ;CACvE;CAEA,MAAM,oBAAoB,OAAmC;EAC3D,MAAM,kBAAkB,MAAM,UAAU,cAAc,MAAM,UAAU;EACtE,IAAI,iBAAiB;GACnB,MAAM,QAAQ,MAAM,KAAK,YAAY,aAAa,KAAK,YAAY;GACnE,IAAI,OACF,KAAK,gBAAgB,KAAK,eAAe,KAAK,CAAC;EAEnD;EACA,OAAO;GACL;GACA,gBAAgB,MAAM,UAAU,aAAa,MAAM,UAAU;GAC7D,eACE,MAAM,iBACL,CACC,IAAI,MAAM,iBAAiB,CAAC,GAAG,KAAK,cAAc,SAAS,WAAW,GACtE,IAAI,MAAM,cAAc,CAAC,GAAG,KAAK,cAAc,WAAW,WAAW,CACvE;EACJ;CACF;AACF;;;;;;;;AASA,SAAgB,6BAA6B,cAA8B;CACzE,OAAO,oBAAoB;AAC7B;AAEA,SAAS,sBACP,OACqC;CACrC,OACE,OAAO,UAAU,YACjB,UAAU,QACV,cAAc,SACd,WAAW,SACX,YAAY,SACZ,eAAe;AAEnB"}
|