syncorejs 0.2.2 → 0.2.4

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.
Files changed (142) hide show
  1. package/dist/_vendor/cli/app.d.mts.map +1 -1
  2. package/dist/_vendor/cli/app.mjs +8 -5
  3. package/dist/_vendor/cli/app.mjs.map +1 -1
  4. package/dist/_vendor/cli/context.mjs.map +1 -1
  5. package/dist/_vendor/cli/dev-session.mjs.map +1 -1
  6. package/dist/_vendor/cli/doctor.mjs.map +1 -1
  7. package/dist/_vendor/cli/errors.mjs.map +1 -1
  8. package/dist/_vendor/cli/help.mjs.map +1 -1
  9. package/dist/_vendor/cli/index.mjs +9 -2
  10. package/dist/_vendor/cli/index.mjs.map +1 -1
  11. package/dist/_vendor/cli/messages.mjs.map +1 -1
  12. package/dist/_vendor/cli/preflight.mjs.map +1 -1
  13. package/dist/_vendor/cli/project.mjs +20 -20
  14. package/dist/_vendor/cli/project.mjs.map +1 -1
  15. package/dist/_vendor/cli/render.mjs.map +1 -1
  16. package/dist/_vendor/cli/targets.mjs.map +1 -1
  17. package/dist/_vendor/core/cli.d.mts +8 -2
  18. package/dist/_vendor/core/cli.d.mts.map +1 -1
  19. package/dist/_vendor/core/cli.mjs +510 -71
  20. package/dist/_vendor/core/cli.mjs.map +1 -1
  21. package/dist/_vendor/core/devtools-auth.mjs.map +1 -1
  22. package/dist/_vendor/core/index.d.mts +3 -3
  23. package/dist/_vendor/core/runtime/components.d.mts.map +1 -1
  24. package/dist/_vendor/core/runtime/components.mjs.map +1 -1
  25. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  26. package/dist/_vendor/core/runtime/devtools.mjs +261 -23
  27. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  28. package/dist/_vendor/core/runtime/functions.d.mts +388 -6
  29. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  30. package/dist/_vendor/core/runtime/functions.mjs +72 -1
  31. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  32. package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
  33. package/dist/_vendor/core/runtime/id.mjs.map +1 -1
  34. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +12 -6
  35. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -1
  36. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +123 -20
  37. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -1
  38. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +56 -8
  39. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -1
  40. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +49 -14
  41. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -1
  42. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +4 -7
  43. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -1
  44. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +81 -2
  45. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -1
  46. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +100 -13
  47. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -1
  48. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +42 -7
  49. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -1
  50. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -1
  51. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -1
  52. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +4 -0
  53. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -1
  54. package/dist/_vendor/core/runtime/runtime.d.mts +1100 -12
  55. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  56. package/dist/_vendor/core/runtime/runtime.mjs +63 -0
  57. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  58. package/dist/_vendor/core/transport.d.mts +2 -0
  59. package/dist/_vendor/core/transport.d.mts.map +1 -1
  60. package/dist/_vendor/core/transport.mjs +61 -27
  61. package/dist/_vendor/core/transport.mjs.map +1 -1
  62. package/dist/_vendor/devtools-protocol/index.d.ts +223 -4
  63. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  64. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  65. package/dist/_vendor/next/config.d.ts +3 -4
  66. package/dist/_vendor/next/config.d.ts.map +1 -1
  67. package/dist/_vendor/next/config.js +37 -19
  68. package/dist/_vendor/next/config.js.map +1 -1
  69. package/dist/_vendor/next/index.d.ts +109 -29
  70. package/dist/_vendor/next/index.d.ts.map +1 -1
  71. package/dist/_vendor/next/index.js +86 -18
  72. package/dist/_vendor/next/index.js.map +1 -1
  73. package/dist/_vendor/platform-expo/index.d.ts +146 -27
  74. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  75. package/dist/_vendor/platform-expo/index.js +81 -10
  76. package/dist/_vendor/platform-expo/index.js.map +1 -1
  77. package/dist/_vendor/platform-expo/react.js.map +1 -1
  78. package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
  79. package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
  80. package/dist/_vendor/platform-node/index.d.mts +174 -9
  81. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  82. package/dist/_vendor/platform-node/index.mjs +251 -95
  83. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  84. package/dist/_vendor/platform-node/ipc-react.mjs +4 -0
  85. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  86. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  87. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  88. package/dist/_vendor/platform-web/external-change.d.ts +41 -0
  89. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  90. package/dist/_vendor/platform-web/external-change.js +30 -0
  91. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  92. package/dist/_vendor/platform-web/index.d.ts +312 -37
  93. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  94. package/dist/_vendor/platform-web/index.js +247 -25
  95. package/dist/_vendor/platform-web/index.js.map +1 -1
  96. package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
  97. package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
  98. package/dist/_vendor/platform-web/indexeddb.js +10 -0
  99. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  100. package/dist/_vendor/platform-web/opfs.d.ts +16 -1
  101. package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
  102. package/dist/_vendor/platform-web/opfs.js +41 -3
  103. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  104. package/dist/_vendor/platform-web/persistence.d.ts +85 -1
  105. package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
  106. package/dist/_vendor/platform-web/persistence.js +15 -0
  107. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  108. package/dist/_vendor/platform-web/react.d.ts +1 -2
  109. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  110. package/dist/_vendor/platform-web/react.js +11 -5
  111. package/dist/_vendor/platform-web/react.js.map +1 -1
  112. package/dist/_vendor/platform-web/sqljs.js +10 -1
  113. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  114. package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
  115. package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
  116. package/dist/_vendor/platform-web/worker.d.ts +60 -9
  117. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  118. package/dist/_vendor/platform-web/worker.js +37 -4
  119. package/dist/_vendor/platform-web/worker.js.map +1 -1
  120. package/dist/_vendor/react/index.d.ts +197 -13
  121. package/dist/_vendor/react/index.d.ts.map +1 -1
  122. package/dist/_vendor/react/index.js +209 -17
  123. package/dist/_vendor/react/index.js.map +1 -1
  124. package/dist/_vendor/schema/definition.d.ts +129 -0
  125. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  126. package/dist/_vendor/schema/definition.js +99 -0
  127. package/dist/_vendor/schema/definition.js.map +1 -1
  128. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  129. package/dist/_vendor/schema/planner.js.map +1 -1
  130. package/dist/_vendor/schema/validators.d.ts +180 -4
  131. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  132. package/dist/_vendor/schema/validators.js +35 -1
  133. package/dist/_vendor/schema/validators.js.map +1 -1
  134. package/dist/_vendor/svelte/index.d.ts +207 -7
  135. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  136. package/dist/_vendor/svelte/index.js +201 -6
  137. package/dist/_vendor/svelte/index.js.map +1 -1
  138. package/dist/browser.d.ts.map +1 -1
  139. package/dist/cli.js +3 -1
  140. package/dist/cli.js.map +1 -1
  141. package/dist/index.d.ts +1 -1
  142. package/package.json +24 -21
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n createDevtoolsCommandHandler,\n createDevtoolsSubscriptionHost,\n type DevtoolsCommandHandler,\n type DevtoolsSink,\n type DevtoolsSubscriptionHost,\n type SyncoreDataModel,\n generateId,\n SyncoreRuntime,\n type SchedulerOptions,\n type SyncoreCapabilities,\n type SyncoreRuntimeOptions,\n type SyncoreStorageAdapter,\n type StorageObject,\n type StorageWriteInput\n} from \"@syncore/core\";\nimport {\n SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,\n SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,\n SYNCORE_DEVTOOLS_PROTOCOL_VERSION,\n type SyncoreDevtoolsClientMessage,\n type SyncoreDevtoolsMessage,\n type SyncoreRuntimeSummary\n} from \"@syncore/devtools-protocol\";\nimport {\n createWebPersistence,\n type SyncoreWebPersistence,\n type WebPersistenceMode\n} from \"./persistence.js\";\nimport {\n BroadcastChannelExternalChangeSignal,\n createDefaultSyncChannelName,\n SqlJsExternalChangeApplier\n} from \"./external-change.js\";\nimport { SqlJsDriver } from \"./sqljs.js\";\nimport {\n attachWebWorkerRuntime,\n type SyncoreWorkerMessageEndpoint\n} from \"./worker.js\";\nexport * from \"./worker.js\";\nexport * from \"./persistence.js\";\nexport * from \"./indexeddb.js\";\nexport * from \"./opfs.js\";\nexport * from \"./external-change.js\";\n\nexport type WebSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = TSchema;\nexport type BrowserSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = WebSyncoreSchema<TSchema>;\n\nconst DEVTOOLS_META_NAMESPACE = \"__syncore_devtools_meta__\";\nconst STORAGE_SCOPE_ID_PREFIX = \"storage-scope\";\n\n/**\n * Options for constructing a browser Syncore runtime.\n *\n * Use this when you want to host the full runtime in a browser tab or worker.\n */\nexport interface CreateWebRuntimeOptions<\n TSchema extends WebSyncoreSchema = WebSyncoreSchema\n> {\n /** The schema for the local Syncore app. */\n schema: TSchema;\n\n /** The generated function registry for the local Syncore app. */\n functions: SyncoreRuntimeOptions<TSchema>[\"functions\"];\n\n /** Optional resolved installed components for the local Syncore app. */\n components?: SyncoreRuntimeOptions<TSchema>[\"components\"];\n\n /** Optional platform capabilities exposed to function handlers. */\n capabilities?: SyncoreCapabilities;\n\n /** Optional custom SQL driver. Defaults to SQL.js with local persistence. */\n driver?: SyncoreRuntimeOptions<TSchema>[\"driver\"];\n\n /** Optional custom file/blob storage adapter. */\n storage?: SyncoreStorageAdapter;\n\n /** Optional explicit persistence implementation. */\n persistence?: SyncoreWebPersistence;\n\n /** Which browser persistence mode to use when Syncore creates one for you. */\n persistenceMode?: WebPersistenceMode;\n\n /** Logical database name for SQL.js and local storage namespaces. */\n databaseName?: string;\n\n /** Optional IndexedDB database name for persistence metadata. */\n persistenceDatabaseName?: string;\n\n /** Optional OPFS directory name for persistent files. */\n opfsRootDirectoryName?: string;\n\n /** Optional namespace for file/blob storage. */\n storageNamespace?: string;\n\n /** Optional direct wasm URL for SQL.js. */\n wasmUrl?: string;\n\n /** Optional callback for resolving SQL.js support files. */\n locateFile?: (fileName: string) => string;\n\n /** Optional runtime platform label shown in devtools snapshots. */\n platform?: string;\n\n /** Optional devtools sink used during development. */\n devtools?: DevtoolsSink | false;\n\n /** Optional scheduler configuration for jobs and recurring work. */\n scheduler?: SchedulerOptions;\n}\n\n/**\n * Options for hosting a Syncore runtime inside a browser Worker.\n */\nexport interface CreateWebWorkerRuntimeOptions<\n TSchema extends WebSyncoreSchema = WebSyncoreSchema\n> extends CreateWebRuntimeOptions<TSchema> {\n /** The message endpoint exposed by the current worker global. */\n endpoint: SyncoreWorkerMessageEndpoint;\n}\n\n/**\n * Options for constructing a browser Syncore runtime.\n */\nexport type CreateBrowserRuntimeOptions<\n TSchema extends BrowserSyncoreSchema = BrowserSyncoreSchema\n> = CreateWebRuntimeOptions<TSchema>;\n\n/**\n * Options for hosting a Syncore runtime inside a browser Worker.\n */\nexport type CreateBrowserWorkerRuntimeOptions<\n TSchema extends BrowserSyncoreSchema = BrowserSyncoreSchema\n> = CreateWebWorkerRuntimeOptions<TSchema>;\n\nexport interface WebExternalChangeSupport {\n signal: BroadcastChannelExternalChangeSignal;\n applier?: SqlJsExternalChangeApplier;\n}\n\n/**\n * Create a full Syncore runtime directly in the browser.\n *\n * Most React apps should use a worker runtime instead so queries and SQLite work\n * stay off the main thread.\n */\nexport async function createWebSyncoreRuntime<\n TSchema extends WebSyncoreSchema\n>(\n options: CreateWebRuntimeOptions<TSchema>\n): Promise<SyncoreRuntime<TSchema>> {\n const persistence =\n options.persistence ??\n (await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName:\n options.opfsRootDirectoryName ?? options.databaseName ?? \"syncore\"\n }));\n const driver =\n options.driver ??\n (await SqlJsDriver.create({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n ...(options.wasmUrl ? { wasmUrl: options.wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n }));\n const storage =\n options.storage ??\n new BrowserFileStorageAdapter(\n persistence,\n options.storageNamespace ?? options.databaseName ?? \"syncore\"\n );\n const externalChangeSupport = createWebExternalChangeSupport({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n driver\n });\n const appName = resolveWebAppName();\n const origin = resolveWebOrigin();\n const sessionLabel = resolveWebSessionLabel();\n const databaseLabel = options.databaseName ?? \"syncore\";\n const storageScopeId = await resolvePersistedStorageScopeId(\n persistence,\n databaseLabel\n );\n const storageIdentity = [\n origin ?? \"unknown-origin\",\n persistence.storageProtocol,\n databaseLabel,\n storageScopeId\n ].join(\"::\");\n const autoDevtools =\n options.devtools === undefined && shouldAutoConnectDevtools()\n ? (() => {\n const sinkOptions: BrowserWebSocketDevtoolsSinkOptions = {\n url: resolveDefaultDevtoolsUrl(),\n targetKind: \"client\",\n storageProtocol: persistence.storageProtocol,\n databaseLabel,\n storageIdentity\n };\n if (appName) {\n sinkOptions.appName = appName;\n }\n if (origin) {\n sinkOptions.origin = origin;\n }\n if (sessionLabel) {\n sinkOptions.sessionLabel = sessionLabel;\n }\n return createBrowserWebSocketDevtoolsSink(sinkOptions);\n })()\n : undefined;\n const resolvedDevtools =\n options.devtools === false ? undefined : (options.devtools ?? autoDevtools);\n\n announceBrowserSession({\n enabled: resolvedDevtools !== undefined,\n sessionLabel,\n appName,\n origin,\n devtoolsUrl:\n options.devtools && typeof options.devtools === \"object\"\n ? undefined\n : resolveDefaultDevtoolsUrl()\n });\n\n const runtime = new SyncoreRuntime({\n schema: options.schema,\n functions: options.functions,\n ...(options.components ? { components: options.components } : {}),\n driver,\n storage,\n externalChangeSignal: externalChangeSupport.signal,\n ...(externalChangeSupport.applier\n ? { externalChangeApplier: externalChangeSupport.applier }\n : {}),\n platform: options.platform ?? \"browser\",\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n ...(resolvedDevtools ? { devtools: resolvedDevtools } : {}),\n ...(options.scheduler ? { scheduler: options.scheduler } : {})\n });\n\n if (autoDevtools) {\n autoDevtools.attachRuntime(runtime);\n autoDevtools.attachCommandHandler(\n createDevtoolsCommandHandler({\n driver,\n schema: options.schema,\n functions: options.functions,\n admin: runtime.getAdmin()\n })\n );\n autoDevtools.attachSubscriptionHost(\n createDevtoolsSubscriptionHost({\n driver,\n schema: options.schema,\n functions: options.functions,\n admin: runtime.getAdmin()\n })\n );\n }\n\n return runtime;\n}\n\nexport function createWebExternalChangeSupport(options: {\n databaseName: string;\n persistence: SyncoreWebPersistence;\n driver: CreateWebRuntimeOptions<SyncoreDataModel>[\"driver\"] | undefined;\n}): WebExternalChangeSupport {\n const signal = new BroadcastChannelExternalChangeSignal({\n channelName: createDefaultSyncChannelName(options.databaseName)\n });\n const sqlDriver =\n options.driver instanceof SqlJsDriver ? options.driver : undefined;\n\n if (!sqlDriver) {\n return { signal };\n }\n\n return {\n signal,\n applier: new SqlJsExternalChangeApplier({\n databaseName: options.databaseName,\n persistence: options.persistence,\n createDatabase: (bytes) => sqlDriver.createDatabaseFromBytes(bytes),\n replaceDatabase: (database) => {\n sqlDriver.replaceDatabase(database);\n }\n })\n };\n}\n\nexport async function createExpoWebExternalChangeSupport(options: {\n databaseName: string;\n locateFile?: (fileName: string) => string;\n wasmUrl?: string;\n persistenceDatabaseName?: string;\n opfsRootDirectoryName?: string;\n persistenceMode?: WebPersistenceMode;\n}): Promise<WebExternalChangeSupport> {\n const persistence = await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName: options.opfsRootDirectoryName ?? options.databaseName\n });\n const driver = await SqlJsDriver.create({\n databaseName: options.databaseName,\n persistence,\n ...(options.wasmUrl ? { wasmUrl: options.wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n });\n\n return createWebExternalChangeSupport({\n databaseName: options.databaseName,\n persistence,\n driver\n });\n}\n\n/**\n * Attach a Syncore runtime to a browser Worker endpoint.\n */\nexport function createWebWorkerRuntime<\n TSchema extends WebSyncoreSchema\n>(options: CreateWebWorkerRuntimeOptions<TSchema>) {\n return attachWebWorkerRuntime({\n endpoint: options.endpoint,\n createRuntime: () => createWebSyncoreRuntime(options)\n });\n}\n\n/**\n * Attach a Syncore runtime to a browser Worker endpoint.\n */\nexport function createBrowserWorkerRuntime(\n options: CreateBrowserWorkerRuntimeOptions\n) {\n return createWebWorkerRuntime(options);\n}\n\n/**\n * Create a client directly from a browser Syncore runtime.\n */\nexport function createWebSyncoreClient<\n TSchema extends WebSyncoreSchema\n>(runtime: SyncoreRuntime<TSchema>) {\n return runtime.createClient();\n}\n\n/**\n * Create a full Syncore runtime directly in the browser.\n */\nexport function createBrowserSyncoreRuntime<\n TSchema extends BrowserSyncoreSchema\n>(options: CreateBrowserRuntimeOptions<TSchema>) {\n return createWebSyncoreRuntime(options);\n}\n\n/**\n * Create a client directly from a browser Syncore runtime.\n */\nexport function createBrowserSyncoreClient<\n TSchema extends BrowserSyncoreSchema\n>(runtime: SyncoreRuntime<TSchema>) {\n return createWebSyncoreClient(runtime);\n}\n\nexport interface BrowserWebSocketDevtoolsSinkOptions {\n url: string;\n reconnectDelayMs?: number;\n appName?: string;\n origin?: string;\n sessionLabel?: string;\n targetKind?: \"client\";\n storageProtocol?: string;\n databaseLabel?: string;\n storageIdentity?: string;\n}\n\nexport interface BrowserWebSocketDevtoolsSink extends DevtoolsSink {\n attachRuntime(runtime: SyncoreRuntime<WebSyncoreSchema>): void;\n attachCommandHandler(handler: DevtoolsCommandHandler): void;\n attachSubscriptionHost(host: DevtoolsSubscriptionHost): void;\n dispose(): void;\n}\n\nexport function createBrowserWebSocketDevtoolsSink(\n options: BrowserWebSocketDevtoolsSinkOptions\n): BrowserWebSocketDevtoolsSink {\n let socket: WebSocket | undefined;\n let disposed = false;\n let connectTimer: ReturnType<typeof setTimeout> | undefined;\n let getSummary: (() => SyncoreRuntimeSummary) | undefined;\n let onCommand: DevtoolsCommandHandler | undefined;\n let subscriptionHost: DevtoolsSubscriptionHost | undefined;\n const pendingMessages: SyncoreDevtoolsMessage[] = [];\n let latestHello:\n | {\n runtimeId: string;\n platform: string;\n }\n | undefined;\n\n const connect = () => {\n if (disposed || typeof WebSocket === \"undefined\") {\n return;\n }\n socket = new WebSocket(options.url);\n socket.onopen = () => {\n if (latestHello) {\n sendNow({\n type: \"hello\",\n protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,\n minSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,\n maxSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,\n runtimeId: latestHello.runtimeId,\n platform: latestHello.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {})\n });\n }\n flushPendingMessages();\n };\n socket.onmessage = (event) => {\n if (typeof event.data !== \"string\") {\n return;\n }\n const message = JSON.parse(event.data) as\n | SyncoreDevtoolsMessage\n | SyncoreDevtoolsClientMessage;\n if (message.type === \"ping\") {\n send({ type: \"pong\" });\n } else if (message.type === \"command\" && onCommand) {\n onCommand(message.payload)\n .then((responsePayload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"command.result\",\n commandId: message.commandId,\n runtimeId,\n payload: responsePayload\n });\n })\n .catch((err) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"command.result\",\n commandId: message.commandId,\n runtimeId,\n payload: {\n kind: \"error\",\n message: err instanceof Error ? err.message : \"Unknown error\"\n }\n });\n });\n } else if (message.type === \"subscribe\" && subscriptionHost) {\n void subscriptionHost.subscribe(\n message.subscriptionId,\n message.payload,\n (payload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"subscription.data\",\n subscriptionId: message.subscriptionId,\n runtimeId,\n payload\n });\n }\n );\n } else if (message.type === \"unsubscribe\") {\n subscriptionHost?.unsubscribe(message.subscriptionId);\n }\n };\n socket.onclose = scheduleReconnect;\n socket.onerror = () => {\n socket?.close();\n };\n };\n\n const scheduleReconnect = () => {\n if (disposed || connectTimer) {\n return;\n }\n connectTimer = setTimeout(() => {\n connectTimer = undefined;\n connect();\n }, options.reconnectDelayMs ?? 1200);\n };\n\n const sendNow = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify(message));\n }\n };\n\n const flushPendingMessages = () => {\n while (pendingMessages.length > 0) {\n const nextMessage = pendingMessages.shift();\n if (nextMessage) {\n sendNow(nextMessage);\n }\n }\n };\n\n const send = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n sendNow(message);\n return;\n }\n pendingMessages.push(message);\n };\n\n connect();\n\n return {\n emit(event) {\n if (event.type === \"runtime.connected\") {\n latestHello = {\n runtimeId: event.runtimeId,\n platform: event.platform\n };\n send({\n type: \"hello\",\n protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,\n minSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,\n maxSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,\n runtimeId: event.runtimeId,\n platform: event.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {})\n });\n }\n send({ type: \"event\", event });\n },\n attachRuntime(runtime) {\n getSummary = () =>\n withRuntimeSummaryMeta(runtime.getAdmin().getRuntimeSummary(), options);\n },\n attachCommandHandler(handler) {\n onCommand = handler;\n },\n attachSubscriptionHost(host) {\n subscriptionHost = host;\n },\n dispose() {\n disposed = true;\n if (connectTimer) {\n clearTimeout(connectTimer);\n }\n subscriptionHost?.dispose();\n socket?.close();\n }\n };\n}\n\nfunction withRuntimeSummaryMeta(\n summary: SyncoreRuntimeSummary,\n options: BrowserWebSocketDevtoolsSinkOptions\n): SyncoreRuntimeSummary {\n return {\n ...summary,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {})\n };\n}\n\nfunction shouldAutoConnectDevtools(): boolean {\n const hostname = resolveWebHostname();\n if (!hostname) {\n return false;\n }\n return (\n hostname === \"localhost\" ||\n isPrivateNetworkHostname(hostname) ||\n hostname.endsWith(\".local\")\n );\n}\n\nfunction resolveDefaultDevtoolsUrl(): string {\n return \"ws://127.0.0.1:4311\";\n}\n\nfunction resolveLocationString(\n key: \"href\" | \"origin\" | \"hostname\"\n): string | undefined {\n try {\n const value = globalThis.location?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveGlobalOrigin(): string | undefined {\n try {\n const value = (globalThis as { origin?: unknown }).origin;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction parseUrlCandidate(candidate: string | undefined): URL | undefined {\n if (!candidate || candidate === \"null\") {\n return undefined;\n }\n try {\n const parsed = new URL(candidate);\n if (parsed.protocol === \"blob:\" && parsed.pathname.length > 0) {\n try {\n return new URL(parsed.pathname);\n } catch {\n return parsed;\n }\n }\n return parsed;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebHostname(): string | undefined {\n const directHostname = resolveLocationString(\"hostname\");\n if (directHostname) {\n return directHostname;\n }\n return (\n parseUrlCandidate(resolveLocationString(\"href\"))?.hostname ||\n parseUrlCandidate(resolveLocationString(\"origin\"))?.hostname ||\n parseUrlCandidate(resolveGlobalOrigin())?.hostname ||\n undefined\n );\n}\n\nfunction isPrivateNetworkHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (normalized === \"::1\") {\n return true;\n }\n if (normalized.startsWith(\"fc\") || normalized.startsWith(\"fd\")) {\n return true;\n }\n const match = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(normalized);\n if (!match) {\n return false;\n }\n const octets = match.slice(1).map((part) => Number(part));\n if (octets.some((part) => Number.isNaN(part) || part < 0 || part > 255)) {\n return false;\n }\n const first = octets[0];\n const second = octets[1];\n if (first === undefined || second === undefined) {\n return false;\n }\n return (\n first === 10 ||\n first === 127 ||\n (first === 169 && second === 254) ||\n (first === 172 && second >= 16 && second <= 31) ||\n (first === 192 && second === 168)\n );\n}\n\nfunction resolveWebOrigin(): string | undefined {\n const directOrigin = resolveLocationString(\"origin\");\n if (directOrigin && directOrigin !== \"null\") {\n return directOrigin;\n }\n const parsedOrigin =\n parseUrlCandidate(resolveLocationString(\"href\"))?.origin ||\n parseUrlCandidate(resolveGlobalOrigin())?.origin;\n return parsedOrigin && parsedOrigin !== \"null\" ? parsedOrigin : undefined;\n}\n\nfunction resolveWebAppName(): string | undefined {\n try {\n return resolveWebHostname() ?? globalThis.document?.title ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebSessionLabel(): string | undefined {\n try {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n\n // Generate or retrieve a persistent unique name for this browser instance.\n // This makes it much easier to identify which browser tab/window you're\n // looking at in the devtools dashboard.\n const STORAGE_KEY = \"syncore-session-name\";\n let uniqueName: string | null = null;\n\n try {\n uniqueName = globalThis.localStorage?.getItem(STORAGE_KEY) ?? null;\n } catch {\n /* localStorage may not be available */\n }\n\n if (!uniqueName) {\n uniqueName = generateUniqueSessionName();\n\n try {\n globalThis.localStorage?.setItem(STORAGE_KEY, uniqueName);\n } catch {\n /* ignore storage errors */\n }\n }\n\n const browser = resolveBrowserName(navigator);\n\n return `${uniqueName} (${browser})`;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveBrowserName(\n nav: Navigator & {\n userAgentData?: {\n brands?: Array<{\n brand: string;\n }>;\n };\n }\n): string {\n const brands = nav.userAgentData?.brands?.map((entry) => entry.brand) ?? [];\n\n if (brands.some((brand) => /microsoft edge/i.test(brand))) {\n return \"Edge\";\n }\n if (brands.some((brand) => /firefox/i.test(brand))) {\n return \"Firefox\";\n }\n if (brands.some((brand) => /opera/i.test(brand))) {\n return \"Opera\";\n }\n if (brands.some((brand) => /chrome|chromium/i.test(brand))) {\n return \"Chrome\";\n }\n if (brands.some((brand) => /safari/i.test(brand))) {\n return \"Safari\";\n }\n\n const userAgent = nav.userAgent;\n if (/Firefox\\//i.test(userAgent)) {\n return \"Firefox\";\n }\n if (/Edg\\//i.test(userAgent)) {\n return \"Edge\";\n }\n if (/OPR\\/|Opera/i.test(userAgent)) {\n return \"Opera\";\n }\n if (/Chrome\\/|CriOS\\//i.test(userAgent)) {\n return \"Chrome\";\n }\n if (/Safari\\//i.test(userAgent)) {\n return \"Safari\";\n }\n return \"Browser\";\n}\n\nasync function resolvePersistedStorageScopeId(\n persistence: SyncoreWebPersistence,\n databaseLabel: string\n): Promise<string> {\n const id = `${STORAGE_SCOPE_ID_PREFIX}:${databaseLabel}`;\n const existing = await persistence.getFile(DEVTOOLS_META_NAMESPACE, id);\n\n if (existing) {\n const value = new TextDecoder().decode(existing.bytes).trim();\n if (value.length > 0) {\n return value;\n }\n }\n\n const nextValue = generateId();\n await persistence.putFile(\n DEVTOOLS_META_NAMESPACE,\n id,\n new TextEncoder().encode(nextValue),\n \"text/plain\"\n );\n return nextValue;\n}\n\nfunction announceBrowserSession(options: {\n enabled: boolean;\n sessionLabel?: string | undefined;\n appName?: string | undefined;\n origin?: string | undefined;\n devtoolsUrl?: string | undefined;\n}): void {\n if (!options.enabled || !options.sessionLabel) {\n return;\n }\n\n const announcedSessions = getAnnouncedBrowserSessions();\n if (announcedSessions.has(options.sessionLabel)) {\n return;\n }\n announcedSessions.add(options.sessionLabel);\n\n try {\n const details = [\n options.appName ? `app=${options.appName}` : undefined,\n options.origin ? `origin=${options.origin}` : undefined,\n options.devtoolsUrl ? `devtools=${options.devtoolsUrl}` : undefined\n ].filter((value): value is string => value !== undefined);\n\n console.info(\n `[syncore] Browser session: ${options.sessionLabel}${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}`\n );\n } catch {\n /* ignore console failures */\n }\n}\n\nfunction getAnnouncedBrowserSessions(): Set<string> {\n const key = \"__syncoreAnnouncedBrowserSessions\";\n const scope = globalThis as typeof globalThis & {\n [key]?: Set<string>;\n };\n if (!scope[key]) {\n scope[key] = new Set<string>();\n }\n return scope[key];\n}\n\n/* ------------------------------------------------------------------ */\n/* Unique session name generator */\n/* ------------------------------------------------------------------ */\n\nconst SESSION_ADJECTIVES = [\n \"Acrobatic\",\n \"Bold\",\n \"Cosmic\",\n \"Daring\",\n \"Electric\",\n \"Fierce\",\n \"Golden\",\n \"Hidden\",\n \"Iron\",\n \"Jade\",\n \"Keen\",\n \"Lunar\",\n \"Mystic\",\n \"Noble\",\n \"Orbital\",\n \"Primal\",\n \"Quick\",\n \"Radiant\",\n \"Shadow\",\n \"Turbo\",\n \"Ultra\",\n \"Vivid\",\n \"Wicked\",\n \"Xenon\",\n \"Zen\",\n \"Arctic\",\n \"Binary\",\n \"Cyber\",\n \"Digital\",\n \"Ember\",\n \"Frozen\",\n \"Galactic\",\n \"Hyper\",\n \"Infra\",\n \"Jumbo\",\n \"Kinetic\",\n \"Liquid\",\n \"Magnetic\",\n \"Neon\",\n \"Onyx\",\n \"Phantom\",\n \"Quantum\",\n \"Rapid\",\n \"Sonic\",\n \"Titan\",\n \"Velvet\",\n \"Wild\",\n \"Blazing\",\n \"Crystal\",\n \"Dynamic\"\n] as const;\n\nconst SESSION_NOUNS = [\n \"Monkey\",\n \"Phoenix\",\n \"Tiger\",\n \"Dragon\",\n \"Falcon\",\n \"Panther\",\n \"Wolf\",\n \"Eagle\",\n \"Cobra\",\n \"Shark\",\n \"Raven\",\n \"Fox\",\n \"Lynx\",\n \"Hawk\",\n \"Bear\",\n \"Jaguar\",\n \"Viper\",\n \"Owl\",\n \"Stallion\",\n \"Dolphin\",\n \"Developer\",\n \"Hacker\",\n \"Wizard\",\n \"Ninja\",\n \"Pilot\",\n \"Pioneer\",\n \"Voyager\",\n \"Explorer\",\n \"Runner\",\n \"Ranger\",\n \"Maverick\",\n \"Spartan\",\n \"Viking\",\n \"Sentinel\",\n \"Guardian\",\n \"Nomad\",\n \"Cipher\",\n \"Vector\",\n \"Matrix\",\n \"Prism\",\n \"Nebula\",\n \"Comet\",\n \"Pulse\",\n \"Vertex\",\n \"Flux\",\n \"Storm\",\n \"Blaze\",\n \"Frost\",\n \"Thunder\",\n \"Drift\"\n] as const;\n\nfunction generateUniqueSessionName(): string {\n const adj =\n SESSION_ADJECTIVES[Math.floor(Math.random() * SESSION_ADJECTIVES.length)]!;\n const noun = SESSION_NOUNS[Math.floor(Math.random() * SESSION_NOUNS.length)]!;\n return `${adj} ${noun}`;\n}\n\n/**\n * Browser file/blob storage built on top of Syncore web persistence.\n */\nexport class BrowserFileStorageAdapter implements SyncoreStorageAdapter {\n constructor(\n private readonly persistence: SyncoreWebPersistence,\n private readonly namespace: string\n ) {}\n\n async put(id: string, input: StorageWriteInput): Promise<StorageObject> {\n const bytes = normalizeBinary(input.data);\n await this.persistence.putFile(\n this.namespace,\n id,\n bytes,\n input.contentType ?? null\n );\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: bytes.byteLength,\n contentType: input.contentType ?? null\n };\n }\n\n async get(id: string): Promise<StorageObject | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n if (!file) {\n return null;\n }\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: file.size,\n contentType: file.contentType\n };\n }\n\n async read(id: string): Promise<Uint8Array | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n return file?.bytes ?? null;\n }\n\n async delete(id: string): Promise<void> {\n await this.persistence.deleteFile(this.namespace, id);\n }\n\n async list(): Promise<StorageObject[]> {\n const files = await this.persistence.listFiles(this.namespace);\n return files.map((file) => ({\n id: file.id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${file.id}`,\n size: file.size,\n contentType: file.contentType\n }));\n }\n}\n\nfunction normalizeBinary(data: StorageWriteInput[\"data\"]): Uint8Array {\n if (typeof data === \"string\") {\n return new TextEncoder().encode(data);\n }\n if (data instanceof Uint8Array) {\n return data;\n }\n return new Uint8Array(data);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["scope"],"sources":["../src/index.ts"],"sourcesContent":["import {\n createDevtoolsCommandHandler,\n createDevtoolsSubscriptionHost,\n type DevtoolsCommandHandler,\n type DevtoolsSink,\n type DevtoolsSubscriptionHost,\n type SyncoreDataModel,\n generateId,\n SyncoreRuntime,\n type SchedulerOptions,\n type SyncoreCapabilities,\n type SyncoreRuntimeCapabilities,\n type SyncoreRuntimeOptions,\n type SyncoreStorageAdapter,\n type StorageObject,\n type StorageWriteInput\n} from \"@syncore/core\";\nimport {\n SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,\n SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,\n SYNCORE_DEVTOOLS_PROTOCOL_VERSION,\n type SyncoreDevtoolsClientMessage,\n type SyncoreDevtoolsCapabilities,\n type SyncoreDevtoolsMessage,\n type SyncoreRuntimeSummary\n} from \"@syncore/devtools-protocol\";\nimport {\n createWebPersistence,\n type SyncoreWebPersistence,\n type WebPersistenceMode\n} from \"./persistence.js\";\nimport {\n BroadcastChannelExternalChangeSignal,\n createDefaultSyncChannelName,\n SqlJsExternalChangeApplier\n} from \"./external-change.js\";\nimport { SqlJsDriver } from \"./sqljs.js\";\nimport {\n attachWebWorkerRuntime,\n type SyncoreWorkerMessageEndpoint\n} from \"./worker.js\";\nexport * from \"./worker.js\";\nexport * from \"./persistence.js\";\nexport * from \"./indexeddb.js\";\nexport * from \"./opfs.js\";\nexport * from \"./external-change.js\";\n\n/**\n * Schema type constraint for web-platform Syncore runtimes.\n *\n * Pass any schema produced by `defineSchema()` where this type is expected.\n * Defaults to the unconstrained `SyncoreDataModel` when omitted.\n */\nexport type WebSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = TSchema;\n/**\n * Alias of {@link WebSyncoreSchema} for the `syncorejs/browser` surface.\n * @see WebSyncoreSchema\n */\nexport type BrowserSyncoreSchema<\n TSchema extends SyncoreDataModel = SyncoreDataModel\n> = WebSyncoreSchema<TSchema>;\n\nconst DEVTOOLS_META_NAMESPACE = \"__syncore_devtools_meta__\";\nconst STORAGE_SCOPE_ID_PREFIX = \"storage-scope\";\nconst DATA_SOURCE_ALIAS_PREFIX = \"data-source-alias\";\n\n/**\n * Options for constructing a browser Syncore runtime.\n *\n * Use this when you want to host the full runtime directly in a browser tab or\n * dedicated Web Worker. In most React or Svelte apps you should call\n * `createWebWorkerSyncoreRuntime()` inside a worker file instead, so that\n * SQLite and query execution run off the main thread.\n *\n * At minimum you must supply `schema` and `functions`. Everything else has\n * sensible defaults (OPFS persistence, SQL.js driver, auto-devtools connect).\n *\n * ```ts\n * const runtime = await createWebSyncoreRuntime({\n * schema,\n * functions,\n * databaseName: \"my-app\",\n * });\n * ```\n */\nexport interface CreateWebRuntimeOptions<\n TSchema extends WebSyncoreSchema = WebSyncoreSchema\n> {\n /** The data model that defines the available tables and indexes. */\n schema: TSchema;\n\n /**\n * The registered function map. In practice this is always the `functions`\n * export from `syncore/_generated/functions.ts`.\n */\n functions: SyncoreRuntimeOptions<TSchema>[\"functions\"];\n\n /**\n * Resolved Syncore component instances to mount alongside the root app.\n * Only required when your app installs Syncore component packages.\n */\n components?: SyncoreRuntimeOptions<TSchema>[\"components\"];\n\n /**\n * Platform capabilities injected into `ctx.capabilities` inside function\n * handlers. Use this to expose browser APIs (e.g. `navigator.geolocation`)\n * to your Syncore functions in a portable way.\n */\n capabilities?: SyncoreCapabilities;\n\n /**\n * Custom SQLite driver. Defaults to a `SqlJsDriver` backed by the\n * persistence layer chosen by `persistenceMode` / `persistence`.\n *\n * Override only when you need a non-standard SQLite binding.\n */\n driver?: SyncoreRuntimeOptions<TSchema>[\"driver\"];\n\n /**\n * Custom blob storage adapter. Defaults to `BrowserFileStorageAdapter`\n * only when the resolved persistence layer is OPFS. IndexedDB persistence is\n * data-only unless a custom adapter is provided explicitly.\n *\n * Override when you want to store files in a different location (e.g. an\n * in-memory adapter for tests).\n */\n storage?: SyncoreStorageAdapter;\n\n /**\n * An explicit persistence implementation. When provided, `persistenceMode`,\n * `persistenceDatabaseName`, and `opfsRootDirectoryName` are ignored.\n *\n * Most apps should omit this and let Syncore choose the best available mode\n * automatically via `persistenceMode`.\n */\n persistence?: SyncoreWebPersistence;\n\n /**\n * Which browser storage backend Syncore should use when it creates the\n * persistence layer for you.\n *\n * - `\"opfs\"` — Origin Private File System (recommended for modern browsers;\n * supports large databases and true WAL mode).\n * - `\"indexeddb\"` — IndexedDB-backed persistence (wider compatibility).\n *\n * Defaults to the best mode available in the current browser.\n */\n persistenceMode?: WebPersistenceMode;\n\n /**\n * Logical name used to namespace the SQL.js database and local storage keys.\n *\n * Set a stable value (e.g. your app’s slug) so the database persists across\n * page reloads with a predictable name. Defaults to `\"syncore\"`.\n */\n databaseName?: string;\n\n /**\n * IndexedDB database name used to store persistence metadata (e.g. the OPFS\n * scope identifier). Defaults to `databaseName`.\n */\n persistenceDatabaseName?: string;\n\n /**\n * OPFS root directory name for the SQLite database file and blob storage.\n * Defaults to `databaseName` or `\"syncore\"`.\n */\n opfsRootDirectoryName?: string;\n\n /**\n * Namespace prefix for blob storage keys. Defaults to `databaseName` or\n * `\"syncore\"`.\n */\n storageNamespace?: string;\n\n /**\n * Explicit URL for the `sql.js` WebAssembly binary.\n *\n * Syncore resolves the URL automatically in most bundler setups. Override\n * this only if the auto-resolved URL is incorrect (e.g. in a custom CDN\n * deploy or a worker with a different asset base path).\n */\n wasmUrl?: string;\n\n /**\n * Custom file resolver for SQL.js support files (wasm + worker scripts).\n *\n * Takes a filename (e.g. `\"sql-wasm.wasm\"`) and returns the full URL.\n * Equivalent to sql.js’s `locateFile` option. Use `wasmUrl` instead when\n * you only need to override the `.wasm` path.\n */\n locateFile?: (fileName: string) => string;\n\n /**\n * Platform label reported to the devtools dashboard.\n * Defaults to `\"browser\"`.\n */\n platform?: string;\n\n /** Human-readable app name shown in the devtools dashboard header. */\n appName?: string;\n\n /**\n * Explicit devtools WebSocket server URL.\n * Defaults to `ws://127.0.0.1:4311` (the Syncore devtools default port).\n */\n devtoolsUrl?: string;\n\n /**\n * Devtools event sink. Pass `false` to disable devtools entirely\n * (recommended for production builds). Omit to auto-connect to the local\n * devtools server when running in development.\n */\n devtools?: DevtoolsSink | false;\n\n /** Scheduler configuration for background and recurring jobs. */\n scheduler?: SchedulerOptions;\n}\n\n/**\n * Options for hosting a Syncore runtime inside a dedicated browser Worker.\n *\n * Extends {@link CreateWebRuntimeOptions} with the `endpoint` field that wires\n * the runtime to the worker’s message port. Use this inside a worker entry\n * file (`syncore.worker.ts`):\n *\n * ```ts\n * // syncore.worker.ts\n * import { createWebWorkerSyncoreRuntime } from \"syncorejs/browser\";\n * import schema from \"./syncore/schema\";\n * import { functions } from \"./syncore/_generated/functions\";\n *\n * createWebWorkerSyncoreRuntime({\n * schema,\n * functions,\n * endpoint: self as unknown as SyncoreWorkerMessageEndpoint,\n * });\n * ```\n */\nexport interface CreateWebWorkerRuntimeOptions<\n TSchema extends WebSyncoreSchema = WebSyncoreSchema\n> extends CreateWebRuntimeOptions<TSchema> {\n /** The message endpoint exposed by the current worker global. */\n endpoint: SyncoreWorkerMessageEndpoint;\n}\n\n/**\n * Alias of {@link CreateWebRuntimeOptions} for the `syncorejs/browser` surface.\n * @see CreateWebRuntimeOptions\n */\nexport type CreateBrowserRuntimeOptions<\n TSchema extends BrowserSyncoreSchema = BrowserSyncoreSchema\n> = CreateWebRuntimeOptions<TSchema>;\n\n/**\n * Alias of {@link CreateWebWorkerRuntimeOptions} for the `syncorejs/browser` surface.\n * @see CreateWebWorkerRuntimeOptions\n */\nexport type CreateBrowserWorkerRuntimeOptions<\n TSchema extends BrowserSyncoreSchema = BrowserSyncoreSchema\n> = CreateWebWorkerRuntimeOptions<TSchema>;\n\n/**\n * Internal bookkeeping for the browser cross-tab change synchronisation layer.\n *\n * Holds the `BroadcastChannel`-based signal that publishes and receives\n * database-change events between tabs, and optionally an `applier` that\n * reconciles incoming changes into an in-memory SQL.js database.\n *\n * You do not need to use this directly — `createWebSyncoreRuntime` builds it\n * for you from your options. Exposed for advanced setups (e.g. Expo web) that\n * construct the change support layer independently.\n */\nexport interface WebExternalChangeSupport {\n signal: BroadcastChannelExternalChangeSignal;\n applier?: SqlJsExternalChangeApplier;\n}\n\n/**\n * Create a full Syncore runtime directly in the browser (main thread or\n * shared worker).\n *\n * This function sets up SQL.js, the OPFS/IndexedDB persistence layer,\n * OPFS-backed blob storage when available, cross-tab change synchronisation via `BroadcastChannel`, and\n * auto-connects to the devtools server in development.\n *\n * @remarks\n * Most React/Svelte apps should run the runtime inside a `Worker` using\n * `createWebWorkerSyncoreRuntime()` instead, so that SQLite queries don’t\n * block the main thread. Use `createWebSyncoreRuntime` only when a worker is\n * not practical (e.g. in Electron renderer processes or certain test setups).\n *\n * ```ts\n * const runtime = await createWebSyncoreRuntime({ schema, functions });\n * await runtime.start();\n * const client = runtime.createClient();\n * ```\n */\nexport async function createWebSyncoreRuntime<TSchema extends WebSyncoreSchema>(\n options: CreateWebRuntimeOptions<TSchema>\n): Promise<SyncoreRuntime<TSchema>> {\n const persistence =\n options.persistence ??\n (await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName:\n options.opfsRootDirectoryName ?? options.databaseName ?? \"syncore\"\n }));\n const wasmUrl =\n options.wasmUrl ??\n (options.locateFile || !isBrowserLikeRuntime()\n ? undefined\n : await resolveDefaultWebWasmUrl());\n const driver =\n options.driver ??\n (await SqlJsDriver.create({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n ...(wasmUrl ? { wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n }));\n const storageNamespace =\n options.storageNamespace ?? options.databaseName ?? \"syncore\";\n const storage =\n options.storage ??\n (persistence.storageProtocol === \"opfs\"\n ? new BrowserFileStorageAdapter(persistence, storageNamespace)\n : new UnavailableBrowserStorageAdapter(\n BROWSER_STORAGE_UNAVAILABLE_REASON\n ));\n const runtimeCapabilities = createBrowserRuntimeCapabilities(\n persistence,\n storage,\n Boolean(options.storage)\n );\n const externalChangeSupport = createWebExternalChangeSupport({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n driver\n });\n const appName = options.appName ?? resolveWebAppName();\n const origin = resolveWebOrigin();\n const sessionLabel = resolveWebSessionLabel();\n const databaseLabel = options.databaseName ?? \"syncore\";\n const storageScopeId = await resolvePersistedStorageScopeId(\n persistence,\n databaseLabel\n );\n const dataSourceAlias = await resolvePersistedDataSourceAlias(\n persistence,\n databaseLabel\n );\n const storageIdentity = [\n origin ?? \"unknown-origin\",\n persistence.storageProtocol,\n databaseLabel,\n storageScopeId\n ].join(\"::\");\n const autoDevtools =\n options.devtools === undefined && shouldAutoConnectDevtools()\n ? (() => {\n const sinkOptions: BrowserWebSocketDevtoolsSinkOptions = {\n url: options.devtoolsUrl ?? resolveDefaultDevtoolsUrl(),\n targetKind: \"client\",\n storageProtocol: persistence.storageProtocol,\n databaseLabel,\n dataSourceAlias,\n storageIdentity,\n capabilities: createBrowserDevtoolsCapabilities(runtimeCapabilities)\n };\n if (appName) {\n sinkOptions.appName = appName;\n }\n if (origin) {\n sinkOptions.origin = origin;\n }\n if (sessionLabel) {\n sinkOptions.sessionLabel = sessionLabel;\n }\n return createBrowserWebSocketDevtoolsSink(sinkOptions);\n })()\n : undefined;\n const resolvedDevtools =\n options.devtools === false ? undefined : (options.devtools ?? autoDevtools);\n\n announceBrowserSession({\n enabled: resolvedDevtools !== undefined,\n sessionLabel,\n appName,\n origin,\n devtoolsUrl:\n options.devtools && typeof options.devtools === \"object\"\n ? undefined\n : (options.devtoolsUrl ?? resolveDefaultDevtoolsUrl())\n });\n\n const runtime = new SyncoreRuntime({\n schema: options.schema,\n functions: options.functions,\n ...(options.components ? { components: options.components } : {}),\n driver,\n storage,\n externalChangeSignal: externalChangeSupport.signal,\n ...(externalChangeSupport.applier\n ? { externalChangeApplier: externalChangeSupport.applier }\n : {}),\n platform: options.platform ?? \"browser\",\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n runtimeCapabilities,\n ...(resolvedDevtools ? { devtools: resolvedDevtools } : {}),\n ...(options.scheduler ? { scheduler: options.scheduler } : {})\n });\n\n if (isAttachableBrowserDevtoolsSink(resolvedDevtools)) {\n resolvedDevtools.attachRuntime(runtime);\n resolvedDevtools.attachCommandHandler(\n createDevtoolsCommandHandler({\n driver,\n schema: options.schema,\n functions: options.functions,\n admin: runtime.getAdmin()\n })\n );\n resolvedDevtools.attachSubscriptionHost(\n createDevtoolsSubscriptionHost({\n driver,\n schema: options.schema,\n functions: options.functions,\n admin: runtime.getAdmin()\n })\n );\n }\n\n return runtime;\n}\n\nfunction isAttachableBrowserDevtoolsSink(\n sink: DevtoolsSink | undefined\n): sink is BrowserWebSocketDevtoolsSink {\n return (\n !!sink &&\n typeof (sink as BrowserWebSocketDevtoolsSink).attachRuntime ===\n \"function\" &&\n typeof (sink as BrowserWebSocketDevtoolsSink).attachCommandHandler ===\n \"function\" &&\n typeof (sink as BrowserWebSocketDevtoolsSink).attachSubscriptionHost ===\n \"function\"\n );\n}\n\n/**\n * Build a {@link WebExternalChangeSupport} bundle for a given database and\n * persistence layer.\n *\n * Creates a `BroadcastChannel`-based signal so that all tabs sharing the same\n * `databaseName` are notified when a mutation commits. When `driver` is a\n * `SqlJsDriver` (i.e. an in-memory database), an `applier` is also created so\n * the local database can be updated from the latest on-disk snapshot.\n *\n * Called automatically by `createWebSyncoreRuntime`. Exposed for advanced use\n * cases such as the Expo web adapter.\n */\nexport function createWebExternalChangeSupport(options: {\n databaseName: string;\n persistence: SyncoreWebPersistence;\n driver: CreateWebRuntimeOptions<SyncoreDataModel>[\"driver\"] | undefined;\n}): WebExternalChangeSupport {\n const signal = new BroadcastChannelExternalChangeSignal({\n channelName: createDefaultSyncChannelName(options.databaseName)\n });\n const sqlDriver =\n options.driver instanceof SqlJsDriver ? options.driver : undefined;\n\n if (!sqlDriver) {\n return { signal };\n }\n\n return {\n signal,\n applier: new SqlJsExternalChangeApplier({\n databaseName: options.databaseName,\n persistence: options.persistence,\n createDatabase: (bytes) => sqlDriver.createDatabaseFromBytes(bytes),\n replaceDatabase: (database) => {\n sqlDriver.replaceDatabase(database);\n }\n })\n };\n}\n\n/**\n * Build a {@link WebExternalChangeSupport} bundle for an Expo app running on\n * the web platform.\n *\n * Behaves identically to {@link createWebExternalChangeSupport} but accepts\n * the same options shape used by `createExpoSyncoreRuntime`, making it easy\n * to share config when bootstrapping an Expo web runtime.\n *\n * Called internally by the Expo platform adapter. Use directly only when\n * constructing the runtime outside of `createExpoSyncoreRuntime`.\n */\nexport async function createExpoWebExternalChangeSupport(options: {\n databaseName: string;\n locateFile?: (fileName: string) => string;\n wasmUrl?: string;\n persistenceDatabaseName?: string;\n opfsRootDirectoryName?: string;\n persistenceMode?: WebPersistenceMode;\n}): Promise<WebExternalChangeSupport> {\n const persistence = await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName: options.opfsRootDirectoryName ?? options.databaseName\n });\n const wasmUrl =\n options.wasmUrl ??\n (options.locateFile || !isBrowserLikeRuntime()\n ? undefined\n : await resolveDefaultWebWasmUrl());\n const driver = await SqlJsDriver.create({\n databaseName: options.databaseName,\n persistence,\n ...(wasmUrl ? { wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n });\n\n return createWebExternalChangeSupport({\n databaseName: options.databaseName,\n persistence,\n driver\n });\n}\n\n/**\n * Start a Syncore runtime inside a browser `Worker` and wire it to the\n * worker’s own message endpoint.\n *\n * This is the function you call **inside your worker file** (`syncore.worker.ts`).\n * It creates the full runtime (SQL.js + OPFS + BroadcastChannel) in the worker\n * context and begins listening for messages from the main-thread client.\n *\n * ```ts\n * // syncore.worker.ts\n * import { createWebWorkerRuntime } from \"syncorejs/browser\";\n * import schema from \"./syncore/schema\";\n * import { functions } from \"./syncore/_generated/functions\";\n *\n * void createWebWorkerRuntime({\n * schema,\n * functions,\n * endpoint: self as unknown as SyncoreWorkerMessageEndpoint,\n * });\n * ```\n *\n * On the main thread, connect with `createManagedWebWorkerClient()` or\n * `SyncoreNextProvider` (Next.js).\n */\nexport function createWebWorkerRuntime<TSchema extends WebSyncoreSchema>(\n options: CreateWebWorkerRuntimeOptions<TSchema>\n) {\n return attachWebWorkerRuntime({\n endpoint: options.endpoint,\n createRuntime: () =>\n createWebSyncoreRuntime({\n ...options,\n platform: options.platform ?? \"browser-worker\"\n })\n });\n}\n\n/**\n * Alias of {@link createWebWorkerRuntime} for the `syncorejs/browser` surface.\n * @see createWebWorkerRuntime\n */\nexport function createBrowserWorkerRuntime(\n options: CreateBrowserWorkerRuntimeOptions\n) {\n return createWebWorkerRuntime(options);\n}\n\n/**\n * Create a same-process Syncore client from a started browser runtime.\n *\n * Use this when the runtime lives in the same context as the client (e.g.\n * main-thread runtime in an Electron renderer or a test harness). For\n * worker-based setups use `createManagedWebWorkerClient()` instead, which\n * communicates with the worker over `postMessage`.\n *\n * ```ts\n * const runtime = await createWebSyncoreRuntime({ schema, functions });\n * await runtime.start();\n * const client = createWebSyncoreClient(runtime);\n * ```\n */\nexport function createWebSyncoreClient<TSchema extends WebSyncoreSchema>(\n runtime: SyncoreRuntime<TSchema>\n) {\n return runtime.createClient();\n}\n\n/**\n * Alias of {@link createWebSyncoreRuntime} for the `syncorejs/browser` surface.\n * @see createWebSyncoreRuntime\n */\nexport function createBrowserSyncoreRuntime<\n TSchema extends BrowserSyncoreSchema\n>(options: CreateBrowserRuntimeOptions<TSchema>) {\n return createWebSyncoreRuntime(options);\n}\n\n/**\n * Alias of {@link createWebSyncoreClient} for the `syncorejs/browser` surface.\n * @see createWebSyncoreClient\n */\nexport function createBrowserSyncoreClient<\n TSchema extends BrowserSyncoreSchema\n>(runtime: SyncoreRuntime<TSchema>) {\n return createWebSyncoreClient(runtime);\n}\n\n/**\n * Configuration options for {@link createBrowserWebSocketDevtoolsSink}.\n *\n * All fields except `url` are optional — `createWebSyncoreRuntime` fills them\n * in automatically from the runtime’s own metadata.\n */\nexport interface BrowserWebSocketDevtoolsSinkOptions {\n /** WebSocket URL of the Syncore devtools server, e.g. `\"ws://127.0.0.1:4311\"`. */\n url: string;\n /**\n * How long to wait before attempting a reconnect after the WebSocket closes,\n * in milliseconds. Defaults to `1200`.\n */\n reconnectDelayMs?: number;\n /** Human-readable app name shown in the devtools dashboard header. */\n appName?: string;\n /** Origin label (e.g. `window.location.origin`) shown in the devtools session list. */\n origin?: string;\n /** Session label auto-generated from the tab’s URL path; helps distinguish multiple open tabs. */\n sessionLabel?: string;\n /** Kind of this devtools participant. Always `\"client\"` for browser runtimes. */\n targetKind?: \"client\";\n /** Persistence protocol tag reported to devtools (e.g. `\"opfs\"`, `\"indexeddb\"`). */\n storageProtocol?: string;\n /** Logical database name used to group sessions in the devtools UI. */\n databaseLabel?: string;\n /** Stable alias for the data source, used by devtools for cross-session continuity. */\n dataSourceAlias?: string;\n /**\n * Opaque identity string that uniquely identifies this database across origin\n * + persistence protocol + name, used by devtools for data-source tracking.\n */\n storageIdentity?: string;\n /** Capability flags advertising what devtools features this runtime supports. */\n capabilities?: SyncoreDevtoolsCapabilities;\n}\n\nasync function resolveDefaultWebWasmUrl(): Promise<string | undefined> {\n try {\n const module = await import(\"./web-sqljs-wasm.js\");\n return module.resolveDefaultWebSqlJsWasmUrl();\n } catch (error) {\n if (!isBrowserLikeRuntime()) {\n return undefined;\n }\n throw new Error(\n \"Syncore could not resolve the default sql.js WebAssembly asset. \" +\n \"Pass wasmUrl or locateFile to createWebSyncoreRuntime/createBrowserWorkerRuntime for this bundler.\",\n { cause: error }\n );\n }\n}\n\nfunction isBrowserLikeRuntime(): boolean {\n const scope = globalThis as typeof globalThis & {\n WorkerGlobalScope?: unknown;\n };\n return typeof window !== \"undefined\" || scope.WorkerGlobalScope !== undefined;\n}\n\n/**\n * A DevtoolsSink that forwards runtime events to the Syncore devtools\n * dashboard over a persistent WebSocket connection with auto-reconnect.\n *\n * Returned by {@link createBrowserWebSocketDevtoolsSink}. You typically do not\n * use this interface directly — `createWebSyncoreRuntime` creates and manages\n * the sink automatically when running in development.\n */\nexport interface BrowserWebSocketDevtoolsSink extends DevtoolsSink {\n /** Attach the runtime so the sink can pull metadata for devtools messages. */\n attachRuntime(runtime: SyncoreRuntime<WebSyncoreSchema>): void;\n /** Attach the command handler that processes devtools RPC commands. */\n attachCommandHandler(handler: DevtoolsCommandHandler): void;\n /** Attach the subscription host for live query streaming. */\n attachSubscriptionHost(host: DevtoolsSubscriptionHost): void;\n /** Close the WebSocket and stop reconnecting. Call on runtime shutdown. */\n dispose(): void;\n}\n\n/**\n * Create a WebSocket-based devtools sink that connects to the Syncore devtools\n * server and forwards runtime events in real time.\n *\n * The sink auto-reconnects if the connection drops (e.g. while the devtools\n * dashboard is restarting) and buffers events that arrive before the socket is\n * open.\n *\n * In most cases you do not need to call this directly — `createWebSyncoreRuntime`\n * creates and attaches the sink automatically when `devtools` is omitted and the\n * page is served from a local/private hostname.\n *\n * ```ts\n * const sink = createBrowserWebSocketDevtoolsSink({\n * url: \"ws://127.0.0.1:4311\",\n * appName: \"My App\",\n * });\n * const runtime = await createWebSyncoreRuntime({ schema, functions, devtools: sink });\n * ```\n */\nexport function createBrowserWebSocketDevtoolsSink(\n options: BrowserWebSocketDevtoolsSinkOptions\n): BrowserWebSocketDevtoolsSink {\n let socket: WebSocket | undefined;\n let disposed = false;\n let connectTimer: ReturnType<typeof setTimeout> | undefined;\n let getSummary: (() => SyncoreRuntimeSummary) | undefined;\n let onCommand: DevtoolsCommandHandler | undefined;\n let subscriptionHost: DevtoolsSubscriptionHost | undefined;\n const pendingMessages: SyncoreDevtoolsMessage[] = [];\n let latestHello:\n | {\n runtimeId: string;\n platform: string;\n }\n | undefined;\n\n const connect = () => {\n if (disposed || typeof WebSocket === \"undefined\") {\n return;\n }\n socket = new WebSocket(options.url);\n socket.onopen = () => {\n if (latestHello) {\n sendNow({\n type: \"hello\",\n protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,\n minSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,\n maxSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,\n runtimeId: latestHello.runtimeId,\n platform: latestHello.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel\n ? { databaseLabel: options.databaseLabel }\n : {}),\n ...(options.dataSourceAlias\n ? { dataSourceAlias: options.dataSourceAlias }\n : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {}),\n capabilities:\n options.capabilities ?? createBrowserDevtoolsCapabilities()\n });\n }\n flushPendingMessages();\n };\n socket.onmessage = (event) => {\n if (typeof event.data !== \"string\") {\n return;\n }\n const message = JSON.parse(event.data) as\n | SyncoreDevtoolsMessage\n | SyncoreDevtoolsClientMessage;\n if (message.type === \"ping\") {\n send({ type: \"pong\" });\n } else if (message.type === \"command\" && onCommand) {\n onCommand(message.payload)\n .then((responsePayload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"command.result\",\n commandId: message.commandId,\n runtimeId,\n payload: responsePayload\n });\n })\n .catch((err) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"command.result\",\n commandId: message.commandId,\n runtimeId,\n payload: {\n kind: \"error\",\n message: err instanceof Error ? err.message : \"Unknown error\"\n }\n });\n });\n } else if (message.type === \"subscribe\" && subscriptionHost) {\n void subscriptionHost.subscribe(\n message.subscriptionId,\n message.payload,\n (payload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"subscription.data\",\n subscriptionId: message.subscriptionId,\n runtimeId,\n payload\n });\n }\n );\n } else if (message.type === \"unsubscribe\") {\n subscriptionHost?.unsubscribe(message.subscriptionId);\n }\n };\n socket.onclose = scheduleReconnect;\n socket.onerror = () => {\n socket?.close();\n };\n };\n\n const scheduleReconnect = () => {\n if (disposed || connectTimer) {\n return;\n }\n connectTimer = setTimeout(() => {\n connectTimer = undefined;\n connect();\n }, options.reconnectDelayMs ?? 1200);\n };\n\n const sendNow = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify(message));\n }\n };\n\n const flushPendingMessages = () => {\n while (pendingMessages.length > 0) {\n const nextMessage = pendingMessages.shift();\n if (nextMessage) {\n sendNow(nextMessage);\n }\n }\n };\n\n const send = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n sendNow(message);\n return;\n }\n pendingMessages.push(message);\n };\n\n connect();\n\n return {\n emit(event) {\n if (event.type === \"runtime.connected\") {\n latestHello = {\n runtimeId: event.runtimeId,\n platform: event.platform\n };\n send({\n type: \"hello\",\n protocolVersion: SYNCORE_DEVTOOLS_PROTOCOL_VERSION,\n minSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MIN_SUPPORTED_PROTOCOL_VERSION,\n maxSupportedProtocolVersion:\n SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION,\n runtimeId: event.runtimeId,\n platform: event.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel\n ? { databaseLabel: options.databaseLabel }\n : {}),\n ...(options.dataSourceAlias\n ? { dataSourceAlias: options.dataSourceAlias }\n : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {}),\n capabilities:\n options.capabilities ?? createBrowserDevtoolsCapabilities()\n });\n }\n send({ type: \"event\", event });\n },\n attachRuntime(runtime) {\n getSummary = () =>\n withRuntimeSummaryMeta(runtime.getAdmin().getRuntimeSummary(), options);\n },\n attachCommandHandler(handler) {\n onCommand = handler;\n },\n attachSubscriptionHost(host) {\n subscriptionHost = host;\n },\n dispose() {\n disposed = true;\n if (connectTimer) {\n clearTimeout(connectTimer);\n }\n subscriptionHost?.dispose();\n socket?.close();\n }\n };\n}\n\nfunction withRuntimeSummaryMeta(\n summary: SyncoreRuntimeSummary,\n options: BrowserWebSocketDevtoolsSinkOptions\n): SyncoreRuntimeSummary {\n return {\n ...summary,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.dataSourceAlias\n ? { dataSourceAlias: options.dataSourceAlias }\n : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {}),\n capabilities: options.capabilities ?? createBrowserDevtoolsCapabilities()\n };\n}\n\nfunction createBrowserRuntimeCapabilities(\n persistence: SyncoreWebPersistence,\n storage: SyncoreStorageAdapter,\n hasExplicitStorage: boolean\n): SyncoreRuntimeCapabilities {\n if (!hasExplicitStorage && persistence.storageProtocol !== \"opfs\") {\n return {\n storage: {\n available: false,\n reason: BROWSER_STORAGE_UNAVAILABLE_REASON,\n protocol: persistence.storageProtocol,\n supportsRange: false\n }\n };\n }\n return {\n storage: {\n available: true,\n protocol: hasExplicitStorage ? \"custom\" : persistence.storageProtocol,\n ...(storage.supportsRange\n ? { supportsRange: storage.supportsRange() !== false }\n : {})\n }\n };\n}\n\nfunction createBrowserDevtoolsCapabilities(\n runtimeCapabilities?: SyncoreRuntimeCapabilities\n): SyncoreDevtoolsCapabilities {\n const storageCapability = runtimeCapabilities?.storage;\n const storageAvailable = storageCapability?.available !== false;\n return {\n sql: {\n read: false,\n write: false,\n live: false,\n reason: \"SQL Console is not available for browser runtimes.\"\n },\n data: {\n browse: true,\n mutate: true,\n importExport: true\n },\n storage: {\n browse: storageAvailable,\n download: storageAvailable,\n readRange: storageCapability?.supportsRange === true,\n delete: storageAvailable,\n maxPreviewBytes: 80_000,\n ...(!storageAvailable && storageCapability?.reason\n ? { reason: storageCapability.reason }\n : {})\n },\n scheduler: {\n read: true,\n edit: true\n }\n };\n}\n\nfunction shouldAutoConnectDevtools(): boolean {\n const hostname = resolveWebHostname();\n if (!hostname) {\n return false;\n }\n return (\n hostname === \"localhost\" ||\n isPrivateNetworkHostname(hostname) ||\n hostname.endsWith(\".local\")\n );\n}\n\nfunction resolveDefaultDevtoolsUrl(): string {\n return \"ws://127.0.0.1:4311\";\n}\n\nfunction resolveLocationString(\n key: \"href\" | \"origin\" | \"hostname\"\n): string | undefined {\n try {\n const value = globalThis.location?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveGlobalOrigin(): string | undefined {\n try {\n const value = (globalThis as { origin?: unknown }).origin;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction parseUrlCandidate(candidate: string | undefined): URL | undefined {\n if (!candidate || candidate === \"null\") {\n return undefined;\n }\n try {\n const parsed = new URL(candidate);\n if (parsed.protocol === \"blob:\" && parsed.pathname.length > 0) {\n try {\n return new URL(parsed.pathname);\n } catch {\n return parsed;\n }\n }\n return parsed;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebHostname(): string | undefined {\n const directHostname = resolveLocationString(\"hostname\");\n if (directHostname) {\n return directHostname;\n }\n return (\n parseUrlCandidate(resolveLocationString(\"href\"))?.hostname ||\n parseUrlCandidate(resolveLocationString(\"origin\"))?.hostname ||\n parseUrlCandidate(resolveGlobalOrigin())?.hostname ||\n undefined\n );\n}\n\nfunction isPrivateNetworkHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (normalized === \"::1\") {\n return true;\n }\n if (normalized.startsWith(\"fc\") || normalized.startsWith(\"fd\")) {\n return true;\n }\n const match = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(normalized);\n if (!match) {\n return false;\n }\n const octets = match.slice(1).map((part) => Number(part));\n if (octets.some((part) => Number.isNaN(part) || part < 0 || part > 255)) {\n return false;\n }\n const first = octets[0];\n const second = octets[1];\n if (first === undefined || second === undefined) {\n return false;\n }\n return (\n first === 10 ||\n first === 127 ||\n (first === 169 && second === 254) ||\n (first === 172 && second >= 16 && second <= 31) ||\n (first === 192 && second === 168)\n );\n}\n\nfunction resolveWebOrigin(): string | undefined {\n const directOrigin = resolveLocationString(\"origin\");\n if (directOrigin && directOrigin !== \"null\") {\n return directOrigin;\n }\n const parsedOrigin =\n parseUrlCandidate(resolveLocationString(\"href\"))?.origin ||\n parseUrlCandidate(resolveGlobalOrigin())?.origin;\n return parsedOrigin && parsedOrigin !== \"null\" ? parsedOrigin : undefined;\n}\n\nfunction resolveWebAppName(): string | undefined {\n try {\n return resolveWebHostname() ?? globalThis.document?.title ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebSessionLabel(): string | undefined {\n try {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n\n // Generate or retrieve a persistent unique name for this browser instance.\n // This makes it much easier to identify which browser tab/window you're\n // looking at in the devtools dashboard.\n const STORAGE_KEY = \"syncore-session-name\";\n let uniqueName: string | null = null;\n\n try {\n uniqueName = globalThis.localStorage?.getItem(STORAGE_KEY) ?? null;\n } catch {\n /* localStorage may not be available */\n }\n\n if (!uniqueName) {\n uniqueName = generateUniqueSessionName();\n\n try {\n globalThis.localStorage?.setItem(STORAGE_KEY, uniqueName);\n } catch {\n /* ignore storage errors */\n }\n }\n\n const browser = resolveBrowserName(navigator);\n\n return `${uniqueName} (${browser})`;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveBrowserName(\n nav: Navigator & {\n userAgentData?: {\n brands?: Array<{\n brand: string;\n }>;\n };\n }\n): string {\n const brands = nav.userAgentData?.brands?.map((entry) => entry.brand) ?? [];\n\n if (brands.some((brand) => /microsoft edge/i.test(brand))) {\n return \"Edge\";\n }\n if (brands.some((brand) => /firefox/i.test(brand))) {\n return \"Firefox\";\n }\n if (brands.some((brand) => /opera/i.test(brand))) {\n return \"Opera\";\n }\n if (brands.some((brand) => /chrome|chromium/i.test(brand))) {\n return \"Chrome\";\n }\n if (brands.some((brand) => /safari/i.test(brand))) {\n return \"Safari\";\n }\n\n const userAgent = nav.userAgent;\n if (/Firefox\\//i.test(userAgent)) {\n return \"Firefox\";\n }\n if (/Edg\\//i.test(userAgent)) {\n return \"Edge\";\n }\n if (/OPR\\/|Opera/i.test(userAgent)) {\n return \"Opera\";\n }\n if (/Chrome\\/|CriOS\\//i.test(userAgent)) {\n return \"Chrome\";\n }\n if (/Safari\\//i.test(userAgent)) {\n return \"Safari\";\n }\n return \"Browser\";\n}\n\nasync function resolvePersistedStorageScopeId(\n persistence: SyncoreWebPersistence,\n databaseLabel: string\n): Promise<string> {\n const id = `${STORAGE_SCOPE_ID_PREFIX}:${databaseLabel}`;\n const existing = await persistence.getFile(DEVTOOLS_META_NAMESPACE, id);\n\n if (existing) {\n const value = new TextDecoder().decode(existing.bytes).trim();\n if (value.length > 0) {\n return value;\n }\n }\n\n const nextValue = generateId();\n await persistence.putFile(\n DEVTOOLS_META_NAMESPACE,\n id,\n new TextEncoder().encode(nextValue),\n \"text/plain\"\n );\n return nextValue;\n}\n\nasync function resolvePersistedDataSourceAlias(\n persistence: SyncoreWebPersistence,\n databaseLabel: string\n): Promise<string> {\n const id = `${DATA_SOURCE_ALIAS_PREFIX}:${databaseLabel}`;\n const existing = await persistence.getFile(DEVTOOLS_META_NAMESPACE, id);\n\n if (existing) {\n const value = new TextDecoder().decode(existing.bytes).trim();\n if (value.length > 0) {\n return value;\n }\n }\n\n const nextValue = generateUniqueSessionName();\n await persistence.putFile(\n DEVTOOLS_META_NAMESPACE,\n id,\n new TextEncoder().encode(nextValue),\n \"text/plain\"\n );\n return nextValue;\n}\n\nfunction announceBrowserSession(options: {\n enabled: boolean;\n sessionLabel?: string | undefined;\n appName?: string | undefined;\n origin?: string | undefined;\n devtoolsUrl?: string | undefined;\n}): void {\n if (!options.enabled || !options.sessionLabel) {\n return;\n }\n\n const announcedSessions = getAnnouncedBrowserSessions();\n if (announcedSessions.has(options.sessionLabel)) {\n return;\n }\n announcedSessions.add(options.sessionLabel);\n\n try {\n const details = [\n options.appName ? `app=${options.appName}` : undefined,\n options.origin ? `origin=${options.origin}` : undefined,\n options.devtoolsUrl ? `devtools=${options.devtoolsUrl}` : undefined\n ].filter((value): value is string => value !== undefined);\n\n console.info(\n `[syncore] Browser session: ${options.sessionLabel}${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}`\n );\n } catch {\n /* ignore console failures */\n }\n}\n\nfunction getAnnouncedBrowserSessions(): Set<string> {\n const key = \"__syncoreAnnouncedBrowserSessions\";\n const scope = globalThis as typeof globalThis & {\n [key]?: Set<string>;\n };\n if (!scope[key]) {\n scope[key] = new Set<string>();\n }\n return scope[key];\n}\n\n/* ------------------------------------------------------------------ */\n/* Unique session name generator */\n/* ------------------------------------------------------------------ */\n\nconst SESSION_ADJECTIVES = [\n \"Acrobatic\",\n \"Bold\",\n \"Cosmic\",\n \"Daring\",\n \"Electric\",\n \"Fierce\",\n \"Golden\",\n \"Hidden\",\n \"Iron\",\n \"Jade\",\n \"Keen\",\n \"Lunar\",\n \"Mystic\",\n \"Noble\",\n \"Orbital\",\n \"Primal\",\n \"Quick\",\n \"Radiant\",\n \"Shadow\",\n \"Turbo\",\n \"Ultra\",\n \"Vivid\",\n \"Wicked\",\n \"Xenon\",\n \"Zen\",\n \"Arctic\",\n \"Binary\",\n \"Cyber\",\n \"Digital\",\n \"Ember\",\n \"Frozen\",\n \"Galactic\",\n \"Hyper\",\n \"Infra\",\n \"Jumbo\",\n \"Kinetic\",\n \"Liquid\",\n \"Magnetic\",\n \"Neon\",\n \"Onyx\",\n \"Phantom\",\n \"Quantum\",\n \"Rapid\",\n \"Sonic\",\n \"Titan\",\n \"Velvet\",\n \"Wild\",\n \"Blazing\",\n \"Crystal\",\n \"Dynamic\"\n] as const;\n\nconst SESSION_NOUNS = [\n \"Monkey\",\n \"Phoenix\",\n \"Tiger\",\n \"Dragon\",\n \"Falcon\",\n \"Panther\",\n \"Wolf\",\n \"Eagle\",\n \"Cobra\",\n \"Shark\",\n \"Raven\",\n \"Fox\",\n \"Lynx\",\n \"Hawk\",\n \"Bear\",\n \"Jaguar\",\n \"Viper\",\n \"Owl\",\n \"Stallion\",\n \"Dolphin\",\n \"Developer\",\n \"Hacker\",\n \"Wizard\",\n \"Ninja\",\n \"Pilot\",\n \"Pioneer\",\n \"Voyager\",\n \"Explorer\",\n \"Runner\",\n \"Ranger\",\n \"Maverick\",\n \"Spartan\",\n \"Viking\",\n \"Sentinel\",\n \"Guardian\",\n \"Nomad\",\n \"Cipher\",\n \"Vector\",\n \"Matrix\",\n \"Prism\",\n \"Nebula\",\n \"Comet\",\n \"Pulse\",\n \"Vertex\",\n \"Flux\",\n \"Storm\",\n \"Blaze\",\n \"Frost\",\n \"Thunder\",\n \"Drift\"\n] as const;\n\nconst BROWSER_STORAGE_UNAVAILABLE_REASON =\n \"Browser file storage requires OPFS. IndexedDB is used for data only.\";\n\nfunction generateUniqueSessionName(): string {\n const adj =\n SESSION_ADJECTIVES[Math.floor(Math.random() * SESSION_ADJECTIVES.length)]!;\n const noun = SESSION_NOUNS[Math.floor(Math.random() * SESSION_NOUNS.length)]!;\n return `${adj} ${noun}`;\n}\n\n/**\n * Browser file/blob storage adapter backed by `SyncoreWebPersistence`.\n *\n * Stores binary blobs (images, documents, etc.) in OPFS alongside the SQLite\n * database. Pass an instance to\n * `CreateWebRuntimeOptions.storage` to enable Syncore's Storage API\n * (`ctx.storage.put`, `ctx.storage.get`, etc.) in browser functions.\n *\n * ```ts\n * const runtime = await createWebSyncoreRuntime({\n * schema,\n * functions,\n * storage: new BrowserFileStorageAdapter(persistence, \"files\"),\n * });\n * ```\n */\nexport class BrowserFileStorageAdapter implements SyncoreStorageAdapter {\n constructor(\n private readonly persistence: SyncoreWebPersistence,\n private readonly namespace: string\n ) {\n if (persistence.storageProtocol !== \"opfs\") {\n throw new Error(BROWSER_STORAGE_UNAVAILABLE_REASON);\n }\n }\n\n async put(id: string, input: StorageWriteInput): Promise<StorageObject> {\n const bytes = normalizeBinary(input.data);\n await this.persistence.putFile(\n this.namespace,\n id,\n bytes,\n input.contentType ?? null\n );\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: bytes.byteLength,\n contentType: input.contentType ?? null\n };\n }\n\n async get(id: string): Promise<StorageObject | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n if (!file) {\n return null;\n }\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: file.size,\n contentType: file.contentType\n };\n }\n\n async read(id: string): Promise<Uint8Array | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n return file?.bytes ?? null;\n }\n\n supportsRange(): boolean {\n return Boolean(this.persistence.getFileRange);\n }\n\n async readRange(\n id: string,\n offset: number,\n length: number\n ): Promise<Uint8Array | null> {\n if (!this.persistence.getFileRange) {\n return null;\n }\n const file = await this.persistence.getFileRange(\n this.namespace,\n id,\n offset,\n length\n );\n return file?.bytes ?? null;\n }\n\n async delete(id: string): Promise<void> {\n await this.persistence.deleteFile(this.namespace, id);\n }\n\n async list(): Promise<StorageObject[]> {\n const files = this.persistence.listFileMetadata\n ? await this.persistence.listFileMetadata(this.namespace)\n : await this.persistence.listFiles(this.namespace);\n return files.map((file) => ({\n id: file.id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${file.id}`,\n size: file.size,\n contentType: file.contentType\n }));\n }\n}\n\nclass UnavailableBrowserStorageAdapter implements SyncoreStorageAdapter {\n constructor(private readonly reason: string) {}\n\n async put(): Promise<StorageObject> {\n throw new Error(this.reason);\n }\n\n async get(): Promise<StorageObject | null> {\n throw new Error(this.reason);\n }\n\n async read(): Promise<Uint8Array | null> {\n throw new Error(this.reason);\n }\n\n supportsRange(): boolean {\n return false;\n }\n\n async delete(): Promise<void> {\n throw new Error(this.reason);\n }\n}\n\nfunction normalizeBinary(data: StorageWriteInput[\"data\"]): Uint8Array {\n if (typeof data === \"string\") {\n return new TextEncoder().encode(data);\n }\n if (data instanceof Uint8Array) {\n return data;\n }\n return new Uint8Array(data);\n}\n"],"mappings":"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"}
@@ -1,9 +1,21 @@
1
1
  import { StoredWebFile, SyncoreWebPersistence } from "./persistence.js";
2
2
 
3
3
  //#region src/indexeddb.d.ts
4
+ /** Options for constructing a {@link SyncoreIndexedDbPersistence}. */
4
5
  interface IndexedDbPersistenceOptions {
6
+ /** IndexedDB database name. Defaults to `"syncore-web"`. */
5
7
  databaseName?: string;
6
8
  }
9
+ /**
10
+ * IndexedDB-backed {@link SyncoreWebPersistence} implementation.
11
+ *
12
+ * Stores the SQLite database blob in IndexedDB. It still satisfies the lower
13
+ * level persistence interface for compatibility, but Syncore's default browser
14
+ * file storage is OPFS-only and will not use IndexedDB for blobs.
15
+ *
16
+ * Prefer `createWebPersistence()` over constructing this directly unless
17
+ * you need to pass a specific IndexedDB database name.
18
+ */
7
19
  declare class SyncoreIndexedDbPersistence implements SyncoreWebPersistence {
8
20
  readonly storageProtocol: "idb";
9
21
  private readonly databaseName;
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb.d.ts","names":[],"sources":["../src/indexeddb.ts"],"mappings":";;;UAEiB,2BAAA;EACf,YAAA;AAAA;AAAA,cAiBW,2BAAA,YAAuC,qBAAA;EAAA,SACzC,eAAA;EAAA,iBACQ,YAAA;cAEL,OAAA,GAAU,2BAAA;EAIhB,YAAA,CAAa,GAAA,WAAc,OAAA,CAAQ,UAAA;EAQnC,YAAA,CAAa,GAAA,UAAa,KAAA,EAAO,UAAA,GAAa,OAAA;EAQ9C,OAAA,CACJ,SAAA,UACA,EAAA,WACC,OAAA,CAAQ,aAAA;EAgBL,OAAA,CACJ,SAAA,UACA,EAAA,UACA,KAAA,EAAO,UAAA,EACP,WAAA,kBACC,OAAA;EAUG,UAAA,CAAW,SAAA,UAAmB,EAAA,WAAa,OAAA;EAI3C,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,aAAA;EAAA,QAa9B,WAAA;EAAA,QAuBA,SAAA;EAAA,QAkBA,SAAA;EAAA,QAkBA,YAAA;EAAA,QAkBA,WAAA;AAAA"}
1
+ {"version":3,"file":"indexeddb.d.ts","names":[],"sources":["../src/indexeddb.ts"],"mappings":";;;;UAGiB,2BAAA;EAAA;EAEf,YAAY;AAAA;;AAAA;AA2Bd;;;;;;;;cAAa,2BAAA,YAAuC,qBAAA;EAAA,SACzC,eAAA;EAAA,iBACQ,YAAA;cAEL,OAAA,GAAU,2BAAA;EAIhB,YAAA,CAAa,GAAA,WAAc,OAAA,CAAQ,UAAA;EAQnC,YAAA,CAAa,GAAA,UAAa,KAAA,EAAO,UAAA,GAAa,OAAA;EAQ9C,OAAA,CACJ,SAAA,UACA,EAAA,WACC,OAAA,CAAQ,aAAA;EAgBL,OAAA,CACJ,SAAA,UACA,EAAA,UACA,KAAA,EAAO,UAAA,EACP,WAAA,kBACC,OAAA;EAUG,UAAA,CAAW,SAAA,UAAmB,EAAA,WAAa,OAAA;EAI3C,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,aAAA;EAAA,QAa9B,WAAA;EAAA,QAuBA,SAAA;EAAA,QAqBA,SAAA;EAAA,QAqBA,YAAA;EAAA,QAqBA,WAAA;AAAA"}
@@ -1,4 +1,14 @@
1
1
  //#region src/indexeddb.ts
2
+ /**
3
+ * IndexedDB-backed {@link SyncoreWebPersistence} implementation.
4
+ *
5
+ * Stores the SQLite database blob in IndexedDB. It still satisfies the lower
6
+ * level persistence interface for compatibility, but Syncore's default browser
7
+ * file storage is OPFS-only and will not use IndexedDB for blobs.
8
+ *
9
+ * Prefer `createWebPersistence()` over constructing this directly unless
10
+ * you need to pass a specific IndexedDB database name.
11
+ */
2
12
  var SyncoreIndexedDbPersistence = class {
3
13
  storageProtocol = "idb";
4
14
  databaseName;
@@ -1 +1 @@
1
- {"version":3,"file":"indexeddb.js","names":[],"sources":["../src/indexeddb.ts"],"sourcesContent":["import type { SyncoreWebPersistence, StoredWebFile } from \"./persistence.js\";\n\nexport interface IndexedDbPersistenceOptions {\n databaseName?: string;\n}\n\ntype StoredDatabaseRecord = {\n key: string;\n bytes: ArrayBuffer;\n updatedAt: number;\n};\n\ntype StoredFileRecord = {\n key: string;\n bytes: ArrayBuffer;\n contentType: string | null;\n size: number;\n updatedAt: number;\n};\n\nexport class SyncoreIndexedDbPersistence implements SyncoreWebPersistence {\n readonly storageProtocol = \"idb\" as const;\n private readonly databaseName: string;\n\n constructor(options?: IndexedDbPersistenceOptions) {\n this.databaseName = options?.databaseName ?? \"syncore-web\";\n }\n\n async loadDatabase(key: string): Promise<Uint8Array | null> {\n const record = await this.getRecord<StoredDatabaseRecord>(\"databases\", key);\n if (!record) {\n return null;\n }\n return new Uint8Array(record.bytes);\n }\n\n async saveDatabase(key: string, bytes: Uint8Array): Promise<void> {\n await this.putRecord<StoredDatabaseRecord>(\"databases\", {\n key,\n bytes: sliceToArrayBuffer(bytes),\n updatedAt: Date.now()\n });\n }\n\n async getFile(\n namespace: string,\n id: string\n ): Promise<StoredWebFile | null> {\n const record = await this.getRecord<StoredFileRecord>(\n \"files\",\n createNamespacedKey(namespace, id)\n );\n if (!record) {\n return null;\n }\n return {\n id,\n bytes: new Uint8Array(record.bytes),\n contentType: record.contentType,\n size: record.size\n };\n }\n\n async putFile(\n namespace: string,\n id: string,\n bytes: Uint8Array,\n contentType: string | null\n ): Promise<void> {\n await this.putRecord<StoredFileRecord>(\"files\", {\n key: createNamespacedKey(namespace, id),\n bytes: sliceToArrayBuffer(bytes),\n contentType,\n size: bytes.byteLength,\n updatedAt: Date.now()\n });\n }\n\n async deleteFile(namespace: string, id: string): Promise<void> {\n await this.deleteRecord(\"files\", createNamespacedKey(namespace, id));\n }\n\n async listFiles(namespace: string): Promise<StoredWebFile[]> {\n const prefix = `${namespace}:`;\n const records = await this.listRecords<StoredFileRecord>(\"files\");\n return records\n .filter((record) => record.key.startsWith(prefix))\n .map((record) => ({\n id: record.key.slice(prefix.length),\n bytes: new Uint8Array(record.bytes),\n contentType: record.contentType,\n size: record.size\n }));\n }\n\n private async getDatabase(): Promise<IDBDatabase> {\n const indexedDb = globalThis.indexedDB;\n if (!indexedDb) {\n throw new Error(\"IndexedDB is not available in this environment.\");\n }\n\n return new Promise((resolve, reject) => {\n const request = indexedDb.open(this.databaseName, 1);\n request.onupgradeneeded = () => {\n const database = request.result;\n if (!database.objectStoreNames.contains(\"databases\")) {\n database.createObjectStore(\"databases\", { keyPath: \"key\" });\n }\n if (!database.objectStoreNames.contains(\"files\")) {\n database.createObjectStore(\"files\", { keyPath: \"key\" });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () =>\n reject(request.error ?? new Error(\"Failed to open IndexedDB.\"));\n });\n }\n\n private async getRecord<TRecord>(\n storeName: \"databases\" | \"files\",\n key: string\n ): Promise<TRecord | null> {\n const database = await this.getDatabase();\n try {\n return await new Promise<TRecord | null>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readonly\");\n const request = transaction.objectStore(storeName).get(key);\n request.onsuccess = () => resolve((request.result as TRecord | undefined) ?? null);\n request.onerror = () =>\n reject(request.error ?? new Error(`Failed to read ${storeName}/${key}.`));\n });\n } finally {\n database.close();\n }\n }\n\n private async putRecord<TRecord extends { key: string }>(\n storeName: \"databases\" | \"files\",\n record: TRecord\n ): Promise<void> {\n const database = await this.getDatabase();\n try {\n await new Promise<void>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readwrite\");\n transaction.oncomplete = () => resolve();\n transaction.onerror = () =>\n reject(transaction.error ?? new Error(`Failed to write ${storeName}/${record.key}.`));\n transaction.objectStore(storeName).put(record);\n });\n } finally {\n database.close();\n }\n }\n\n private async deleteRecord(\n storeName: \"databases\" | \"files\",\n key: string\n ): Promise<void> {\n const database = await this.getDatabase();\n try {\n await new Promise<void>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readwrite\");\n transaction.oncomplete = () => resolve();\n transaction.onerror = () =>\n reject(transaction.error ?? new Error(`Failed to delete ${storeName}/${key}.`));\n transaction.objectStore(storeName).delete(key);\n });\n } finally {\n database.close();\n }\n }\n\n private async listRecords<TRecord>(\n storeName: \"databases\" | \"files\"\n ): Promise<TRecord[]> {\n const database = await this.getDatabase();\n try {\n return await new Promise<TRecord[]>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readonly\");\n const request = transaction.objectStore(storeName).getAll();\n request.onsuccess = () => resolve((request.result as TRecord[] | undefined) ?? []);\n request.onerror = () =>\n reject(request.error ?? new Error(`Failed to list records from ${storeName}.`));\n });\n } finally {\n database.close();\n }\n }\n}\n\nfunction createNamespacedKey(namespace: string, id: string): string {\n return `${namespace}:${id}`;\n}\n\nfunction sliceToArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n ) as ArrayBuffer;\n}\n"],"mappings":";AAoBA,IAAa,8BAAb,MAA0E;CACxE,kBAA2B;CAC3B;CAEA,YAAY,SAAuC;AACjD,OAAK,eAAe,SAAS,gBAAgB;;CAG/C,MAAM,aAAa,KAAyC;EAC1D,MAAM,SAAS,MAAM,KAAK,UAAgC,aAAa,IAAI;AAC3E,MAAI,CAAC,OACH,QAAO;AAET,SAAO,IAAI,WAAW,OAAO,MAAM;;CAGrC,MAAM,aAAa,KAAa,OAAkC;AAChE,QAAM,KAAK,UAAgC,aAAa;GACtD;GACA,OAAO,mBAAmB,MAAM;GAChC,WAAW,KAAK,KAAK;GACtB,CAAC;;CAGJ,MAAM,QACJ,WACA,IAC+B;EAC/B,MAAM,SAAS,MAAM,KAAK,UACxB,SACA,oBAAoB,WAAW,GAAG,CACnC;AACD,MAAI,CAAC,OACH,QAAO;AAET,SAAO;GACL;GACA,OAAO,IAAI,WAAW,OAAO,MAAM;GACnC,aAAa,OAAO;GACpB,MAAM,OAAO;GACd;;CAGH,MAAM,QACJ,WACA,IACA,OACA,aACe;AACf,QAAM,KAAK,UAA4B,SAAS;GAC9C,KAAK,oBAAoB,WAAW,GAAG;GACvC,OAAO,mBAAmB,MAAM;GAChC;GACA,MAAM,MAAM;GACZ,WAAW,KAAK,KAAK;GACtB,CAAC;;CAGJ,MAAM,WAAW,WAAmB,IAA2B;AAC7D,QAAM,KAAK,aAAa,SAAS,oBAAoB,WAAW,GAAG,CAAC;;CAGtE,MAAM,UAAU,WAA6C;EAC3D,MAAM,SAAS,GAAG,UAAU;AAE5B,UADgB,MAAM,KAAK,YAA8B,QAAQ,EAE9D,QAAQ,WAAW,OAAO,IAAI,WAAW,OAAO,CAAC,CACjD,KAAK,YAAY;GAChB,IAAI,OAAO,IAAI,MAAM,OAAO,OAAO;GACnC,OAAO,IAAI,WAAW,OAAO,MAAM;GACnC,aAAa,OAAO;GACpB,MAAM,OAAO;GACd,EAAE;;CAGP,MAAc,cAAoC;EAChD,MAAM,YAAY,WAAW;AAC7B,MAAI,CAAC,UACH,OAAM,IAAI,MAAM,kDAAkD;AAGpE,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,MAAM,UAAU,UAAU,KAAK,KAAK,cAAc,EAAE;AACpD,WAAQ,wBAAwB;IAC9B,MAAM,WAAW,QAAQ;AACzB,QAAI,CAAC,SAAS,iBAAiB,SAAS,YAAY,CAClD,UAAS,kBAAkB,aAAa,EAAE,SAAS,OAAO,CAAC;AAE7D,QAAI,CAAC,SAAS,iBAAiB,SAAS,QAAQ,CAC9C,UAAS,kBAAkB,SAAS,EAAE,SAAS,OAAO,CAAC;;AAG3D,WAAQ,kBAAkB,QAAQ,QAAQ,OAAO;AACjD,WAAQ,gBACN,OAAO,QAAQ,yBAAS,IAAI,MAAM,4BAA4B,CAAC;IACjE;;CAGJ,MAAc,UACZ,WACA,KACyB;EACzB,MAAM,WAAW,MAAM,KAAK,aAAa;AACzC,MAAI;AACF,UAAO,MAAM,IAAI,SAAyB,SAAS,WAAW;IAE5D,MAAM,UADc,SAAS,YAAY,WAAW,WAAW,CACnC,YAAY,UAAU,CAAC,IAAI,IAAI;AAC3D,YAAQ,kBAAkB,QAAS,QAAQ,UAAkC,KAAK;AAClF,YAAQ,gBACN,OAAO,QAAQ,yBAAS,IAAI,MAAM,kBAAkB,UAAU,GAAG,IAAI,GAAG,CAAC;KAC3E;YACM;AACR,YAAS,OAAO;;;CAIpB,MAAc,UACZ,WACA,QACe;EACf,MAAM,WAAW,MAAM,KAAK,aAAa;AACzC,MAAI;AACF,SAAM,IAAI,SAAe,SAAS,WAAW;IAC3C,MAAM,cAAc,SAAS,YAAY,WAAW,YAAY;AAChE,gBAAY,mBAAmB,SAAS;AACxC,gBAAY,gBACV,OAAO,YAAY,yBAAS,IAAI,MAAM,mBAAmB,UAAU,GAAG,OAAO,IAAI,GAAG,CAAC;AACvF,gBAAY,YAAY,UAAU,CAAC,IAAI,OAAO;KAC9C;YACM;AACR,YAAS,OAAO;;;CAIpB,MAAc,aACZ,WACA,KACe;EACf,MAAM,WAAW,MAAM,KAAK,aAAa;AACzC,MAAI;AACF,SAAM,IAAI,SAAe,SAAS,WAAW;IAC3C,MAAM,cAAc,SAAS,YAAY,WAAW,YAAY;AAChE,gBAAY,mBAAmB,SAAS;AACxC,gBAAY,gBACV,OAAO,YAAY,yBAAS,IAAI,MAAM,oBAAoB,UAAU,GAAG,IAAI,GAAG,CAAC;AACjF,gBAAY,YAAY,UAAU,CAAC,OAAO,IAAI;KAC9C;YACM;AACR,YAAS,OAAO;;;CAIpB,MAAc,YACZ,WACoB;EACpB,MAAM,WAAW,MAAM,KAAK,aAAa;AACzC,MAAI;AACF,UAAO,MAAM,IAAI,SAAoB,SAAS,WAAW;IAEvD,MAAM,UADc,SAAS,YAAY,WAAW,WAAW,CACnC,YAAY,UAAU,CAAC,QAAQ;AAC3D,YAAQ,kBAAkB,QAAS,QAAQ,UAAoC,EAAE,CAAC;AAClF,YAAQ,gBACN,OAAO,QAAQ,yBAAS,IAAI,MAAM,+BAA+B,UAAU,GAAG,CAAC;KACjF;YACM;AACR,YAAS,OAAO;;;;AAKtB,SAAS,oBAAoB,WAAmB,IAAoB;AAClE,QAAO,GAAG,UAAU,GAAG;;AAGzB,SAAS,mBAAmB,OAAgC;AAC1D,QAAO,MAAM,OAAO,MAClB,MAAM,YACN,MAAM,aAAa,MAAM,WAC1B"}
1
+ {"version":3,"file":"indexeddb.js","names":[],"sources":["../src/indexeddb.ts"],"sourcesContent":["import type { SyncoreWebPersistence, StoredWebFile } from \"./persistence.js\";\n\n/** Options for constructing a {@link SyncoreIndexedDbPersistence}. */\nexport interface IndexedDbPersistenceOptions {\n /** IndexedDB database name. Defaults to `\"syncore-web\"`. */\n databaseName?: string;\n}\n\ntype StoredDatabaseRecord = {\n key: string;\n bytes: ArrayBuffer;\n updatedAt: number;\n};\n\ntype StoredFileRecord = {\n key: string;\n bytes: ArrayBuffer;\n contentType: string | null;\n size: number;\n updatedAt: number;\n};\n\n/**\n * IndexedDB-backed {@link SyncoreWebPersistence} implementation.\n *\n * Stores the SQLite database blob in IndexedDB. It still satisfies the lower\n * level persistence interface for compatibility, but Syncore's default browser\n * file storage is OPFS-only and will not use IndexedDB for blobs.\n *\n * Prefer `createWebPersistence()` over constructing this directly unless\n * you need to pass a specific IndexedDB database name.\n */\nexport class SyncoreIndexedDbPersistence implements SyncoreWebPersistence {\n readonly storageProtocol = \"idb\" as const;\n private readonly databaseName: string;\n\n constructor(options?: IndexedDbPersistenceOptions) {\n this.databaseName = options?.databaseName ?? \"syncore-web\";\n }\n\n async loadDatabase(key: string): Promise<Uint8Array | null> {\n const record = await this.getRecord<StoredDatabaseRecord>(\"databases\", key);\n if (!record) {\n return null;\n }\n return new Uint8Array(record.bytes);\n }\n\n async saveDatabase(key: string, bytes: Uint8Array): Promise<void> {\n await this.putRecord<StoredDatabaseRecord>(\"databases\", {\n key,\n bytes: sliceToArrayBuffer(bytes),\n updatedAt: Date.now()\n });\n }\n\n async getFile(\n namespace: string,\n id: string\n ): Promise<StoredWebFile | null> {\n const record = await this.getRecord<StoredFileRecord>(\n \"files\",\n createNamespacedKey(namespace, id)\n );\n if (!record) {\n return null;\n }\n return {\n id,\n bytes: new Uint8Array(record.bytes),\n contentType: record.contentType,\n size: record.size\n };\n }\n\n async putFile(\n namespace: string,\n id: string,\n bytes: Uint8Array,\n contentType: string | null\n ): Promise<void> {\n await this.putRecord<StoredFileRecord>(\"files\", {\n key: createNamespacedKey(namespace, id),\n bytes: sliceToArrayBuffer(bytes),\n contentType,\n size: bytes.byteLength,\n updatedAt: Date.now()\n });\n }\n\n async deleteFile(namespace: string, id: string): Promise<void> {\n await this.deleteRecord(\"files\", createNamespacedKey(namespace, id));\n }\n\n async listFiles(namespace: string): Promise<StoredWebFile[]> {\n const prefix = `${namespace}:`;\n const records = await this.listRecords<StoredFileRecord>(\"files\");\n return records\n .filter((record) => record.key.startsWith(prefix))\n .map((record) => ({\n id: record.key.slice(prefix.length),\n bytes: new Uint8Array(record.bytes),\n contentType: record.contentType,\n size: record.size\n }));\n }\n\n private async getDatabase(): Promise<IDBDatabase> {\n const indexedDb = (globalThis as { indexedDB?: IDBFactory }).indexedDB;\n if (!indexedDb) {\n throw new Error(\"IndexedDB is not available in this environment.\");\n }\n\n return new Promise((resolve, reject) => {\n const request = indexedDb.open(this.databaseName, 1);\n request.onupgradeneeded = () => {\n const database = request.result;\n if (!database.objectStoreNames.contains(\"databases\")) {\n database.createObjectStore(\"databases\", { keyPath: \"key\" });\n }\n if (!database.objectStoreNames.contains(\"files\")) {\n database.createObjectStore(\"files\", { keyPath: \"key\" });\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () =>\n reject(request.error ?? new Error(\"Failed to open IndexedDB.\"));\n });\n }\n\n private async getRecord<TRecord>(\n storeName: \"databases\" | \"files\",\n key: string\n ): Promise<TRecord | null> {\n const database = await this.getDatabase();\n try {\n return await new Promise<TRecord | null>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readonly\");\n const request = transaction.objectStore(storeName).get(key);\n request.onsuccess = () =>\n resolve((request.result as TRecord | undefined) ?? null);\n request.onerror = () =>\n reject(\n request.error ?? new Error(`Failed to read ${storeName}/${key}.`)\n );\n });\n } finally {\n database.close();\n }\n }\n\n private async putRecord<TRecord extends { key: string }>(\n storeName: \"databases\" | \"files\",\n record: TRecord\n ): Promise<void> {\n const database = await this.getDatabase();\n try {\n await new Promise<void>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readwrite\");\n transaction.oncomplete = () => resolve();\n transaction.onerror = () =>\n reject(\n transaction.error ??\n new Error(`Failed to write ${storeName}/${record.key}.`)\n );\n transaction.objectStore(storeName).put(record);\n });\n } finally {\n database.close();\n }\n }\n\n private async deleteRecord(\n storeName: \"databases\" | \"files\",\n key: string\n ): Promise<void> {\n const database = await this.getDatabase();\n try {\n await new Promise<void>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readwrite\");\n transaction.oncomplete = () => resolve();\n transaction.onerror = () =>\n reject(\n transaction.error ??\n new Error(`Failed to delete ${storeName}/${key}.`)\n );\n transaction.objectStore(storeName).delete(key);\n });\n } finally {\n database.close();\n }\n }\n\n private async listRecords<TRecord>(\n storeName: \"databases\" | \"files\"\n ): Promise<TRecord[]> {\n const database = await this.getDatabase();\n try {\n return await new Promise<TRecord[]>((resolve, reject) => {\n const transaction = database.transaction(storeName, \"readonly\");\n const request = transaction.objectStore(storeName).getAll();\n request.onsuccess = () =>\n resolve((request.result as TRecord[] | undefined) ?? []);\n request.onerror = () =>\n reject(\n request.error ??\n new Error(`Failed to list records from ${storeName}.`)\n );\n });\n } finally {\n database.close();\n }\n }\n}\n\nfunction createNamespacedKey(namespace: string, id: string): string {\n return `${namespace}:${id}`;\n}\n\nfunction sliceToArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n ) as ArrayBuffer;\n}\n"],"mappings":"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"}
@@ -1,9 +1,22 @@
1
- import { StoredWebFile, SyncoreWebPersistence } from "./persistence.js";
1
+ import { StoredWebFile, StoredWebFileMetadata, StoredWebFileRange, SyncoreWebPersistence } from "./persistence.js";
2
2
 
3
3
  //#region src/opfs.d.ts
4
+ /** Options for constructing a {@link SyncoreOpfsPersistence}. */
4
5
  interface OpfsPersistenceOptions {
6
+ /** Root directory name inside the Origin Private File System bucket. Defaults to `"syncore"`. */
5
7
  rootDirectoryName?: string;
6
8
  }
9
+ /**
10
+ * Origin Private File System (OPFS) backed {@link SyncoreWebPersistence}.
11
+ *
12
+ * Stores the SQLite database blob as a `.sqlite` file and binary file objects
13
+ * as individual OPFS entries under a configurable root directory. OPFS offers
14
+ * significantly better I/O throughput than IndexedDB and is the preferred
15
+ * persistence backend when available.
16
+ *
17
+ * Used automatically by `createWebPersistence()` in `"opfs"` or `"auto"` mode
18
+ * when `isOpfsAvailable()` returns `true`.
19
+ */
7
20
  declare class SyncoreOpfsPersistence implements SyncoreWebPersistence {
8
21
  private readonly options;
9
22
  readonly storageProtocol: "opfs";
@@ -12,9 +25,11 @@ declare class SyncoreOpfsPersistence implements SyncoreWebPersistence {
12
25
  loadDatabase(key: string): Promise<Uint8Array | null>;
13
26
  saveDatabase(key: string, bytes: Uint8Array): Promise<void>;
14
27
  getFile(namespace: string, id: string): Promise<StoredWebFile | null>;
28
+ getFileRange(namespace: string, id: string, offset: number, length: number): Promise<StoredWebFileRange | null>;
15
29
  putFile(namespace: string, id: string, bytes: Uint8Array, contentType: string | null): Promise<void>;
16
30
  deleteFile(namespace: string, id: string): Promise<void>;
17
31
  listFiles(namespace: string): Promise<StoredWebFile[]>;
32
+ listFileMetadata(namespace: string): Promise<StoredWebFileMetadata[]>;
18
33
  private ensureDirectory;
19
34
  private getOptionalDirectory;
20
35
  private getOptionalFileHandle;
@@ -1 +1 @@
1
- {"version":3,"file":"opfs.d.ts","names":[],"sources":["../src/opfs.ts"],"mappings":";;;UAEiB,sBAAA;EACf,iBAAA;AAAA;AAAA,cAWW,sBAAA,YAAkC,qBAAA;EAAA,iBAIhB,OAAA;EAAA,SAHpB,eAAA;EAAA,QACD,oBAAA;cAEqB,OAAA,GAAS,sBAAA;EAEhC,YAAA,CAAa,GAAA,WAAc,OAAA,CAAQ,UAAA;EAWnC,YAAA,CAAa,GAAA,UAAa,KAAA,EAAO,UAAA,GAAa,OAAA;EAU9C,OAAA,CAAQ,SAAA,UAAmB,EAAA,WAAa,OAAA,CAAQ,aAAA;EA0BhD,OAAA,CACJ,SAAA,UACA,EAAA,UACA,KAAA,EAAO,UAAA,EACP,WAAA,kBACC,OAAA;EAcG,UAAA,CAAW,SAAA,UAAmB,EAAA,WAAa,OAAA;EAW3C,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,aAAA;EAAA,QA4B9B,eAAA;EAAA,QAUA,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAWA,kCAAA;EAAA,QAcA,YAAA;EAAA,QAaA,gBAAA;AAAA"}
1
+ {"version":3,"file":"opfs.d.ts","names":[],"sources":["../src/opfs.ts"],"mappings":";;;;UAQiB,sBAAA;EAAA;EAEf,iBAAiB;AAAA;;AAAA;AAsBnB;;;;;;;;;cAAa,sBAAA,YAAkC,qBAAA;EAAA,iBAIhB,OAAA;EAAA,SAHpB,eAAA;EAAA,QACD,oBAAA;cAEqB,OAAA,GAAS,sBAAA;EAEhC,YAAA,CAAa,GAAA,WAAc,OAAA,CAAQ,UAAA;EAWnC,YAAA,CAAa,GAAA,UAAa,KAAA,EAAO,UAAA,GAAa,OAAA;EAU9C,OAAA,CAAQ,SAAA,UAAmB,EAAA,WAAa,OAAA,CAAQ,aAAA;EAgChD,YAAA,CACJ,SAAA,UACA,EAAA,UACA,MAAA,UACA,MAAA,WACC,OAAA,CAAQ,kBAAA;EAqCL,OAAA,CACJ,SAAA,UACA,EAAA,UACA,KAAA,EAAO,UAAA,EACP,WAAA,kBACC,OAAA;EAiBG,UAAA,CAAW,SAAA,UAAmB,EAAA,WAAa,OAAA;EAc3C,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,aAAA;EAUtC,gBAAA,CAAiB,SAAA,WAAoB,OAAA,CAAQ,qBAAA;EAAA,QAiCrC,eAAA;EAAA,QAUA,oBAAA;EAAA,QAiBA,qBAAA;EAAA,QAWA,kCAAA;EAAA,QAcA,YAAA;EAAA,QAgBA,gBAAA;AAAA"}
@@ -1,5 +1,17 @@
1
1
  //#region src/opfs.ts
2
+ /**
3
+ * Origin Private File System (OPFS) backed {@link SyncoreWebPersistence}.
4
+ *
5
+ * Stores the SQLite database blob as a `.sqlite` file and binary file objects
6
+ * as individual OPFS entries under a configurable root directory. OPFS offers
7
+ * significantly better I/O throughput than IndexedDB and is the preferred
8
+ * persistence backend when available.
9
+ *
10
+ * Used automatically by `createWebPersistence()` in `"opfs"` or `"auto"` mode
11
+ * when `isOpfsAvailable()` returns `true`.
12
+ */
2
13
  var SyncoreOpfsPersistence = class {
14
+ options;
3
15
  storageProtocol = "opfs";
4
16
  rootDirectoryPromise;
5
17
  constructor(options = {}) {
@@ -28,6 +40,24 @@ var SyncoreOpfsPersistence = class {
28
40
  contentType: metadata?.contentType ?? null
29
41
  };
30
42
  }
43
+ async getFileRange(namespace, id, offset, length) {
44
+ const directory = await this.getOptionalDirectory(["files", encodePathComponent(namespace)]);
45
+ if (!directory) return null;
46
+ const encodedId = encodePathComponent(id);
47
+ const fileHandle = await this.getOptionalFileHandleFromDirectory(directory, `${encodedId}.bin`);
48
+ if (!fileHandle) return null;
49
+ const [file, metadata] = await Promise.all([fileHandle.getFile(), this.readMetadata(directory, `${encodedId}.meta.json`)]);
50
+ const normalizedOffset = Math.max(offset, 0);
51
+ const normalizedLength = Math.max(length, 0);
52
+ const slice = file.slice(normalizedOffset, normalizedOffset + normalizedLength);
53
+ return {
54
+ id,
55
+ bytes: new Uint8Array(await slice.arrayBuffer()),
56
+ size: file.size,
57
+ contentType: metadata?.contentType ?? null,
58
+ offset: normalizedOffset
59
+ };
60
+ }
31
61
  async putFile(namespace, id, bytes, contentType) {
32
62
  const directory = await this.ensureDirectory(["files", encodePathComponent(namespace)]);
33
63
  const encodedId = encodePathComponent(id);
@@ -42,6 +72,15 @@ var SyncoreOpfsPersistence = class {
42
72
  await removeEntryIfExists(directory, `${encodedId}.meta.json`);
43
73
  }
44
74
  async listFiles(namespace) {
75
+ const metadata = await this.listFileMetadata(namespace);
76
+ return Promise.all(metadata.map(async (file) => {
77
+ return await this.getFile(namespace, file.id) ?? {
78
+ ...file,
79
+ bytes: new Uint8Array()
80
+ };
81
+ }));
82
+ }
83
+ async listFileMetadata(namespace) {
45
84
  const directory = await this.getOptionalDirectory(["files", encodePathComponent(namespace)]);
46
85
  if (!directory) return [];
47
86
  const files = [];
@@ -50,12 +89,11 @@ var SyncoreOpfsPersistence = class {
50
89
  if (handle.kind !== "file" || !name.endsWith(".bin")) continue;
51
90
  const encodedId = name.slice(0, -4);
52
91
  const id = decodeURIComponent(encodedId);
53
- const bytes = await readFileBytes(handle);
92
+ const file = await handle.getFile();
54
93
  const metadata = await this.readMetadata(directory, `${encodedId}.meta.json`);
55
94
  files.push({
56
95
  id,
57
- bytes,
58
- size: bytes.byteLength,
96
+ size: file.size,
59
97
  contentType: metadata?.contentType ?? null
60
98
  });
61
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"opfs.js","names":[],"sources":["../src/opfs.ts"],"sourcesContent":["import type { SyncoreWebPersistence, StoredWebFile } from \"./persistence.js\";\n\nexport interface OpfsPersistenceOptions {\n rootDirectoryName?: string;\n}\n\ntype StoredFileMetadata = {\n contentType: string | null;\n};\n\ntype OpfsStorageManager = StorageManager & {\n getDirectory?: () => Promise<FileSystemDirectoryHandle>;\n};\n\nexport class SyncoreOpfsPersistence implements SyncoreWebPersistence {\n readonly storageProtocol = \"opfs\" as const;\n private rootDirectoryPromise: Promise<FileSystemDirectoryHandle> | undefined;\n\n constructor(private readonly options: OpfsPersistenceOptions = {}) {}\n\n async loadDatabase(key: string): Promise<Uint8Array | null> {\n const handle = await this.getOptionalFileHandle(\n [\"databases\"],\n `${encodePathComponent(key)}.sqlite`\n );\n if (!handle) {\n return null;\n }\n return readFileBytes(handle);\n }\n\n async saveDatabase(key: string, bytes: Uint8Array): Promise<void> {\n const directory = await this.ensureDirectory([\"databases\"]);\n await writeBytes(\n await directory.getFileHandle(`${encodePathComponent(key)}.sqlite`, {\n create: true\n }),\n bytes\n );\n }\n\n async getFile(namespace: string, id: string): Promise<StoredWebFile | null> {\n const directory = await this.getOptionalDirectory([\"files\", encodePathComponent(namespace)]);\n if (!directory) {\n return null;\n }\n\n const fileName = `${encodePathComponent(id)}.bin`;\n const metadataName = `${encodePathComponent(id)}.meta.json`;\n const fileHandle = await this.getOptionalFileHandleFromDirectory(directory, fileName);\n if (!fileHandle) {\n return null;\n }\n\n const [bytes, metadata] = await Promise.all([\n readFileBytes(fileHandle),\n this.readMetadata(directory, metadataName)\n ]);\n\n return {\n id,\n bytes,\n size: bytes.byteLength,\n contentType: metadata?.contentType ?? null\n };\n }\n\n async putFile(\n namespace: string,\n id: string,\n bytes: Uint8Array,\n contentType: string | null\n ): Promise<void> {\n const directory = await this.ensureDirectory([\"files\", encodePathComponent(namespace)]);\n const encodedId = encodePathComponent(id);\n\n await writeBytes(\n await directory.getFileHandle(`${encodedId}.bin`, { create: true }),\n bytes\n );\n await writeText(\n await directory.getFileHandle(`${encodedId}.meta.json`, { create: true }),\n JSON.stringify({ contentType } satisfies StoredFileMetadata)\n );\n }\n\n async deleteFile(namespace: string, id: string): Promise<void> {\n const directory = await this.getOptionalDirectory([\"files\", encodePathComponent(namespace)]);\n if (!directory) {\n return;\n }\n\n const encodedId = encodePathComponent(id);\n await removeEntryIfExists(directory, `${encodedId}.bin`);\n await removeEntryIfExists(directory, `${encodedId}.meta.json`);\n }\n\n async listFiles(namespace: string): Promise<StoredWebFile[]> {\n const directory = await this.getOptionalDirectory([\"files\", encodePathComponent(namespace)]);\n if (!directory) {\n return [];\n }\n\n const files: StoredWebFile[] = [];\n const iterableDirectory = directory as FileSystemDirectoryHandle & {\n entries(): AsyncIterable<[string, FileSystemHandle]>;\n };\n for await (const [name, handle] of iterableDirectory.entries()) {\n if (handle.kind !== \"file\" || !name.endsWith(\".bin\")) {\n continue;\n }\n const encodedId = name.slice(0, -4);\n const id = decodeURIComponent(encodedId);\n const bytes = await readFileBytes(handle as FileSystemFileHandle);\n const metadata = await this.readMetadata(directory, `${encodedId}.meta.json`);\n files.push({\n id,\n bytes,\n size: bytes.byteLength,\n contentType: metadata?.contentType ?? null\n });\n }\n return files;\n }\n\n private async ensureDirectory(\n pathSegments: string[]\n ): Promise<FileSystemDirectoryHandle> {\n let directory = await this.getRootDirectory();\n for (const segment of pathSegments) {\n directory = await directory.getDirectoryHandle(segment, { create: true });\n }\n return directory;\n }\n\n private async getOptionalDirectory(\n pathSegments: string[]\n ): Promise<FileSystemDirectoryHandle | null> {\n try {\n let directory = await this.getRootDirectory();\n for (const segment of pathSegments) {\n directory = await directory.getDirectoryHandle(segment);\n }\n return directory;\n } catch (error) {\n if (isNotFoundError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n private async getOptionalFileHandle(\n pathSegments: string[],\n fileName: string\n ): Promise<FileSystemFileHandle | null> {\n const directory = await this.getOptionalDirectory(pathSegments);\n if (!directory) {\n return null;\n }\n return this.getOptionalFileHandleFromDirectory(directory, fileName);\n }\n\n private async getOptionalFileHandleFromDirectory(\n directory: FileSystemDirectoryHandle,\n fileName: string\n ): Promise<FileSystemFileHandle | null> {\n try {\n return await directory.getFileHandle(fileName);\n } catch (error) {\n if (isNotFoundError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n private async readMetadata(\n directory: FileSystemDirectoryHandle,\n fileName: string\n ): Promise<StoredFileMetadata | null> {\n const handle = await this.getOptionalFileHandleFromDirectory(directory, fileName);\n if (!handle) {\n return null;\n }\n\n const bytes = await readFileBytes(handle);\n return JSON.parse(new TextDecoder().decode(bytes)) as StoredFileMetadata;\n }\n\n private async getRootDirectory(): Promise<FileSystemDirectoryHandle> {\n if (!this.rootDirectoryPromise) {\n this.rootDirectoryPromise = (async () => {\n const storageManager = getOpfsStorageManager();\n if (!storageManager?.getDirectory) {\n throw new Error(\"OPFS is not available in this environment.\");\n }\n const root = await storageManager.getDirectory();\n return root.getDirectoryHandle(\n this.options.rootDirectoryName ?? \"syncore\",\n { create: true }\n );\n })();\n }\n return this.rootDirectoryPromise;\n }\n}\n\nasync function readFileBytes(handle: FileSystemFileHandle): Promise<Uint8Array> {\n const file = await handle.getFile();\n return new Uint8Array(await file.arrayBuffer());\n}\n\nasync function writeBytes(\n handle: FileSystemFileHandle,\n bytes: Uint8Array\n): Promise<void> {\n const writable = await handle.createWritable();\n try {\n await writable.write(sliceToArrayBuffer(bytes));\n await writable.truncate(bytes.byteLength);\n } finally {\n await writable.close();\n }\n}\n\nasync function writeText(\n handle: FileSystemFileHandle,\n value: string\n): Promise<void> {\n await writeBytes(handle, new TextEncoder().encode(value));\n}\n\nasync function removeEntryIfExists(\n directory: FileSystemDirectoryHandle,\n name: string\n): Promise<void> {\n try {\n await directory.removeEntry(name);\n } catch (error) {\n if (!isNotFoundError(error)) {\n throw error;\n }\n }\n}\n\nfunction encodePathComponent(value: string): string {\n return encodeURIComponent(value);\n}\n\nfunction sliceToArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n ) as ArrayBuffer;\n}\n\nfunction getOpfsStorageManager(): OpfsStorageManager | undefined {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n return navigator.storage as OpfsStorageManager | undefined;\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"NotFoundError\"\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"opfs.js","names":[],"sources":["../src/opfs.ts"],"sourcesContent":["import type {\n SyncoreWebPersistence,\n StoredWebFile,\n StoredWebFileMetadata,\n StoredWebFileRange\n} from \"./persistence.js\";\n\n/** Options for constructing a {@link SyncoreOpfsPersistence}. */\nexport interface OpfsPersistenceOptions {\n /** Root directory name inside the Origin Private File System bucket. Defaults to `\"syncore\"`. */\n rootDirectoryName?: string;\n}\n\ntype StoredFileMetadata = {\n contentType: string | null;\n};\n\ntype OpfsStorageManager = StorageManager & {\n getDirectory?: () => Promise<FileSystemDirectoryHandle>;\n};\n\n/**\n * Origin Private File System (OPFS) backed {@link SyncoreWebPersistence}.\n *\n * Stores the SQLite database blob as a `.sqlite` file and binary file objects\n * as individual OPFS entries under a configurable root directory. OPFS offers\n * significantly better I/O throughput than IndexedDB and is the preferred\n * persistence backend when available.\n *\n * Used automatically by `createWebPersistence()` in `\"opfs\"` or `\"auto\"` mode\n * when `isOpfsAvailable()` returns `true`.\n */\nexport class SyncoreOpfsPersistence implements SyncoreWebPersistence {\n readonly storageProtocol = \"opfs\" as const;\n private rootDirectoryPromise: Promise<FileSystemDirectoryHandle> | undefined;\n\n constructor(private readonly options: OpfsPersistenceOptions = {}) {}\n\n async loadDatabase(key: string): Promise<Uint8Array | null> {\n const handle = await this.getOptionalFileHandle(\n [\"databases\"],\n `${encodePathComponent(key)}.sqlite`\n );\n if (!handle) {\n return null;\n }\n return readFileBytes(handle);\n }\n\n async saveDatabase(key: string, bytes: Uint8Array): Promise<void> {\n const directory = await this.ensureDirectory([\"databases\"]);\n await writeBytes(\n await directory.getFileHandle(`${encodePathComponent(key)}.sqlite`, {\n create: true\n }),\n bytes\n );\n }\n\n async getFile(namespace: string, id: string): Promise<StoredWebFile | null> {\n const directory = await this.getOptionalDirectory([\n \"files\",\n encodePathComponent(namespace)\n ]);\n if (!directory) {\n return null;\n }\n\n const fileName = `${encodePathComponent(id)}.bin`;\n const metadataName = `${encodePathComponent(id)}.meta.json`;\n const fileHandle = await this.getOptionalFileHandleFromDirectory(\n directory,\n fileName\n );\n if (!fileHandle) {\n return null;\n }\n\n const [bytes, metadata] = await Promise.all([\n readFileBytes(fileHandle),\n this.readMetadata(directory, metadataName)\n ]);\n\n return {\n id,\n bytes,\n size: bytes.byteLength,\n contentType: metadata?.contentType ?? null\n };\n }\n\n async getFileRange(\n namespace: string,\n id: string,\n offset: number,\n length: number\n ): Promise<StoredWebFileRange | null> {\n const directory = await this.getOptionalDirectory([\n \"files\",\n encodePathComponent(namespace)\n ]);\n if (!directory) {\n return null;\n }\n\n const encodedId = encodePathComponent(id);\n const fileHandle = await this.getOptionalFileHandleFromDirectory(\n directory,\n `${encodedId}.bin`\n );\n if (!fileHandle) {\n return null;\n }\n\n const [file, metadata] = await Promise.all([\n fileHandle.getFile(),\n this.readMetadata(directory, `${encodedId}.meta.json`)\n ]);\n const normalizedOffset = Math.max(offset, 0);\n const normalizedLength = Math.max(length, 0);\n const slice = file.slice(\n normalizedOffset,\n normalizedOffset + normalizedLength\n );\n return {\n id,\n bytes: new Uint8Array(await slice.arrayBuffer()),\n size: file.size,\n contentType: metadata?.contentType ?? null,\n offset: normalizedOffset\n };\n }\n\n async putFile(\n namespace: string,\n id: string,\n bytes: Uint8Array,\n contentType: string | null\n ): Promise<void> {\n const directory = await this.ensureDirectory([\n \"files\",\n encodePathComponent(namespace)\n ]);\n const encodedId = encodePathComponent(id);\n\n await writeBytes(\n await directory.getFileHandle(`${encodedId}.bin`, { create: true }),\n bytes\n );\n await writeText(\n await directory.getFileHandle(`${encodedId}.meta.json`, { create: true }),\n JSON.stringify({ contentType } satisfies StoredFileMetadata)\n );\n }\n\n async deleteFile(namespace: string, id: string): Promise<void> {\n const directory = await this.getOptionalDirectory([\n \"files\",\n encodePathComponent(namespace)\n ]);\n if (!directory) {\n return;\n }\n\n const encodedId = encodePathComponent(id);\n await removeEntryIfExists(directory, `${encodedId}.bin`);\n await removeEntryIfExists(directory, `${encodedId}.meta.json`);\n }\n\n async listFiles(namespace: string): Promise<StoredWebFile[]> {\n const metadata = await this.listFileMetadata(namespace);\n return Promise.all(\n metadata.map(async (file) => {\n const fullFile = await this.getFile(namespace, file.id);\n return fullFile ?? { ...file, bytes: new Uint8Array() };\n })\n );\n }\n\n async listFileMetadata(namespace: string): Promise<StoredWebFileMetadata[]> {\n const directory = await this.getOptionalDirectory([\n \"files\",\n encodePathComponent(namespace)\n ]);\n if (!directory) {\n return [];\n }\n\n const files: StoredWebFileMetadata[] = [];\n const iterableDirectory = directory as FileSystemDirectoryHandle & {\n entries(): AsyncIterable<[string, FileSystemHandle]>;\n };\n for await (const [name, handle] of iterableDirectory.entries()) {\n if (handle.kind !== \"file\" || !name.endsWith(\".bin\")) {\n continue;\n }\n const encodedId = name.slice(0, -4);\n const id = decodeURIComponent(encodedId);\n const file = await (handle as FileSystemFileHandle).getFile();\n const metadata = await this.readMetadata(\n directory,\n `${encodedId}.meta.json`\n );\n files.push({\n id,\n size: file.size,\n contentType: metadata?.contentType ?? null\n });\n }\n return files;\n }\n\n private async ensureDirectory(\n pathSegments: string[]\n ): Promise<FileSystemDirectoryHandle> {\n let directory = await this.getRootDirectory();\n for (const segment of pathSegments) {\n directory = await directory.getDirectoryHandle(segment, { create: true });\n }\n return directory;\n }\n\n private async getOptionalDirectory(\n pathSegments: string[]\n ): Promise<FileSystemDirectoryHandle | null> {\n try {\n let directory = await this.getRootDirectory();\n for (const segment of pathSegments) {\n directory = await directory.getDirectoryHandle(segment);\n }\n return directory;\n } catch (error) {\n if (isNotFoundError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n private async getOptionalFileHandle(\n pathSegments: string[],\n fileName: string\n ): Promise<FileSystemFileHandle | null> {\n const directory = await this.getOptionalDirectory(pathSegments);\n if (!directory) {\n return null;\n }\n return this.getOptionalFileHandleFromDirectory(directory, fileName);\n }\n\n private async getOptionalFileHandleFromDirectory(\n directory: FileSystemDirectoryHandle,\n fileName: string\n ): Promise<FileSystemFileHandle | null> {\n try {\n return await directory.getFileHandle(fileName);\n } catch (error) {\n if (isNotFoundError(error)) {\n return null;\n }\n throw error;\n }\n }\n\n private async readMetadata(\n directory: FileSystemDirectoryHandle,\n fileName: string\n ): Promise<StoredFileMetadata | null> {\n const handle = await this.getOptionalFileHandleFromDirectory(\n directory,\n fileName\n );\n if (!handle) {\n return null;\n }\n\n const bytes = await readFileBytes(handle);\n return JSON.parse(new TextDecoder().decode(bytes)) as StoredFileMetadata;\n }\n\n private async getRootDirectory(): Promise<FileSystemDirectoryHandle> {\n if (!this.rootDirectoryPromise) {\n this.rootDirectoryPromise = (async () => {\n const storageManager = getOpfsStorageManager();\n if (!storageManager?.getDirectory) {\n throw new Error(\"OPFS is not available in this environment.\");\n }\n const root = await storageManager.getDirectory();\n return root.getDirectoryHandle(\n this.options.rootDirectoryName ?? \"syncore\",\n { create: true }\n );\n })();\n }\n return this.rootDirectoryPromise;\n }\n}\n\nasync function readFileBytes(\n handle: FileSystemFileHandle\n): Promise<Uint8Array> {\n const file = await handle.getFile();\n return new Uint8Array(await file.arrayBuffer());\n}\n\nasync function writeBytes(\n handle: FileSystemFileHandle,\n bytes: Uint8Array\n): Promise<void> {\n const writable = await handle.createWritable();\n try {\n await writable.write(sliceToArrayBuffer(bytes));\n await writable.truncate(bytes.byteLength);\n } finally {\n await writable.close();\n }\n}\n\nasync function writeText(\n handle: FileSystemFileHandle,\n value: string\n): Promise<void> {\n await writeBytes(handle, new TextEncoder().encode(value));\n}\n\nasync function removeEntryIfExists(\n directory: FileSystemDirectoryHandle,\n name: string\n): Promise<void> {\n try {\n await directory.removeEntry(name);\n } catch (error) {\n if (!isNotFoundError(error)) {\n throw error;\n }\n }\n}\n\nfunction encodePathComponent(value: string): string {\n return encodeURIComponent(value);\n}\n\nfunction sliceToArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n ) as ArrayBuffer;\n}\n\nfunction getOpfsStorageManager(): OpfsStorageManager | undefined {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n return navigator.storage as OpfsStorageManager | undefined;\n}\n\nfunction isNotFoundError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"NotFoundError\"\n );\n}\n"],"mappings":";;;;;;;;;;;;AAgCA,IAAa,yBAAb,MAAqE;CAItC;CAH7B,kBAA2B;CAC3B;CAEA,YAAY,UAAmD,CAAC,GAAG;EAAtC,KAAA,UAAA;CAAuC;CAEpE,MAAM,aAAa,KAAyC;EAC1D,MAAM,SAAS,MAAM,KAAK,sBACxB,CAAC,WAAW,GACZ,GAAG,oBAAoB,GAAG,EAAE,QAC9B;EACA,IAAI,CAAC,QACH,OAAO;EAET,OAAO,cAAc,MAAM;CAC7B;CAEA,MAAM,aAAa,KAAa,OAAkC;EAEhE,MAAM,WACJ,OAAM,MAFgB,KAAK,gBAAgB,CAAC,WAAW,CAAC,GAExC,cAAc,GAAG,oBAAoB,GAAG,EAAE,UAAU,EAClE,QAAQ,KACV,CAAC,GACD,KACF;CACF;CAEA,MAAM,QAAQ,WAAmB,IAA2C;EAC1E,MAAM,YAAY,MAAM,KAAK,qBAAqB,CAChD,SACA,oBAAoB,SAAS,CAC/B,CAAC;EACD,IAAI,CAAC,WACH,OAAO;EAGT,MAAM,WAAW,GAAG,oBAAoB,EAAE,EAAE;EAC5C,MAAM,eAAe,GAAG,oBAAoB,EAAE,EAAE;EAChD,MAAM,aAAa,MAAM,KAAK,mCAC5B,WACA,QACF;EACA,IAAI,CAAC,YACH,OAAO;EAGT,MAAM,CAAC,OAAO,YAAY,MAAM,QAAQ,IAAI,CAC1C,cAAc,UAAU,GACxB,KAAK,aAAa,WAAW,YAAY,CAC3C,CAAC;EAED,OAAO;GACL;GACA;GACA,MAAM,MAAM;GACZ,aAAa,UAAU,eAAe;EACxC;CACF;CAEA,MAAM,aACJ,WACA,IACA,QACA,QACoC;EACpC,MAAM,YAAY,MAAM,KAAK,qBAAqB,CAChD,SACA,oBAAoB,SAAS,CAC/B,CAAC;EACD,IAAI,CAAC,WACH,OAAO;EAGT,MAAM,YAAY,oBAAoB,EAAE;EACxC,MAAM,aAAa,MAAM,KAAK,mCAC5B,WACA,GAAG,UAAU,KACf;EACA,IAAI,CAAC,YACH,OAAO;EAGT,MAAM,CAAC,MAAM,YAAY,MAAM,QAAQ,IAAI,CACzC,WAAW,QAAQ,GACnB,KAAK,aAAa,WAAW,GAAG,UAAU,WAAW,CACvD,CAAC;EACD,MAAM,mBAAmB,KAAK,IAAI,QAAQ,CAAC;EAC3C,MAAM,mBAAmB,KAAK,IAAI,QAAQ,CAAC;EAC3C,MAAM,QAAQ,KAAK,MACjB,kBACA,mBAAmB,gBACrB;EACA,OAAO;GACL;GACA,OAAO,IAAI,WAAW,MAAM,MAAM,YAAY,CAAC;GAC/C,MAAM,KAAK;GACX,aAAa,UAAU,eAAe;GACtC,QAAQ;EACV;CACF;CAEA,MAAM,QACJ,WACA,IACA,OACA,aACe;EACf,MAAM,YAAY,MAAM,KAAK,gBAAgB,CAC3C,SACA,oBAAoB,SAAS,CAC/B,CAAC;EACD,MAAM,YAAY,oBAAoB,EAAE;EAExC,MAAM,WACJ,MAAM,UAAU,cAAc,GAAG,UAAU,OAAO,EAAE,QAAQ,KAAK,CAAC,GAClE,KACF;EACA,MAAM,UACJ,MAAM,UAAU,cAAc,GAAG,UAAU,aAAa,EAAE,QAAQ,KAAK,CAAC,GACxE,KAAK,UAAU,EAAE,YAAY,CAA8B,CAC7D;CACF;CAEA,MAAM,WAAW,WAAmB,IAA2B;EAC7D,MAAM,YAAY,MAAM,KAAK,qBAAqB,CAChD,SACA,oBAAoB,SAAS,CAC/B,CAAC;EACD,IAAI,CAAC,WACH;EAGF,MAAM,YAAY,oBAAoB,EAAE;EACxC,MAAM,oBAAoB,WAAW,GAAG,UAAU,KAAK;EACvD,MAAM,oBAAoB,WAAW,GAAG,UAAU,WAAW;CAC/D;CAEA,MAAM,UAAU,WAA6C;EAC3D,MAAM,WAAW,MAAM,KAAK,iBAAiB,SAAS;EACtD,OAAO,QAAQ,IACb,SAAS,IAAI,OAAO,SAAS;GAE3B,OAAO,MADgB,KAAK,QAAQ,WAAW,KAAK,EAAE,KACnC;IAAE,GAAG;IAAM,OAAO,IAAI,WAAW;GAAE;EACxD,CAAC,CACH;CACF;CAEA,MAAM,iBAAiB,WAAqD;EAC1E,MAAM,YAAY,MAAM,KAAK,qBAAqB,CAChD,SACA,oBAAoB,SAAS,CAC/B,CAAC;EACD,IAAI,CAAC,WACH,OAAO,CAAC;EAGV,MAAM,QAAiC,CAAC;EACxC,MAAM,oBAAoB;EAG1B,WAAW,MAAM,CAAC,MAAM,WAAW,kBAAkB,QAAQ,GAAG;GAC9D,IAAI,OAAO,SAAS,UAAU,CAAC,KAAK,SAAS,MAAM,GACjD;GAEF,MAAM,YAAY,KAAK,MAAM,GAAG,EAAE;GAClC,MAAM,KAAK,mBAAmB,SAAS;GACvC,MAAM,OAAO,MAAO,OAAgC,QAAQ;GAC5D,MAAM,WAAW,MAAM,KAAK,aAC1B,WACA,GAAG,UAAU,WACf;GACA,MAAM,KAAK;IACT;IACA,MAAM,KAAK;IACX,aAAa,UAAU,eAAe;GACxC,CAAC;EACH;EACA,OAAO;CACT;CAEA,MAAc,gBACZ,cACoC;EACpC,IAAI,YAAY,MAAM,KAAK,iBAAiB;EAC5C,KAAK,MAAM,WAAW,cACpB,YAAY,MAAM,UAAU,mBAAmB,SAAS,EAAE,QAAQ,KAAK,CAAC;EAE1E,OAAO;CACT;CAEA,MAAc,qBACZ,cAC2C;EAC3C,IAAI;GACF,IAAI,YAAY,MAAM,KAAK,iBAAiB;GAC5C,KAAK,MAAM,WAAW,cACpB,YAAY,MAAM,UAAU,mBAAmB,OAAO;GAExD,OAAO;EACT,SAAS,OAAO;GACd,IAAI,gBAAgB,KAAK,GACvB,OAAO;GAET,MAAM;EACR;CACF;CAEA,MAAc,sBACZ,cACA,UACsC;EACtC,MAAM,YAAY,MAAM,KAAK,qBAAqB,YAAY;EAC9D,IAAI,CAAC,WACH,OAAO;EAET,OAAO,KAAK,mCAAmC,WAAW,QAAQ;CACpE;CAEA,MAAc,mCACZ,WACA,UACsC;EACtC,IAAI;GACF,OAAO,MAAM,UAAU,cAAc,QAAQ;EAC/C,SAAS,OAAO;GACd,IAAI,gBAAgB,KAAK,GACvB,OAAO;GAET,MAAM;EACR;CACF;CAEA,MAAc,aACZ,WACA,UACoC;EACpC,MAAM,SAAS,MAAM,KAAK,mCACxB,WACA,QACF;EACA,IAAI,CAAC,QACH,OAAO;EAGT,MAAM,QAAQ,MAAM,cAAc,MAAM;EACxC,OAAO,KAAK,MAAM,IAAI,YAAY,EAAE,OAAO,KAAK,CAAC;CACnD;CAEA,MAAc,mBAAuD;EACnE,IAAI,CAAC,KAAK,sBACR,KAAK,wBAAwB,YAAY;GACvC,MAAM,iBAAiB,sBAAsB;GAC7C,IAAI,CAAC,gBAAgB,cACnB,MAAM,IAAI,MAAM,4CAA4C;GAG9D,QAAO,MADY,eAAe,aAAa,GACnC,mBACV,KAAK,QAAQ,qBAAqB,WAClC,EAAE,QAAQ,KAAK,CACjB;EACF,GAAG;EAEL,OAAO,KAAK;CACd;AACF;AAEA,eAAe,cACb,QACqB;CACrB,MAAM,OAAO,MAAM,OAAO,QAAQ;CAClC,OAAO,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC;AAChD;AAEA,eAAe,WACb,QACA,OACe;CACf,MAAM,WAAW,MAAM,OAAO,eAAe;CAC7C,IAAI;EACF,MAAM,SAAS,MAAM,mBAAmB,KAAK,CAAC;EAC9C,MAAM,SAAS,SAAS,MAAM,UAAU;CAC1C,UAAU;EACR,MAAM,SAAS,MAAM;CACvB;AACF;AAEA,eAAe,UACb,QACA,OACe;CACf,MAAM,WAAW,QAAQ,IAAI,YAAY,EAAE,OAAO,KAAK,CAAC;AAC1D;AAEA,eAAe,oBACb,WACA,MACe;CACf,IAAI;EACF,MAAM,UAAU,YAAY,IAAI;CAClC,SAAS,OAAO;EACd,IAAI,CAAC,gBAAgB,KAAK,GACxB,MAAM;CAEV;AACF;AAEA,SAAS,oBAAoB,OAAuB;CAClD,OAAO,mBAAmB,KAAK;AACjC;AAEA,SAAS,mBAAmB,OAAgC;CAC1D,OAAO,MAAM,OAAO,MAClB,MAAM,YACN,MAAM,aAAa,MAAM,UAC3B;AACF;AAEA,SAAS,wBAAwD;CAC/D,IAAI,OAAO,cAAc,aACvB;CAEF,OAAO,UAAU;AACnB;AAEA,SAAS,gBAAgB,OAAyB;CAChD,OACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,MAAM,SAAS;AAEnB"}