syncorejs 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) 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 +238 -64
  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/runtime/components.d.mts.map +1 -1
  23. package/dist/_vendor/core/runtime/components.mjs.map +1 -1
  24. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  25. package/dist/_vendor/core/runtime/devtools.mjs +130 -23
  26. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  27. package/dist/_vendor/core/runtime/functions.d.mts +388 -6
  28. package/dist/_vendor/core/runtime/functions.d.mts.map +1 -1
  29. package/dist/_vendor/core/runtime/functions.mjs +72 -1
  30. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  31. package/dist/_vendor/core/runtime/id.d.mts.map +1 -1
  32. package/dist/_vendor/core/runtime/id.mjs.map +1 -1
  33. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs +11 -5
  34. package/dist/_vendor/core/runtime/internal/engines/devtoolsEngine.mjs.map +1 -1
  35. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs +123 -20
  36. package/dist/_vendor/core/runtime/internal/engines/executionEngine.mjs.map +1 -1
  37. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs +56 -8
  38. package/dist/_vendor/core/runtime/internal/engines/reactivityEngine.mjs.map +1 -1
  39. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs +49 -14
  40. package/dist/_vendor/core/runtime/internal/engines/schedulerEngine.mjs.map +1 -1
  41. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs +4 -7
  42. package/dist/_vendor/core/runtime/internal/engines/schemaEngine.mjs.map +1 -1
  43. package/dist/_vendor/core/runtime/internal/engines/shared.mjs +76 -1
  44. package/dist/_vendor/core/runtime/internal/engines/shared.mjs.map +1 -1
  45. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs +1 -0
  46. package/dist/_vendor/core/runtime/internal/engines/storageEngine.mjs.map +1 -1
  47. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs +4 -3
  48. package/dist/_vendor/core/runtime/internal/runtimeKernel.mjs.map +1 -1
  49. package/dist/_vendor/core/runtime/internal/runtimeStatus.mjs.map +1 -1
  50. package/dist/_vendor/core/runtime/internal/systemMeta.mjs.map +1 -1
  51. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs +4 -0
  52. package/dist/_vendor/core/runtime/internal/transactionCoordinator.mjs.map +1 -1
  53. package/dist/_vendor/core/runtime/runtime.d.mts +1040 -9
  54. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  55. package/dist/_vendor/core/runtime/runtime.mjs +63 -0
  56. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  57. package/dist/_vendor/core/transport.d.mts +2 -0
  58. package/dist/_vendor/core/transport.d.mts.map +1 -1
  59. package/dist/_vendor/core/transport.mjs +33 -24
  60. package/dist/_vendor/core/transport.mjs.map +1 -1
  61. package/dist/_vendor/devtools-protocol/index.d.ts +149 -4
  62. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  63. package/dist/_vendor/devtools-protocol/index.js.map +1 -1
  64. package/dist/_vendor/next/config.d.ts +3 -4
  65. package/dist/_vendor/next/config.d.ts.map +1 -1
  66. package/dist/_vendor/next/config.js +37 -19
  67. package/dist/_vendor/next/config.js.map +1 -1
  68. package/dist/_vendor/next/index.d.ts +109 -29
  69. package/dist/_vendor/next/index.d.ts.map +1 -1
  70. package/dist/_vendor/next/index.js +77 -17
  71. package/dist/_vendor/next/index.js.map +1 -1
  72. package/dist/_vendor/platform-expo/index.d.ts +146 -27
  73. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  74. package/dist/_vendor/platform-expo/index.js +76 -10
  75. package/dist/_vendor/platform-expo/index.js.map +1 -1
  76. package/dist/_vendor/platform-expo/react.js.map +1 -1
  77. package/dist/_vendor/platform-expo/web-sqljs-wasm.js +16 -0
  78. package/dist/_vendor/platform-expo/web-sqljs-wasm.js.map +1 -0
  79. package/dist/_vendor/platform-node/index.d.mts +173 -9
  80. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  81. package/dist/_vendor/platform-node/index.mjs +225 -94
  82. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  83. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  84. package/dist/_vendor/platform-node/ipc.d.mts.map +1 -1
  85. package/dist/_vendor/platform-node/ipc.mjs.map +1 -1
  86. package/dist/_vendor/platform-web/external-change.d.ts +41 -0
  87. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -1
  88. package/dist/_vendor/platform-web/external-change.js +30 -0
  89. package/dist/_vendor/platform-web/external-change.js.map +1 -1
  90. package/dist/_vendor/platform-web/index.d.ts +307 -35
  91. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  92. package/dist/_vendor/platform-web/index.js +189 -23
  93. package/dist/_vendor/platform-web/index.js.map +1 -1
  94. package/dist/_vendor/platform-web/indexeddb.d.ts +12 -0
  95. package/dist/_vendor/platform-web/indexeddb.d.ts.map +1 -1
  96. package/dist/_vendor/platform-web/indexeddb.js +10 -0
  97. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  98. package/dist/_vendor/platform-web/opfs.d.ts +13 -0
  99. package/dist/_vendor/platform-web/opfs.d.ts.map +1 -1
  100. package/dist/_vendor/platform-web/opfs.js +12 -0
  101. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  102. package/dist/_vendor/platform-web/persistence.d.ts +54 -0
  103. package/dist/_vendor/platform-web/persistence.d.ts.map +1 -1
  104. package/dist/_vendor/platform-web/persistence.js +15 -0
  105. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  106. package/dist/_vendor/platform-web/react.d.ts +1 -2
  107. package/dist/_vendor/platform-web/react.d.ts.map +1 -1
  108. package/dist/_vendor/platform-web/react.js +2 -4
  109. package/dist/_vendor/platform-web/react.js.map +1 -1
  110. package/dist/_vendor/platform-web/sqljs.js +10 -1
  111. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  112. package/dist/_vendor/platform-web/web-sqljs-wasm.js +8 -0
  113. package/dist/_vendor/platform-web/web-sqljs-wasm.js.map +1 -0
  114. package/dist/_vendor/platform-web/worker.d.ts +60 -9
  115. package/dist/_vendor/platform-web/worker.d.ts.map +1 -1
  116. package/dist/_vendor/platform-web/worker.js +37 -4
  117. package/dist/_vendor/platform-web/worker.js.map +1 -1
  118. package/dist/_vendor/react/index.d.ts +196 -13
  119. package/dist/_vendor/react/index.d.ts.map +1 -1
  120. package/dist/_vendor/react/index.js +208 -17
  121. package/dist/_vendor/react/index.js.map +1 -1
  122. package/dist/_vendor/schema/definition.d.ts +129 -0
  123. package/dist/_vendor/schema/definition.d.ts.map +1 -1
  124. package/dist/_vendor/schema/definition.js +99 -0
  125. package/dist/_vendor/schema/definition.js.map +1 -1
  126. package/dist/_vendor/schema/planner.d.ts.map +1 -1
  127. package/dist/_vendor/schema/planner.js.map +1 -1
  128. package/dist/_vendor/schema/validators.d.ts +180 -4
  129. package/dist/_vendor/schema/validators.d.ts.map +1 -1
  130. package/dist/_vendor/schema/validators.js +35 -1
  131. package/dist/_vendor/schema/validators.js.map +1 -1
  132. package/dist/_vendor/svelte/index.d.ts +205 -7
  133. package/dist/_vendor/svelte/index.d.ts.map +1 -1
  134. package/dist/_vendor/svelte/index.js +199 -6
  135. package/dist/_vendor/svelte/index.js.map +1 -1
  136. package/dist/browser.d.ts.map +1 -1
  137. package/dist/cli.js +3 -1
  138. package/dist/cli.js.map +1 -1
  139. package/dist/index.d.ts +1 -1
  140. package/package.json +24 -21
@@ -1,4 +1,14 @@
1
1
  //#region src/indexeddb.ts
2
+ /**
3
+ * IndexedDB-backed {@link SyncoreWebPersistence} implementation.
4
+ *
5
+ * Stores the SQLite database blob and file objects in dedicated IndexedDB
6
+ * object stores. Used automatically when OPFS is unavailable or when the
7
+ * persistence mode is explicitly set to `"indexeddb"`.
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":"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"}
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 and file objects in dedicated IndexedDB\n * object stores. Used automatically when OPFS is unavailable or when the\n * persistence mode is explicitly set to `\"indexeddb\"`.\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
1
  import { StoredWebFile, 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";
@@ -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":";;;;UAGiB,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;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,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 = {}) {
@@ -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 { SyncoreWebPersistence, StoredWebFile } 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([\"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,26 +1,80 @@
1
1
  //#region src/persistence.d.ts
2
+ /**
3
+ * A binary file record stored in web persistence (OPFS or IndexedDB).
4
+ * Returned by `SyncoreWebPersistence.getFile` and `listFiles`.
5
+ */
2
6
  interface StoredWebFile {
7
+ /** Unique file identifier within its namespace. */
3
8
  id: string;
9
+ /** Raw file bytes. */
4
10
  bytes: Uint8Array;
11
+ /** MIME type, or `null` if none was recorded at write time. */
5
12
  contentType: string | null;
13
+ /** File size in bytes. */
6
14
  size: number;
7
15
  }
16
+ /**
17
+ * Abstraction over browser storage backends (OPFS or IndexedDB).
18
+ *
19
+ * Handles both the SQLite database blob and binary file objects. All
20
+ * implementations must persist data across page reloads.
21
+ *
22
+ * The concrete implementation is chosen by `createWebPersistence` based on
23
+ * browser capabilities and the requested `WebPersistenceMode`.
24
+ */
8
25
  interface SyncoreWebPersistence {
26
+ /** The storage protocol used: `"opfs"` (Origin Private File System) or `"idb"` (IndexedDB). */
9
27
  readonly storageProtocol: "idb" | "opfs";
28
+ /** Load the serialized SQLite database for `key`, or `null` if none has been saved yet. */
10
29
  loadDatabase(key: string): Promise<Uint8Array | null>;
30
+ /** Persist the serialized SQLite database bytes for `key`. */
11
31
  saveDatabase(key: string, bytes: Uint8Array): Promise<void>;
32
+ /** Retrieve a stored file from `namespace` by `id`, or `null` if not found. */
12
33
  getFile(namespace: string, id: string): Promise<StoredWebFile | null>;
34
+ /** Write a file into `namespace` under `id`, replacing any existing entry. */
13
35
  putFile(namespace: string, id: string, bytes: Uint8Array, contentType: string | null): Promise<void>;
36
+ /** Delete a file from `namespace` by `id`. No-op if the file does not exist. */
14
37
  deleteFile(namespace: string, id: string): Promise<void>;
38
+ /** List all stored files in `namespace`. */
15
39
  listFiles(namespace: string): Promise<StoredWebFile[]>;
16
40
  }
41
+ /**
42
+ * Which browser storage backend Syncore should use for SQLite persistence.
43
+ *
44
+ * - `"opfs"` — Origin Private File System. Fastest option; available in
45
+ * Chrome 102+, Safari 15.2+, and modern Firefox. **Required** for
46
+ * multi-tab coordination using `SharedArrayBuffer`.
47
+ * - `"indexeddb"` — Falls back to IndexedDB for browsers without OPFS.
48
+ * Slower due to serialization overhead but universally available.
49
+ * - `"auto"` *(default)* — Picks `"opfs"` when available, otherwise
50
+ * `"indexeddb"`.
51
+ */
17
52
  type WebPersistenceMode = "auto" | "indexeddb" | "opfs";
53
+ /** Options for {@link createWebPersistence}. */
18
54
  interface CreateWebPersistenceOptions {
55
+ /** Persistence backend to use. Defaults to `"auto"`. */
19
56
  mode?: WebPersistenceMode;
57
+ /** Custom IndexedDB database name. Defaults to the Syncore database name. */
20
58
  indexedDbDatabaseName?: string;
59
+ /** Root directory name inside the OPFS bucket. Defaults to the Syncore database name. */
21
60
  opfsRootDirectoryName?: string;
22
61
  }
62
+ /**
63
+ * Create the appropriate web persistence backend based on browser capabilities
64
+ * and the requested mode.
65
+ *
66
+ * Call this if you need a `SyncoreWebPersistence` instance outside of
67
+ * `createWebSyncoreRuntime` (e.g. in the Expo adapter). In a standard
68
+ * browser setup, `createWebSyncoreRuntime` calls this automatically.
69
+ */
23
70
  declare function createWebPersistence(options?: CreateWebPersistenceOptions): Promise<SyncoreWebPersistence>;
71
+ /**
72
+ * Return `true` if the Origin Private File System API is available in the
73
+ * current browser context.
74
+ *
75
+ * Used internally to decide whether to prefer OPFS over IndexedDB in `"auto"`
76
+ * mode. Also useful in application code for displaying conditional UI.
77
+ */
24
78
  declare function isOpfsAvailable(): boolean;
25
79
  //#endregion
26
80
  export { CreateWebPersistenceOptions, StoredWebFile, SyncoreWebPersistence, WebPersistenceMode, createWebPersistence, isOpfsAvailable };
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","names":[],"sources":["../src/persistence.ts"],"mappings":";UAGiB,aAAA;EACf,EAAA;EACA,KAAA,EAAO,UAAA;EACP,WAAA;EACA,IAAA;AAAA;AAAA,UAGe,qBAAA;EAAA,SACN,eAAA;EACT,YAAA,CAAa,GAAA,WAAc,OAAA,CAAQ,UAAA;EACnC,YAAA,CAAa,GAAA,UAAa,KAAA,EAAO,UAAA,GAAa,OAAA;EAC9C,OAAA,CAAQ,SAAA,UAAmB,EAAA,WAAa,OAAA,CAAQ,aAAA;EAChD,OAAA,CACE,SAAA,UACA,EAAA,UACA,KAAA,EAAO,UAAA,EACP,WAAA,kBACC,OAAA;EACH,UAAA,CAAW,SAAA,UAAmB,EAAA,WAAa,OAAA;EAC3C,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,aAAA;AAAA;AAAA,KAG5B,kBAAA;AAAA,UAEK,2BAAA;EACf,IAAA,GAAO,kBAAA;EACP,qBAAA;EACA,qBAAA;AAAA;AAAA,iBAGoB,oBAAA,CACpB,OAAA,GAAS,2BAAA,GACR,OAAA,CAAQ,qBAAA;AAAA,iBA6BK,eAAA,CAAA"}
1
+ {"version":3,"file":"persistence.d.ts","names":[],"sources":["../src/persistence.ts"],"mappings":";;AAOA;;;UAAiB,aAAA;EAEf;EAAA,EAAA;EAEO;EAAP,KAAA,EAAO,UAAU;EAIjB;EAFA,WAAA;EAEI;EAAJ,IAAA;AAAA;;;;;;;;;;UAYe,qBAAA;EAmBuB;EAAA,SAjB7B,eAAA;EAiB4B;EAfrC,YAAA,CAAa,GAAA,WAAc,OAAA,CAAQ,UAAA;EAF1B;EAIT,YAAA,CAAa,GAAA,UAAa,KAAA,EAAO,UAAA,GAAa,OAAA;EAFjC;EAIb,OAAA,CAAQ,SAAA,UAAmB,EAAA,WAAa,OAAA,CAAQ,aAAA;EAJb;EAMnC,OAAA,CACE,SAAA,UACA,EAAA,UACA,KAAA,EAAO,UAAA,EACP,WAAA,kBACC,OAAA;EATU;EAWb,UAAA,CAAW,SAAA,UAAmB,EAAA,WAAa,OAAA;EAXjB;EAa1B,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,aAAA;AAAA;;;;;;;;;;;;KAc5B,kBAAA;;UAGK,2BAAA;EAnB4B;EAqB3C,IAAA,GAAO,kBAAkB;EAnBf;EAqBV,qBAAA;EArBsC;EAuBtC,qBAAA;AAAA;AATF;;;;AAA8B;AAG9B;;;AAHA,iBAoBsB,oBAAA,CACpB,OAAA,GAAS,2BAAA,GACR,OAAA,CAAQ,qBAAA;;;;;;AAbY;AAWvB;iBAsCgB,eAAA,CAAA"}
@@ -1,6 +1,14 @@
1
1
  import { SyncoreIndexedDbPersistence } from "./indexeddb.js";
2
2
  import { SyncoreOpfsPersistence } from "./opfs.js";
3
3
  //#region src/persistence.ts
4
+ /**
5
+ * Create the appropriate web persistence backend based on browser capabilities
6
+ * and the requested mode.
7
+ *
8
+ * Call this if you need a `SyncoreWebPersistence` instance outside of
9
+ * `createWebSyncoreRuntime` (e.g. in the Expo adapter). In a standard
10
+ * browser setup, `createWebSyncoreRuntime` calls this automatically.
11
+ */
4
12
  async function createWebPersistence(options = {}) {
5
13
  const mode = options.mode ?? "auto";
6
14
  if (mode === "opfs") {
@@ -10,6 +18,13 @@ async function createWebPersistence(options = {}) {
10
18
  if (mode === "auto" && isOpfsAvailable()) return new SyncoreOpfsPersistence(options.opfsRootDirectoryName ? { rootDirectoryName: options.opfsRootDirectoryName } : void 0);
11
19
  return new SyncoreIndexedDbPersistence(options.indexedDbDatabaseName ? { databaseName: options.indexedDbDatabaseName } : void 0);
12
20
  }
21
+ /**
22
+ * Return `true` if the Origin Private File System API is available in the
23
+ * current browser context.
24
+ *
25
+ * Used internally to decide whether to prefer OPFS over IndexedDB in `"auto"`
26
+ * mode. Also useful in application code for displaying conditional UI.
27
+ */
13
28
  function isOpfsAvailable() {
14
29
  return Boolean(getOpfsStorageManager()?.getDirectory);
15
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.js","names":[],"sources":["../src/persistence.ts"],"sourcesContent":["import { SyncoreIndexedDbPersistence } from \"./indexeddb.js\";\nimport { SyncoreOpfsPersistence } from \"./opfs.js\";\n\nexport interface StoredWebFile {\n id: string;\n bytes: Uint8Array;\n contentType: string | null;\n size: number;\n}\n\nexport interface SyncoreWebPersistence {\n readonly storageProtocol: \"idb\" | \"opfs\";\n loadDatabase(key: string): Promise<Uint8Array | null>;\n saveDatabase(key: string, bytes: Uint8Array): Promise<void>;\n getFile(namespace: string, id: string): Promise<StoredWebFile | null>;\n putFile(\n namespace: string,\n id: string,\n bytes: Uint8Array,\n contentType: string | null\n ): Promise<void>;\n deleteFile(namespace: string, id: string): Promise<void>;\n listFiles(namespace: string): Promise<StoredWebFile[]>;\n}\n\nexport type WebPersistenceMode = \"auto\" | \"indexeddb\" | \"opfs\";\n\nexport interface CreateWebPersistenceOptions {\n mode?: WebPersistenceMode;\n indexedDbDatabaseName?: string;\n opfsRootDirectoryName?: string;\n}\n\nexport async function createWebPersistence(\n options: CreateWebPersistenceOptions = {}\n): Promise<SyncoreWebPersistence> {\n const mode = options.mode ?? \"auto\";\n\n if (mode === \"opfs\") {\n if (!isOpfsAvailable()) {\n throw new Error(\"OPFS is not available in this environment.\");\n }\n return new SyncoreOpfsPersistence(\n options.opfsRootDirectoryName\n ? { rootDirectoryName: options.opfsRootDirectoryName }\n : undefined\n );\n }\n\n if (mode === \"auto\" && isOpfsAvailable()) {\n return new SyncoreOpfsPersistence(\n options.opfsRootDirectoryName\n ? { rootDirectoryName: options.opfsRootDirectoryName }\n : undefined\n );\n }\n\n return new SyncoreIndexedDbPersistence(\n options.indexedDbDatabaseName\n ? { databaseName: options.indexedDbDatabaseName }\n : undefined\n );\n}\n\nexport function isOpfsAvailable(): boolean {\n return Boolean(getOpfsStorageManager()?.getDirectory);\n}\n\ntype OpfsStorageManager = StorageManager & {\n getDirectory?: () => Promise<FileSystemDirectoryHandle>;\n};\n\nfunction getOpfsStorageManager(): OpfsStorageManager | undefined {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n return navigator.storage as OpfsStorageManager | undefined;\n}\n"],"mappings":";;;AAiCA,eAAsB,qBACpB,UAAuC,EAAE,EACT;CAChC,MAAM,OAAO,QAAQ,QAAQ;AAE7B,KAAI,SAAS,QAAQ;AACnB,MAAI,CAAC,iBAAiB,CACpB,OAAM,IAAI,MAAM,6CAA6C;AAE/D,SAAO,IAAI,uBACT,QAAQ,wBACJ,EAAE,mBAAmB,QAAQ,uBAAuB,GACpD,KAAA,EACL;;AAGH,KAAI,SAAS,UAAU,iBAAiB,CACtC,QAAO,IAAI,uBACT,QAAQ,wBACJ,EAAE,mBAAmB,QAAQ,uBAAuB,GACpD,KAAA,EACL;AAGH,QAAO,IAAI,4BACT,QAAQ,wBACJ,EAAE,cAAc,QAAQ,uBAAuB,GAC/C,KAAA,EACL;;AAGH,SAAgB,kBAA2B;AACzC,QAAO,QAAQ,uBAAuB,EAAE,aAAa;;AAOvD,SAAS,wBAAwD;AAC/D,KAAI,OAAO,cAAc,YACvB;AAEF,QAAO,UAAU"}
1
+ {"version":3,"file":"persistence.js","names":[],"sources":["../src/persistence.ts"],"sourcesContent":["import { SyncoreIndexedDbPersistence } from \"./indexeddb.js\";\nimport { SyncoreOpfsPersistence } from \"./opfs.js\";\n\n/**\n * A binary file record stored in web persistence (OPFS or IndexedDB).\n * Returned by `SyncoreWebPersistence.getFile` and `listFiles`.\n */\nexport interface StoredWebFile {\n /** Unique file identifier within its namespace. */\n id: string;\n /** Raw file bytes. */\n bytes: Uint8Array;\n /** MIME type, or `null` if none was recorded at write time. */\n contentType: string | null;\n /** File size in bytes. */\n size: number;\n}\n\n/**\n * Abstraction over browser storage backends (OPFS or IndexedDB).\n *\n * Handles both the SQLite database blob and binary file objects. All\n * implementations must persist data across page reloads.\n *\n * The concrete implementation is chosen by `createWebPersistence` based on\n * browser capabilities and the requested `WebPersistenceMode`.\n */\nexport interface SyncoreWebPersistence {\n /** The storage protocol used: `\"opfs\"` (Origin Private File System) or `\"idb\"` (IndexedDB). */\n readonly storageProtocol: \"idb\" | \"opfs\";\n /** Load the serialized SQLite database for `key`, or `null` if none has been saved yet. */\n loadDatabase(key: string): Promise<Uint8Array | null>;\n /** Persist the serialized SQLite database bytes for `key`. */\n saveDatabase(key: string, bytes: Uint8Array): Promise<void>;\n /** Retrieve a stored file from `namespace` by `id`, or `null` if not found. */\n getFile(namespace: string, id: string): Promise<StoredWebFile | null>;\n /** Write a file into `namespace` under `id`, replacing any existing entry. */\n putFile(\n namespace: string,\n id: string,\n bytes: Uint8Array,\n contentType: string | null\n ): Promise<void>;\n /** Delete a file from `namespace` by `id`. No-op if the file does not exist. */\n deleteFile(namespace: string, id: string): Promise<void>;\n /** List all stored files in `namespace`. */\n listFiles(namespace: string): Promise<StoredWebFile[]>;\n}\n\n/**\n * Which browser storage backend Syncore should use for SQLite persistence.\n *\n * - `\"opfs\"` — Origin Private File System. Fastest option; available in\n * Chrome 102+, Safari 15.2+, and modern Firefox. **Required** for\n * multi-tab coordination using `SharedArrayBuffer`.\n * - `\"indexeddb\"` — Falls back to IndexedDB for browsers without OPFS.\n * Slower due to serialization overhead but universally available.\n * - `\"auto\"` *(default)* — Picks `\"opfs\"` when available, otherwise\n * `\"indexeddb\"`.\n */\nexport type WebPersistenceMode = \"auto\" | \"indexeddb\" | \"opfs\";\n\n/** Options for {@link createWebPersistence}. */\nexport interface CreateWebPersistenceOptions {\n /** Persistence backend to use. Defaults to `\"auto\"`. */\n mode?: WebPersistenceMode;\n /** Custom IndexedDB database name. Defaults to the Syncore database name. */\n indexedDbDatabaseName?: string;\n /** Root directory name inside the OPFS bucket. Defaults to the Syncore database name. */\n opfsRootDirectoryName?: string;\n}\n\n/**\n * Create the appropriate web persistence backend based on browser capabilities\n * and the requested mode.\n *\n * Call this if you need a `SyncoreWebPersistence` instance outside of\n * `createWebSyncoreRuntime` (e.g. in the Expo adapter). In a standard\n * browser setup, `createWebSyncoreRuntime` calls this automatically.\n */\nexport async function createWebPersistence(\n options: CreateWebPersistenceOptions = {}\n): Promise<SyncoreWebPersistence> {\n const mode = options.mode ?? \"auto\";\n\n if (mode === \"opfs\") {\n if (!isOpfsAvailable()) {\n throw new Error(\"OPFS is not available in this environment.\");\n }\n return new SyncoreOpfsPersistence(\n options.opfsRootDirectoryName\n ? { rootDirectoryName: options.opfsRootDirectoryName }\n : undefined\n );\n }\n\n if (mode === \"auto\" && isOpfsAvailable()) {\n return new SyncoreOpfsPersistence(\n options.opfsRootDirectoryName\n ? { rootDirectoryName: options.opfsRootDirectoryName }\n : undefined\n );\n }\n\n return new SyncoreIndexedDbPersistence(\n options.indexedDbDatabaseName\n ? { databaseName: options.indexedDbDatabaseName }\n : undefined\n );\n}\n\n/**\n * Return `true` if the Origin Private File System API is available in the\n * current browser context.\n *\n * Used internally to decide whether to prefer OPFS over IndexedDB in `\"auto\"`\n * mode. Also useful in application code for displaying conditional UI.\n */\nexport function isOpfsAvailable(): boolean {\n return Boolean(getOpfsStorageManager()?.getDirectory);\n}\n\ntype OpfsStorageManager = StorageManager & {\n getDirectory?: () => Promise<FileSystemDirectoryHandle>;\n};\n\nfunction getOpfsStorageManager(): OpfsStorageManager | undefined {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n return navigator.storage as OpfsStorageManager | undefined;\n}\n"],"mappings":";;;;;;;;;;;AAgFA,eAAsB,qBACpB,UAAuC,CAAC,GACR;CAChC,MAAM,OAAO,QAAQ,QAAQ;CAE7B,IAAI,SAAS,QAAQ;EACnB,IAAI,CAAC,gBAAgB,GACnB,MAAM,IAAI,MAAM,4CAA4C;EAE9D,OAAO,IAAI,uBACT,QAAQ,wBACJ,EAAE,mBAAmB,QAAQ,sBAAsB,IACnD,KAAA,CACN;CACF;CAEA,IAAI,SAAS,UAAU,gBAAgB,GACrC,OAAO,IAAI,uBACT,QAAQ,wBACJ,EAAE,mBAAmB,QAAQ,sBAAsB,IACnD,KAAA,CACN;CAGF,OAAO,IAAI,4BACT,QAAQ,wBACJ,EAAE,cAAc,QAAQ,sBAAsB,IAC9C,KAAA,CACN;AACF;;;;;;;;AASA,SAAgB,kBAA2B;CACzC,OAAO,QAAQ,sBAAsB,GAAG,YAAY;AACtD;AAMA,SAAS,wBAAwD;CAC/D,IAAI,OAAO,cAAc,aACvB;CAEF,OAAO,UAAU;AACnB"}
@@ -1,6 +1,5 @@
1
1
  import { CreateWebWorkerClientProviderOptions } from "./worker.js";
2
2
  import { ReactNode } from "react";
3
- import * as react_jsx_runtime0 from "react/jsx-runtime";
4
3
 
5
4
  //#region src/react.d.ts
6
5
  /**
@@ -29,7 +28,7 @@ declare function SyncoreWebProvider({
29
28
  /**
30
29
  * Start a worker-backed Syncore client and provide it to React descendants.
31
30
  */
32
- declare function SyncoreBrowserProvider(props: SyncoreBrowserProviderProps): react_jsx_runtime0.JSX.Element;
31
+ declare function SyncoreBrowserProvider(props: SyncoreBrowserProviderProps): import("react/jsx-runtime").JSX.Element;
33
32
  //#endregion
34
33
  export { SyncoreBrowserProvider, SyncoreBrowserProviderProps, SyncoreWebProvider, SyncoreWebProviderProps };
35
34
  //# sourceMappingURL=react.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","names":[],"sources":["../src/react.tsx"],"mappings":";;;;;;;;UAgBiB,uBAAA,SAAgC,oCAAA;EAAR;EAEvC,QAAA,EAAU,SAAA;EAAA;EAGV,QAAA,GAAW,SAAA;AAAA;;;;KAMD,2BAAA,GAA8B,uBAAA;;;;iBAK1B,kBAAA,CAAA;EACd,QAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA;AAAA,GACC,uBAAA,GAA0B,SAAA;;AAX7B;;iBAiEgB,sBAAA,CAAuB,KAAA,EAAO,2BAAA,GAA2B,kBAAA,CAAA,GAAA,CAAA,OAAA"}
1
+ {"version":3,"file":"react.d.ts","names":[],"sources":["../src/react.tsx"],"mappings":";;;;;;AAgBA;UAAiB,uBAAA,SAAgC,oCAAA;;EAE/C,QAAA,EAAU,SAAA;EAGC;EAAX,QAAA,GAAW,SAAA;AAAA;;;;KAMD,2BAAA,GAA8B,uBAAuB;;;;iBAKjD,kBAAA,CAAA;EACd,QAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA;AAAA,GACC,uBAAA,GAA0B,SAAA;AAX7B;;;AAAA,iBA2DgB,sBAAA,CAAuB,KAAA,EAAO,2BAA2B,+BAAA,GAAA,CAAA,OAAA"}
@@ -14,7 +14,6 @@ function SyncoreWebProvider({ children, workerUrl, workerType, workerName, fallb
14
14
  }), []);
15
15
  const [client, setClient] = useState(bootingClient);
16
16
  useEffect(() => {
17
- let disposed = false;
18
17
  let managedClient;
19
18
  setClient(bootingClient);
20
19
  try {
@@ -23,16 +22,15 @@ function SyncoreWebProvider({ children, workerUrl, workerType, workerName, fallb
23
22
  ...workerType ? { workerType } : {},
24
23
  ...workerName ? { workerName } : {}
25
24
  });
26
- if (!disposed) setClient(managedClient.client);
25
+ setClient(managedClient.client);
27
26
  } catch (error) {
28
- if (!disposed) setClient(createUnavailableSyncoreClient({
27
+ setClient(createUnavailableSyncoreClient({
29
28
  kind: "unavailable",
30
29
  reason: "worker-unavailable",
31
30
  ...error instanceof Error ? { error } : {}
32
31
  }));
33
32
  }
34
33
  return () => {
35
- disposed = true;
36
34
  managedClient?.dispose();
37
35
  };
38
36
  }, [
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import {\n createUnavailableSyncoreClient,\n type SyncoreClient\n} from \"@syncore/core\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { SyncoreProvider } from \"@syncore/react\";\nimport {\n createSyncoreWebWorkerClient,\n type CreateWebWorkerClientProviderOptions,\n type ManagedWebWorkerClient\n} from \"./worker.js\";\n\n/**\n * Props for {@link SyncoreWebProvider}.\n */\nexport interface SyncoreWebProviderProps extends CreateWebWorkerClientProviderOptions {\n /** The React subtree that should receive the Syncore client. */\n children: ReactNode;\n\n /** Optional fallback content rendered before the worker client is ready. */\n fallback?: ReactNode;\n}\n\n/**\n * Props for {@link SyncoreBrowserProvider}.\n */\nexport type SyncoreBrowserProviderProps = SyncoreWebProviderProps;\n\n/**\n * Start a worker-backed Syncore client and provide it to React descendants.\n */\nexport function SyncoreWebProvider({\n children,\n workerUrl,\n workerType,\n workerName,\n fallback = null\n}: SyncoreWebProviderProps): ReactNode {\n const bootingClient = useMemo(\n () =>\n createUnavailableSyncoreClient({\n kind: \"starting\",\n reason: \"booting\"\n }),\n []\n );\n const [client, setClient] = useState<SyncoreClient>(bootingClient);\n\n useEffect(() => {\n let disposed = false;\n let managedClient: ManagedWebWorkerClient | undefined;\n\n setClient(bootingClient);\n\n try {\n managedClient = createSyncoreWebWorkerClient({\n workerUrl,\n ...(workerType ? { workerType } : {}),\n ...(workerName ? { workerName } : {})\n });\n if (!disposed) {\n setClient(managedClient.client);\n }\n } catch (error) {\n if (!disposed) {\n setClient(\n createUnavailableSyncoreClient({\n kind: \"unavailable\",\n reason: \"worker-unavailable\",\n ...(error instanceof Error ? { error } : {})\n })\n );\n }\n }\n\n return () => {\n disposed = true;\n managedClient?.dispose();\n };\n }, [bootingClient, workerName, workerType, workerUrl]);\n\n return (\n <SyncoreProvider client={client}>\n {children ?? fallback}\n </SyncoreProvider>\n );\n}\n\n/**\n * Start a worker-backed Syncore client and provide it to React descendants.\n */\nexport function SyncoreBrowserProvider(props: SyncoreBrowserProviderProps) {\n return <SyncoreWebProvider {...props} />;\n}\n"],"mappings":";;;;;;;;;AAgCA,SAAgB,mBAAmB,EACjC,UACA,WACA,YACA,YACA,WAAW,QAC0B;CACrC,MAAM,gBAAgB,cAElB,+BAA+B;EAC7B,MAAM;EACN,QAAQ;EACT,CAAC,EACJ,EAAE,CACH;CACD,MAAM,CAAC,QAAQ,aAAa,SAAwB,cAAc;AAElE,iBAAgB;EACd,IAAI,WAAW;EACf,IAAI;AAEJ,YAAU,cAAc;AAExB,MAAI;AACF,mBAAgB,6BAA6B;IAC3C;IACA,GAAI,aAAa,EAAE,YAAY,GAAG,EAAE;IACpC,GAAI,aAAa,EAAE,YAAY,GAAG,EAAE;IACrC,CAAC;AACF,OAAI,CAAC,SACH,WAAU,cAAc,OAAO;WAE1B,OAAO;AACd,OAAI,CAAC,SACH,WACE,+BAA+B;IAC7B,MAAM;IACN,QAAQ;IACR,GAAI,iBAAiB,QAAQ,EAAE,OAAO,GAAG,EAAE;IAC5C,CAAC,CACH;;AAIL,eAAa;AACX,cAAW;AACX,kBAAe,SAAS;;IAEzB;EAAC;EAAe;EAAY;EAAY;EAAU,CAAC;AAEtD,QACE,oBAAC,iBAAD;EAAyB;YACtB,YAAY;EACG,CAAA;;;;;AAOtB,SAAgB,uBAAuB,OAAoC;AACzE,QAAO,oBAAC,oBAAD,EAAoB,GAAI,OAAS,CAAA"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/react.tsx"],"sourcesContent":["import {\n createUnavailableSyncoreClient,\n type SyncoreClient\n} from \"@syncore/core\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { SyncoreProvider } from \"@syncore/react\";\nimport {\n createSyncoreWebWorkerClient,\n type CreateWebWorkerClientProviderOptions,\n type ManagedWebWorkerClient\n} from \"./worker.js\";\n\n/**\n * Props for {@link SyncoreWebProvider}.\n */\nexport interface SyncoreWebProviderProps extends CreateWebWorkerClientProviderOptions {\n /** The React subtree that should receive the Syncore client. */\n children: ReactNode;\n\n /** Optional fallback content rendered before the worker client is ready. */\n fallback?: ReactNode;\n}\n\n/**\n * Props for {@link SyncoreBrowserProvider}.\n */\nexport type SyncoreBrowserProviderProps = SyncoreWebProviderProps;\n\n/**\n * Start a worker-backed Syncore client and provide it to React descendants.\n */\nexport function SyncoreWebProvider({\n children,\n workerUrl,\n workerType,\n workerName,\n fallback = null\n}: SyncoreWebProviderProps): ReactNode {\n const bootingClient = useMemo(\n () =>\n createUnavailableSyncoreClient({\n kind: \"starting\",\n reason: \"booting\"\n }),\n []\n );\n const [client, setClient] = useState<SyncoreClient>(bootingClient);\n\n useEffect(() => {\n let managedClient: ManagedWebWorkerClient | undefined;\n\n setClient(bootingClient);\n\n try {\n managedClient = createSyncoreWebWorkerClient({\n workerUrl,\n ...(workerType ? { workerType } : {}),\n ...(workerName ? { workerName } : {})\n });\n setClient(managedClient.client);\n } catch (error) {\n setClient(\n createUnavailableSyncoreClient({\n kind: \"unavailable\",\n reason: \"worker-unavailable\",\n ...(error instanceof Error ? { error } : {})\n })\n );\n }\n\n return () => {\n managedClient?.dispose();\n };\n }, [bootingClient, workerName, workerType, workerUrl]);\n\n return (\n <SyncoreProvider client={client}>\n {children ?? fallback}\n </SyncoreProvider>\n );\n}\n\n/**\n * Start a worker-backed Syncore client and provide it to React descendants.\n */\nexport function SyncoreBrowserProvider(props: SyncoreBrowserProviderProps) {\n return <SyncoreWebProvider {...props} />;\n}\n"],"mappings":";;;;;;;;;AAgCA,SAAgB,mBAAmB,EACjC,UACA,WACA,YACA,YACA,WAAW,QAC0B;CACrC,MAAM,gBAAgB,cAElB,+BAA+B;EAC7B,MAAM;EACN,QAAQ;CACV,CAAC,GACH,CAAC,CACH;CACA,MAAM,CAAC,QAAQ,aAAa,SAAwB,aAAa;CAEjE,gBAAgB;EACd,IAAI;EAEJ,UAAU,aAAa;EAEvB,IAAI;GACF,gBAAgB,6BAA6B;IAC3C;IACA,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;IACnC,GAAI,aAAa,EAAE,WAAW,IAAI,CAAC;GACrC,CAAC;GACD,UAAU,cAAc,MAAM;EAChC,SAAS,OAAO;GACd,UACE,+BAA+B;IAC7B,MAAM;IACN,QAAQ;IACR,GAAI,iBAAiB,QAAQ,EAAE,MAAM,IAAI,CAAC;GAC5C,CAAC,CACH;EACF;EAEA,aAAa;GACX,eAAe,QAAQ;EACzB;CACF,GAAG;EAAC;EAAe;EAAY;EAAY;CAAS,CAAC;CAErD,OACE,oBAAC,iBAAD;EAAyB;YACtB,YAAY;CACE,CAAA;AAErB;;;;AAKA,SAAgB,uBAAuB,OAAoC;CACzE,OAAO,oBAAC,oBAAD,EAAoB,GAAI,MAAQ,CAAA;AACzC"}
@@ -2,6 +2,10 @@ import { SyncoreIndexedDbPersistence } from "./indexeddb.js";
2
2
  import initSqlJs from "sql.js";
3
3
  //#region src/sqljs.ts
4
4
  var SqlJsDriver = class SqlJsDriver {
5
+ database;
6
+ persistence;
7
+ databaseName;
8
+ createDatabase;
5
9
  transactionDepth = 0;
6
10
  closed = false;
7
11
  constructor(database, persistence, databaseName, createDatabase) {
@@ -12,7 +16,9 @@ var SqlJsDriver = class SqlJsDriver {
12
16
  }
13
17
  static async create(options) {
14
18
  const persistence = options.persistence ?? new SyncoreIndexedDbPersistence();
15
- const SQL = await initSqlJs(typeof window === "undefined" && !options.locateFile && !options.wasmUrl ? void 0 : { locateFile: options.locateFile ?? (() => options.wasmUrl ?? "/sql-wasm.wasm") });
19
+ const hasExplicitWasmResolver = Boolean(options.locateFile ?? options.wasmUrl);
20
+ if (isBrowserLikeRuntime() && !hasExplicitWasmResolver) throw new Error("SqlJsDriver requires an explicit wasmUrl or locateFile in browser runtimes. Use createWebSyncoreRuntime/createBrowserWorkerRuntime for the default Syncore web resolver.");
21
+ const SQL = await initSqlJs(!hasExplicitWasmResolver ? void 0 : { locateFile: options.locateFile ?? (() => options.wasmUrl) });
16
22
  const existingBytes = await persistence.loadDatabase(options.databaseName);
17
23
  return new SqlJsDriver(existingBytes ? new SQL.Database(existingBytes) : new SQL.Database(), persistence, options.databaseName, (bytes) => bytes ? new SQL.Database(bytes) : new SQL.Database());
18
24
  }
@@ -130,6 +136,9 @@ var SqlJsDriver = class SqlJsDriver {
130
136
  previousDatabase.close();
131
137
  }
132
138
  };
139
+ function isBrowserLikeRuntime() {
140
+ return typeof window !== "undefined" || globalThis.WorkerGlobalScope !== void 0;
141
+ }
133
142
  function normalizeParams(values) {
134
143
  return values.map((value) => {
135
144
  if (typeof value === "boolean") return value ? 1 : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"sqljs.js","names":[],"sources":["../src/sqljs.ts"],"sourcesContent":["import initSqlJs from \"sql.js\";\nimport type { RunResult, SyncoreSqlDriver } from \"@syncore/core\";\nimport { SyncoreIndexedDbPersistence } from \"./indexeddb.js\";\nimport type { SyncoreWebPersistence } from \"./persistence.js\";\n\ntype SqlJsDatabase = initSqlJs.Database;\ntype SqlJsValue = initSqlJs.SqlValue;\n\nexport interface CreateSqlJsDriverOptions {\n databaseName: string;\n persistence?: SyncoreWebPersistence;\n wasmUrl?: string;\n locateFile?: (fileName: string) => string;\n}\n\nexport class SqlJsDriver implements SyncoreSqlDriver {\n private transactionDepth = 0;\n private closed = false;\n\n constructor(\n private database: SqlJsDatabase,\n private readonly persistence: SyncoreWebPersistence,\n private readonly databaseName: string,\n private readonly createDatabase: (bytes?: Uint8Array) => SqlJsDatabase\n ) {}\n\n static async create(options: CreateSqlJsDriverOptions): Promise<SqlJsDriver> {\n const persistence =\n options.persistence ?? new SyncoreIndexedDbPersistence();\n const SQL = await initSqlJs(\n typeof window === \"undefined\" && !options.locateFile && !options.wasmUrl\n ? undefined\n : {\n locateFile:\n options.locateFile ?? (() => options.wasmUrl ?? \"/sql-wasm.wasm\")\n }\n );\n const existingBytes = await persistence.loadDatabase(options.databaseName);\n const database = existingBytes\n ? new SQL.Database(existingBytes)\n : new SQL.Database();\n return new SqlJsDriver(\n database,\n persistence,\n options.databaseName,\n (bytes) => (bytes ? new SQL.Database(bytes) : new SQL.Database())\n );\n }\n\n async exec(sql: string): Promise<void> {\n this.ensureOpen();\n this.database.run(sql);\n await this.persistIfNeeded();\n }\n\n async run(sql: string, params: unknown[] = []): Promise<RunResult> {\n this.ensureOpen();\n const statement = this.database.prepare(sql);\n try {\n statement.run(normalizeParams(params));\n const lastInsertRowid = readScalarNumber(\n this.database,\n \"SELECT last_insert_rowid()\"\n );\n const result = {\n changes: this.database.getRowsModified(),\n ...(lastInsertRowid !== null ? { lastInsertRowid } : {})\n };\n await this.persistIfNeeded();\n return result;\n } finally {\n statement.free();\n }\n }\n\n async get<T>(sql: string, params: unknown[] = []): Promise<T | undefined> {\n this.ensureOpen();\n const statement = this.database.prepare(sql);\n try {\n statement.bind(normalizeParams(params));\n if (!statement.step()) {\n return undefined;\n }\n return statement.getAsObject() as T;\n } finally {\n statement.free();\n }\n }\n\n async all<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n this.ensureOpen();\n const statement = this.database.prepare(sql);\n try {\n statement.bind(normalizeParams(params));\n const rows: T[] = [];\n while (statement.step()) {\n rows.push(statement.getAsObject() as T);\n }\n return rows;\n } finally {\n statement.free();\n }\n }\n\n async withTransaction<T>(callback: () => Promise<T>): Promise<T> {\n this.ensureOpen();\n if (this.transactionDepth > 0) {\n return this.withSavepoint(`nested_${this.transactionDepth}`, callback);\n }\n\n this.transactionDepth += 1;\n this.database.run(\"BEGIN IMMEDIATE\");\n try {\n const result = await callback();\n this.database.run(\"COMMIT\");\n await this.persistNow();\n return result;\n } catch (error) {\n this.database.run(\"ROLLBACK\");\n throw error;\n } finally {\n this.transactionDepth -= 1;\n }\n }\n\n async withSavepoint<T>(name: string, callback: () => Promise<T>): Promise<T> {\n this.ensureOpen();\n const safeName = name.replaceAll(/[^a-zA-Z0-9_]/g, \"_\");\n this.database.run(`SAVEPOINT ${safeName}`);\n this.transactionDepth += 1;\n try {\n const result = await callback();\n this.database.run(`RELEASE SAVEPOINT ${safeName}`);\n return result;\n } catch (error) {\n this.database.run(`ROLLBACK TO SAVEPOINT ${safeName}`);\n this.database.run(`RELEASE SAVEPOINT ${safeName}`);\n throw error;\n } finally {\n this.transactionDepth -= 1;\n }\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n await this.persistNow();\n this.database.close();\n this.closed = true;\n }\n\n async reloadFromPersistence(): Promise<boolean> {\n this.ensureOpen();\n const bytes = await this.persistence.loadDatabase(this.databaseName);\n if (!bytes) {\n return false;\n }\n const nextDatabase = this.createDatabase(bytes);\n const previousDatabase = this.database;\n this.database = nextDatabase;\n previousDatabase.close();\n return true;\n }\n\n createDatabaseFromBytes(bytes?: Uint8Array): SqlJsDatabase {\n return this.createDatabase(bytes);\n }\n\n private async persistIfNeeded(): Promise<void> {\n if (this.transactionDepth === 0) {\n await this.persistNow();\n }\n }\n\n private async persistNow(): Promise<void> {\n this.ensureOpen();\n await this.persistence.saveDatabase(\n this.databaseName,\n this.database.export()\n );\n }\n\n private ensureOpen(): void {\n if (this.closed) {\n throw new Error(\"The sql.js driver is already closed.\");\n }\n }\n\n replaceDatabase(database: SqlJsDatabase): void {\n this.ensureOpen();\n const previousDatabase = this.database;\n this.database = database;\n previousDatabase.close();\n }\n}\n\nfunction normalizeParams(values: unknown[]): SqlJsValue[] {\n return values.map((value) => {\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n if (\n value === null ||\n typeof value === \"number\" ||\n typeof value === \"string\" ||\n value instanceof Uint8Array\n ) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n return JSON.stringify(value);\n });\n}\n\nfunction readScalarNumber(database: SqlJsDatabase, sql: string): number | null {\n const rows = database.exec(sql);\n const firstSet = rows[0];\n const firstRow = firstSet?.values[0];\n const firstValue = firstRow?.[0];\n if (typeof firstValue === \"number\") {\n return firstValue;\n }\n if (typeof firstValue === \"string\") {\n const parsed = Number(firstValue);\n return Number.isNaN(parsed) ? null : parsed;\n }\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sqljs.js","names":["scope"],"sources":["../src/sqljs.ts"],"sourcesContent":["import initSqlJs from \"sql.js\";\nimport type { RunResult, SyncoreSqlDriver } from \"@syncore/core\";\nimport { SyncoreIndexedDbPersistence } from \"./indexeddb.js\";\nimport type { SyncoreWebPersistence } from \"./persistence.js\";\n\ntype SqlJsDatabase = initSqlJs.Database;\ntype SqlJsValue = initSqlJs.SqlValue;\n\nexport interface CreateSqlJsDriverOptions {\n databaseName: string;\n persistence?: SyncoreWebPersistence;\n wasmUrl?: string;\n locateFile?: (fileName: string) => string;\n}\n\nexport class SqlJsDriver implements SyncoreSqlDriver {\n private transactionDepth = 0;\n private closed = false;\n\n constructor(\n private database: SqlJsDatabase,\n private readonly persistence: SyncoreWebPersistence,\n private readonly databaseName: string,\n private readonly createDatabase: (bytes?: Uint8Array) => SqlJsDatabase\n ) {}\n\n static async create(options: CreateSqlJsDriverOptions): Promise<SqlJsDriver> {\n const persistence =\n options.persistence ?? new SyncoreIndexedDbPersistence();\n const hasExplicitWasmResolver = Boolean(options.locateFile ?? options.wasmUrl);\n if (isBrowserLikeRuntime() && !hasExplicitWasmResolver) {\n throw new Error(\n \"SqlJsDriver requires an explicit wasmUrl or locateFile in browser runtimes. \" +\n \"Use createWebSyncoreRuntime/createBrowserWorkerRuntime for the default Syncore web resolver.\"\n );\n }\n const SQL = await initSqlJs(\n !hasExplicitWasmResolver\n ? undefined\n : {\n locateFile:\n options.locateFile ?? (() => options.wasmUrl as string)\n }\n );\n const existingBytes = await persistence.loadDatabase(options.databaseName);\n const database = existingBytes\n ? new SQL.Database(existingBytes)\n : new SQL.Database();\n return new SqlJsDriver(\n database,\n persistence,\n options.databaseName,\n (bytes) => (bytes ? new SQL.Database(bytes) : new SQL.Database())\n );\n }\n\n async exec(sql: string): Promise<void> {\n this.ensureOpen();\n this.database.run(sql);\n await this.persistIfNeeded();\n }\n\n async run(sql: string, params: unknown[] = []): Promise<RunResult> {\n this.ensureOpen();\n const statement = this.database.prepare(sql);\n try {\n statement.run(normalizeParams(params));\n const lastInsertRowid = readScalarNumber(\n this.database,\n \"SELECT last_insert_rowid()\"\n );\n const result = {\n changes: this.database.getRowsModified(),\n ...(lastInsertRowid !== null ? { lastInsertRowid } : {})\n };\n await this.persistIfNeeded();\n return result;\n } finally {\n statement.free();\n }\n }\n\n async get<T>(sql: string, params: unknown[] = []): Promise<T | undefined> {\n this.ensureOpen();\n const statement = this.database.prepare(sql);\n try {\n statement.bind(normalizeParams(params));\n if (!statement.step()) {\n return undefined;\n }\n return statement.getAsObject() as T;\n } finally {\n statement.free();\n }\n }\n\n async all<T>(sql: string, params: unknown[] = []): Promise<T[]> {\n this.ensureOpen();\n const statement = this.database.prepare(sql);\n try {\n statement.bind(normalizeParams(params));\n const rows: T[] = [];\n while (statement.step()) {\n rows.push(statement.getAsObject() as T);\n }\n return rows;\n } finally {\n statement.free();\n }\n }\n\n async withTransaction<T>(callback: () => Promise<T>): Promise<T> {\n this.ensureOpen();\n if (this.transactionDepth > 0) {\n return this.withSavepoint(`nested_${this.transactionDepth}`, callback);\n }\n\n this.transactionDepth += 1;\n this.database.run(\"BEGIN IMMEDIATE\");\n try {\n const result = await callback();\n this.database.run(\"COMMIT\");\n await this.persistNow();\n return result;\n } catch (error) {\n this.database.run(\"ROLLBACK\");\n throw error;\n } finally {\n this.transactionDepth -= 1;\n }\n }\n\n async withSavepoint<T>(name: string, callback: () => Promise<T>): Promise<T> {\n this.ensureOpen();\n const safeName = name.replaceAll(/[^a-zA-Z0-9_]/g, \"_\");\n this.database.run(`SAVEPOINT ${safeName}`);\n this.transactionDepth += 1;\n try {\n const result = await callback();\n this.database.run(`RELEASE SAVEPOINT ${safeName}`);\n return result;\n } catch (error) {\n this.database.run(`ROLLBACK TO SAVEPOINT ${safeName}`);\n this.database.run(`RELEASE SAVEPOINT ${safeName}`);\n throw error;\n } finally {\n this.transactionDepth -= 1;\n }\n }\n\n async close(): Promise<void> {\n if (this.closed) {\n return;\n }\n await this.persistNow();\n this.database.close();\n this.closed = true;\n }\n\n async reloadFromPersistence(): Promise<boolean> {\n this.ensureOpen();\n const bytes = await this.persistence.loadDatabase(this.databaseName);\n if (!bytes) {\n return false;\n }\n const nextDatabase = this.createDatabase(bytes);\n const previousDatabase = this.database;\n this.database = nextDatabase;\n previousDatabase.close();\n return true;\n }\n\n createDatabaseFromBytes(bytes?: Uint8Array): SqlJsDatabase {\n return this.createDatabase(bytes);\n }\n\n private async persistIfNeeded(): Promise<void> {\n if (this.transactionDepth === 0) {\n await this.persistNow();\n }\n }\n\n private async persistNow(): Promise<void> {\n this.ensureOpen();\n await this.persistence.saveDatabase(\n this.databaseName,\n this.database.export()\n );\n }\n\n private ensureOpen(): void {\n if (this.closed) {\n throw new Error(\"The sql.js driver is already closed.\");\n }\n }\n\n replaceDatabase(database: SqlJsDatabase): void {\n this.ensureOpen();\n const previousDatabase = this.database;\n this.database = database;\n previousDatabase.close();\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\nfunction normalizeParams(values: unknown[]): SqlJsValue[] {\n return values.map((value) => {\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n if (\n value === null ||\n typeof value === \"number\" ||\n typeof value === \"string\" ||\n value instanceof Uint8Array\n ) {\n return value;\n }\n if (value instanceof ArrayBuffer) {\n return new Uint8Array(value);\n }\n return JSON.stringify(value);\n });\n}\n\nfunction readScalarNumber(database: SqlJsDatabase, sql: string): number | null {\n const rows = database.exec(sql);\n const firstSet = rows[0];\n const firstRow = firstSet?.values[0];\n const firstValue = firstRow?.[0];\n if (typeof firstValue === \"number\") {\n return firstValue;\n }\n if (typeof firstValue === \"string\") {\n const parsed = Number(firstValue);\n return Number.isNaN(parsed) ? null : parsed;\n }\n return null;\n}\n"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ //#region src/web-sqljs-wasm.ts
2
+ function resolveDefaultWebSqlJsWasmUrl() {
3
+ return new URL("sql.js/dist/sql-wasm.wasm", import.meta.url).toString();
4
+ }
5
+ //#endregion
6
+ export { resolveDefaultWebSqlJsWasmUrl };
7
+
8
+ //# sourceMappingURL=web-sqljs-wasm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-sqljs-wasm.js","names":[],"sources":["../src/web-sqljs-wasm.ts"],"sourcesContent":["export function resolveDefaultWebSqlJsWasmUrl(): string {\n return new URL(\"sql.js/dist/sql-wasm.wasm\", import.meta.url).toString();\n}\n"],"mappings":";AAAA,SAAgB,gCAAwC;CACtD,OAAO,IAAI,IAAI,6BAA6B,OAAO,KAAK,GAAG,EAAE,SAAS;AACxE"}
@@ -1,52 +1,103 @@
1
1
  import { AttachRuntimeBridgeOptions, AttachedRuntimeBridge, BridgeQueryWatch, SyncoreBridgeClient, SyncoreBridgeMessageEndpoint, SyncoreDataModel } from "../core/index.d.mts";
2
2
 
3
3
  //#region src/worker.d.ts
4
+ /**
5
+ * Schema type constraint for worker-side Syncore runtimes.
6
+ *
7
+ * Pass any schema produced by `defineSchema()` where this type is expected.
8
+ * Defaults to the unconstrained `SyncoreDataModel` when omitted.
9
+ */
4
10
  type WebWorkerSyncoreSchema<TSchema extends SyncoreDataModel = SyncoreDataModel> = TSchema;
11
+ /** Message endpoint shape required by the browser worker bridge (alias of `SyncoreBridgeMessageEndpoint`). */
5
12
  type SyncoreWorkerMessageEndpoint = SyncoreBridgeMessageEndpoint;
13
+ /** Live-query subscription handle returned by `SyncoreWebWorkerClient.watchQuery`. */
6
14
  type WorkerQueryWatch<TValue> = BridgeQueryWatch<TValue>;
15
+ /**
16
+ * Syncore client that communicates with a runtime running in a browser Worker
17
+ * over the `postMessage` bridge.
18
+ *
19
+ * Use `createSyncoreWebWorkerClient()` or `createManagedWebWorkerClient()` to
20
+ * create instances. Prefer the React hooks (`useQuery`, `useMutation`, etc.)
21
+ * over calling this directly in React apps.
22
+ */
7
23
  declare class SyncoreWebWorkerClient extends SyncoreBridgeClient {
8
24
  query: SyncoreBridgeClient["query"];
9
25
  mutation: SyncoreBridgeClient["mutation"];
10
26
  action: SyncoreBridgeClient["action"];
11
27
  watchQuery: SyncoreBridgeClient["watchQuery"];
12
28
  }
29
+ /** Options for attaching a runtime to a worker bridge endpoint. Alias of `AttachRuntimeBridgeOptions`. */
13
30
  type AttachWebWorkerRuntimeOptions<TSchema extends WebWorkerSyncoreSchema = WebWorkerSyncoreSchema> = AttachRuntimeBridgeOptions<TSchema>;
31
+ /** Handle returned by `attachWebWorkerRuntime` for controlling the attached bridge. */
14
32
  type AttachedWebWorkerRuntime = AttachedRuntimeBridge;
15
33
  /**
16
- * A worker-backed browser client plus the Worker instance it owns.
34
+ * A browser Worker and its associated Syncore client, bundled for easy
35
+ * lifecycle management.
36
+ *
37
+ * Returned by `createSyncoreWebWorkerClient` and `createManagedWebWorkerClient`.
38
+ * Call `dispose()` to terminate the worker and release its resources.
17
39
  */
18
40
  interface ManagedWebWorkerClient {
41
+ /** The Syncore client connected to the worker. */
19
42
  client: SyncoreWebWorkerClient;
43
+ /** The underlying `Worker` instance. Useful for low-level control. */
20
44
  worker: Worker;
45
+ /** Terminate the worker and dispose the client. Call on app unmount or navigation. */
21
46
  dispose(): void;
22
47
  }
23
48
  /**
24
- * Options for creating a worker-backed Syncore client in the browser.
49
+ * Options for creating a managed worker Syncore client via
50
+ * `createSyncoreWebWorkerClient`.
25
51
  */
26
52
  interface CreateWebWorkerClientProviderOptions {
27
- /** The worker module URL passed to `new Worker(...)`. */
53
+ /** The worker module URL passed to `new Worker(...)`. Typically an `import.meta.url`-relative `URL`. */
28
54
  workerUrl: URL | string;
29
- /** Optional worker type, defaults to `module`. */
55
+ /** Worker module type. Defaults to `"module"` (ESM worker). */
30
56
  workerType?: WorkerOptions["type"];
31
- /** Optional name shown in browser devtools. */
57
+ /** Optional label shown in browser devtools’ Sources panel. */
32
58
  workerName?: string;
33
59
  }
34
60
  /**
35
- * Create a web worker Syncore client from a low-level message endpoint.
61
+ * Create a {@link SyncoreWebWorkerClient} from a low-level message endpoint.
62
+ *
63
+ * Use this when you already have a `Worker` or `MessagePort` reference and
64
+ * want to wrap it manually. For the common case of spawning a new Worker from
65
+ * a URL, use `createSyncoreWebWorkerClient` instead.
36
66
  */
37
67
  declare function createWebWorkerClient(endpoint: SyncoreWorkerMessageEndpoint): SyncoreWebWorkerClient;
38
68
  /**
39
- * Create and manage both a browser Worker and the Syncore client that talks to it.
69
+ * Create a {@link ManagedWebWorkerClient} using a provided Worker factory.
70
+ *
71
+ * Useful when you need control over how the Worker is constructed (e.g. to
72
+ * pass constructor options not exposed by `CreateWebWorkerClientProviderOptions`).
73
+ * For the common URL-based case, use `createSyncoreWebWorkerClient`.
40
74
  */
41
75
  declare function createManagedWebWorkerClient(options: {
42
76
  createWorker: () => Worker;
43
77
  }): ManagedWebWorkerClient;
44
78
  /**
45
- * Create a worker-backed Syncore client using the standard Worker constructor.
79
+ * Create a {@link ManagedWebWorkerClient} by spawning a new Worker from a URL.
80
+ *
81
+ * This is the standard way to create a main-thread client in a browser app.
82
+ * Pass the URL of your `syncore.worker.ts` file (which calls
83
+ * `createWebWorkerRuntime`) and connect the returned `client` to your React
84
+ * `SyncoreProvider` or Svelte context.
85
+ *
86
+ * ```ts
87
+ * // main.ts (or React root)
88
+ * import { createSyncoreWebWorkerClient } from "syncorejs/browser";
89
+ *
90
+ * const { client, dispose } = createSyncoreWebWorkerClient({
91
+ * workerUrl: new URL("./syncore.worker.ts", import.meta.url),
92
+ * });
93
+ * ```
46
94
  */
47
95
  declare function createSyncoreWebWorkerClient(options: CreateWebWorkerClientProviderOptions): ManagedWebWorkerClient;
48
96
  /**
49
- * Attach a Syncore runtime implementation to a worker message endpoint.
97
+ * Wire a Syncore runtime factory to a worker message endpoint.
98
+ *
99
+ * Called internally by `createWebWorkerRuntime`. Exposed for cases where you
100
+ * need to attach a runtime to a custom bridge endpoint (e.g. a `MessagePort`).
50
101
  */
51
102
  declare function attachWebWorkerRuntime(options: AttachWebWorkerRuntimeOptions): AttachedWebWorkerRuntime;
52
103
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","names":[],"sources":["../src/worker.ts"],"mappings":";;;KAUY,sBAAA,iBACM,gBAAA,GAAmB,gBAAA,IACjC,OAAA;AAAA,KACQ,4BAAA,GAA+B,4BAAA;AAAA,KAC/B,gBAAA,WAA2B,gBAAA,CAAiB,MAAA;AAAA,cAE3C,sBAAA,SAA+B,mBAAA;EAClC,KAAA,EAAO,mBAAA;EACP,QAAA,EAAU,mBAAA;EACV,MAAA,EAAQ,mBAAA;EACR,UAAA,EAAY,mBAAA;AAAA;AAAA,KAGV,6BAAA,iBACM,sBAAA,GAAyB,sBAAA,IACvC,0BAAA,CAA2B,OAAA;AAAA,KACnB,wBAAA,GAA2B,qBAAA;;;;UAKtB,sBAAA;EACf,MAAA,EAAQ,sBAAA;EACR,MAAA,EAAQ,MAAA;EACR,OAAA;AAAA;;;AApBF;UA0BiB,oCAAA;EA1BW;EA4B1B,SAAA,EAAW,GAAA;EA5BgB;EA+B3B,UAAA,GAAa,aAAA;EA/ByC;EAkCtD,UAAA;AAAA;AAhCF;;;AAAA,iBAsCgB,qBAAA,CACd,QAAA,EAAU,4BAAA,GACT,sBAAA;;;;iBAOa,4BAAA,CAA6B,OAAA;EAC3C,YAAA,QAAoB,MAAA;AAAA,IAClB,sBAAA;;;;iBAgBY,4BAAA,CACd,OAAA,EAAS,oCAAA,GACR,sBAAA;;;;iBAaa,sBAAA,CACd,OAAA,EAAS,6BAAA,GACR,wBAAA"}
1
+ {"version":3,"file":"worker.d.ts","names":[],"sources":["../src/worker.ts"],"mappings":";;;;;AAgBA;;;;KAAY,sBAAA,iBACM,gBAAA,GAAmB,gBAAA,IACjC,OAAA;;KAEQ,4BAAA,GAA+B,4BAA4B;;KAE3D,gBAAA,WAA2B,gBAAgB,CAAC,MAAA;;;;;AAJ7C;AAEX;;;cAYa,sBAAA,SAA+B,mBAAA;EAClC,KAAA,EAAO,mBAAA;EACP,QAAA,EAAU,mBAAA;EACV,MAAA,EAAQ,mBAAA;EACR,UAAA,EAAY,mBAAA;AAAA;;KAIV,6BAAA,iBACM,sBAAA,GAAyB,sBAAA,IACvC,0BAAA,CAA2B,OAAA;;KAEnB,wBAAA,GAA2B,qBAAqB;AAtBE;AAU9D;;;;;;AAV8D,UA+B7C,sBAAA;EArB2B;EAuB1C,MAAA,EAAQ,sBAAA;EAvBqD;EAyB7D,MAAA,EAAQ,MAAM;EAxBN;EA0BR,OAAA;AAAA;;;;;UAOe,oCAAA;EA9BwB;EAgCvC,SAAA,EAAW,GAAA;EA5BD;EA8BV,UAAA,GAAa,aAAa;EA9Ba;EAgCvC,UAAA;AAAA;;;;;;;;iBAUc,qBAAA,CACd,QAAA,EAAU,4BAAA,GACT,sBAAsB;;;AA1Ca;AAEtC;;;;iBAmDgB,4BAAA,CAA6B,OAAA;EAC3C,YAAA,QAAoB,MAAA;AAAA,IAClB,sBAAsB;;;;;;;;;AAtCjB;AAOT;;;;;;;;iBA6DgB,4BAAA,CACd,OAAA,EAAS,oCAAA,GACR,sBAAsB;;AAzDb;AAUZ;;;;iBA+DgB,sBAAA,CACd,OAAA,EAAS,6BAAA,GACR,wBAAwB"}