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
@@ -9,11 +9,26 @@ import { SYNCORE_DEVTOOLS_MAX_SUPPORTED_PROTOCOL_VERSION, SYNCORE_DEVTOOLS_MIN_S
9
9
  //#region src/index.ts
10
10
  const DEVTOOLS_META_NAMESPACE = "__syncore_devtools_meta__";
11
11
  const STORAGE_SCOPE_ID_PREFIX = "storage-scope";
12
+ const DATA_SOURCE_ALIAS_PREFIX = "data-source-alias";
12
13
  /**
13
- * Create a full Syncore runtime directly in the browser.
14
+ * Create a full Syncore runtime directly in the browser (main thread or
15
+ * shared worker).
14
16
  *
15
- * Most React apps should use a worker runtime instead so queries and SQLite work
16
- * stay off the main thread.
17
+ * This function sets up SQL.js, the OPFS/IndexedDB persistence layer,
18
+ * OPFS-backed blob storage when available, cross-tab change synchronisation via `BroadcastChannel`, and
19
+ * auto-connects to the devtools server in development.
20
+ *
21
+ * @remarks
22
+ * Most React/Svelte apps should run the runtime inside a `Worker` using
23
+ * `createWebWorkerSyncoreRuntime()` instead, so that SQLite queries don’t
24
+ * block the main thread. Use `createWebSyncoreRuntime` only when a worker is
25
+ * not practical (e.g. in Electron renderer processes or certain test setups).
26
+ *
27
+ * ```ts
28
+ * const runtime = await createWebSyncoreRuntime({ schema, functions });
29
+ * await runtime.start();
30
+ * const client = runtime.createClient();
31
+ * ```
17
32
  */
18
33
  async function createWebSyncoreRuntime(options) {
19
34
  const persistence = options.persistence ?? await createWebPersistence({
@@ -21,23 +36,27 @@ async function createWebSyncoreRuntime(options) {
21
36
  ...options.persistenceDatabaseName ? { indexedDbDatabaseName: options.persistenceDatabaseName } : {},
22
37
  opfsRootDirectoryName: options.opfsRootDirectoryName ?? options.databaseName ?? "syncore"
23
38
  });
39
+ const wasmUrl = options.wasmUrl ?? (options.locateFile || !isBrowserLikeRuntime() ? void 0 : await resolveDefaultWebWasmUrl());
24
40
  const driver = options.driver ?? await SqlJsDriver.create({
25
41
  databaseName: options.databaseName ?? "syncore",
26
42
  persistence,
27
- ...options.wasmUrl ? { wasmUrl: options.wasmUrl } : {},
43
+ ...wasmUrl ? { wasmUrl } : {},
28
44
  ...options.locateFile ? { locateFile: options.locateFile } : {}
29
45
  });
30
- const storage = options.storage ?? new BrowserFileStorageAdapter(persistence, options.storageNamespace ?? options.databaseName ?? "syncore");
46
+ const storageNamespace = options.storageNamespace ?? options.databaseName ?? "syncore";
47
+ const storage = options.storage ?? (persistence.storageProtocol === "opfs" ? new BrowserFileStorageAdapter(persistence, storageNamespace) : new UnavailableBrowserStorageAdapter(BROWSER_STORAGE_UNAVAILABLE_REASON));
48
+ const runtimeCapabilities = createBrowserRuntimeCapabilities(persistence, storage, Boolean(options.storage));
31
49
  const externalChangeSupport = createWebExternalChangeSupport({
32
50
  databaseName: options.databaseName ?? "syncore",
33
51
  persistence,
34
52
  driver
35
53
  });
36
- const appName = resolveWebAppName();
54
+ const appName = options.appName ?? resolveWebAppName();
37
55
  const origin = resolveWebOrigin();
38
56
  const sessionLabel = resolveWebSessionLabel();
39
57
  const databaseLabel = options.databaseName ?? "syncore";
40
58
  const storageScopeId = await resolvePersistedStorageScopeId(persistence, databaseLabel);
59
+ const dataSourceAlias = await resolvePersistedDataSourceAlias(persistence, databaseLabel);
41
60
  const storageIdentity = [
42
61
  origin ?? "unknown-origin",
43
62
  persistence.storageProtocol,
@@ -46,11 +65,13 @@ async function createWebSyncoreRuntime(options) {
46
65
  ].join("::");
47
66
  const autoDevtools = options.devtools === void 0 && shouldAutoConnectDevtools() ? (() => {
48
67
  const sinkOptions = {
49
- url: resolveDefaultDevtoolsUrl(),
68
+ url: options.devtoolsUrl ?? resolveDefaultDevtoolsUrl(),
50
69
  targetKind: "client",
51
70
  storageProtocol: persistence.storageProtocol,
52
71
  databaseLabel,
53
- storageIdentity
72
+ dataSourceAlias,
73
+ storageIdentity,
74
+ capabilities: createBrowserDevtoolsCapabilities(runtimeCapabilities)
54
75
  };
55
76
  if (appName) sinkOptions.appName = appName;
56
77
  if (origin) sinkOptions.origin = origin;
@@ -63,7 +84,7 @@ async function createWebSyncoreRuntime(options) {
63
84
  sessionLabel,
64
85
  appName,
65
86
  origin,
66
- devtoolsUrl: options.devtools && typeof options.devtools === "object" ? void 0 : resolveDefaultDevtoolsUrl()
87
+ devtoolsUrl: options.devtools && typeof options.devtools === "object" ? void 0 : options.devtoolsUrl ?? resolveDefaultDevtoolsUrl()
67
88
  });
68
89
  const runtime = new SyncoreRuntime({
69
90
  schema: options.schema,
@@ -75,18 +96,19 @@ async function createWebSyncoreRuntime(options) {
75
96
  ...externalChangeSupport.applier ? { externalChangeApplier: externalChangeSupport.applier } : {},
76
97
  platform: options.platform ?? "browser",
77
98
  ...options.capabilities ? { capabilities: options.capabilities } : {},
99
+ runtimeCapabilities,
78
100
  ...resolvedDevtools ? { devtools: resolvedDevtools } : {},
79
101
  ...options.scheduler ? { scheduler: options.scheduler } : {}
80
102
  });
81
- if (autoDevtools) {
82
- autoDevtools.attachRuntime(runtime);
83
- autoDevtools.attachCommandHandler(createDevtoolsCommandHandler({
103
+ if (isAttachableBrowserDevtoolsSink(resolvedDevtools)) {
104
+ resolvedDevtools.attachRuntime(runtime);
105
+ resolvedDevtools.attachCommandHandler(createDevtoolsCommandHandler({
84
106
  driver,
85
107
  schema: options.schema,
86
108
  functions: options.functions,
87
109
  admin: runtime.getAdmin()
88
110
  }));
89
- autoDevtools.attachSubscriptionHost(createDevtoolsSubscriptionHost({
111
+ resolvedDevtools.attachSubscriptionHost(createDevtoolsSubscriptionHost({
90
112
  driver,
91
113
  schema: options.schema,
92
114
  functions: options.functions,
@@ -95,6 +117,21 @@ async function createWebSyncoreRuntime(options) {
95
117
  }
96
118
  return runtime;
97
119
  }
120
+ function isAttachableBrowserDevtoolsSink(sink) {
121
+ return !!sink && typeof sink.attachRuntime === "function" && typeof sink.attachCommandHandler === "function" && typeof sink.attachSubscriptionHost === "function";
122
+ }
123
+ /**
124
+ * Build a {@link WebExternalChangeSupport} bundle for a given database and
125
+ * persistence layer.
126
+ *
127
+ * Creates a `BroadcastChannel`-based signal so that all tabs sharing the same
128
+ * `databaseName` are notified when a mutation commits. When `driver` is a
129
+ * `SqlJsDriver` (i.e. an in-memory database), an `applier` is also created so
130
+ * the local database can be updated from the latest on-disk snapshot.
131
+ *
132
+ * Called automatically by `createWebSyncoreRuntime`. Exposed for advanced use
133
+ * cases such as the Expo web adapter.
134
+ */
98
135
  function createWebExternalChangeSupport(options) {
99
136
  const signal = new BroadcastChannelExternalChangeSignal({ channelName: createDefaultSyncChannelName(options.databaseName) });
100
137
  const sqlDriver = options.driver instanceof SqlJsDriver ? options.driver : void 0;
@@ -111,16 +148,28 @@ function createWebExternalChangeSupport(options) {
111
148
  })
112
149
  };
113
150
  }
151
+ /**
152
+ * Build a {@link WebExternalChangeSupport} bundle for an Expo app running on
153
+ * the web platform.
154
+ *
155
+ * Behaves identically to {@link createWebExternalChangeSupport} but accepts
156
+ * the same options shape used by `createExpoSyncoreRuntime`, making it easy
157
+ * to share config when bootstrapping an Expo web runtime.
158
+ *
159
+ * Called internally by the Expo platform adapter. Use directly only when
160
+ * constructing the runtime outside of `createExpoSyncoreRuntime`.
161
+ */
114
162
  async function createExpoWebExternalChangeSupport(options) {
115
163
  const persistence = await createWebPersistence({
116
164
  ...options.persistenceMode ? { mode: options.persistenceMode } : {},
117
165
  ...options.persistenceDatabaseName ? { indexedDbDatabaseName: options.persistenceDatabaseName } : {},
118
166
  opfsRootDirectoryName: options.opfsRootDirectoryName ?? options.databaseName
119
167
  });
168
+ const wasmUrl = options.wasmUrl ?? (options.locateFile || !isBrowserLikeRuntime() ? void 0 : await resolveDefaultWebWasmUrl());
120
169
  const driver = await SqlJsDriver.create({
121
170
  databaseName: options.databaseName,
122
171
  persistence,
123
- ...options.wasmUrl ? { wasmUrl: options.wasmUrl } : {},
172
+ ...wasmUrl ? { wasmUrl } : {},
124
173
  ...options.locateFile ? { locateFile: options.locateFile } : {}
125
174
  });
126
175
  return createWebExternalChangeSupport({
@@ -130,38 +179,107 @@ async function createExpoWebExternalChangeSupport(options) {
130
179
  });
131
180
  }
132
181
  /**
133
- * Attach a Syncore runtime to a browser Worker endpoint.
182
+ * Start a Syncore runtime inside a browser `Worker` and wire it to the
183
+ * worker’s own message endpoint.
184
+ *
185
+ * This is the function you call **inside your worker file** (`syncore.worker.ts`).
186
+ * It creates the full runtime (SQL.js + OPFS + BroadcastChannel) in the worker
187
+ * context and begins listening for messages from the main-thread client.
188
+ *
189
+ * ```ts
190
+ * // syncore.worker.ts
191
+ * import { createWebWorkerRuntime } from "syncorejs/browser";
192
+ * import schema from "./syncore/schema";
193
+ * import { functions } from "./syncore/_generated/functions";
194
+ *
195
+ * void createWebWorkerRuntime({
196
+ * schema,
197
+ * functions,
198
+ * endpoint: self as unknown as SyncoreWorkerMessageEndpoint,
199
+ * });
200
+ * ```
201
+ *
202
+ * On the main thread, connect with `createManagedWebWorkerClient()` or
203
+ * `SyncoreNextProvider` (Next.js).
134
204
  */
135
205
  function createWebWorkerRuntime(options) {
136
206
  return attachWebWorkerRuntime({
137
207
  endpoint: options.endpoint,
138
- createRuntime: () => createWebSyncoreRuntime(options)
208
+ createRuntime: () => createWebSyncoreRuntime({
209
+ ...options,
210
+ platform: options.platform ?? "browser-worker"
211
+ })
139
212
  });
140
213
  }
141
214
  /**
142
- * Attach a Syncore runtime to a browser Worker endpoint.
215
+ * Alias of {@link createWebWorkerRuntime} for the `syncorejs/browser` surface.
216
+ * @see createWebWorkerRuntime
143
217
  */
144
218
  function createBrowserWorkerRuntime(options) {
145
219
  return createWebWorkerRuntime(options);
146
220
  }
147
221
  /**
148
- * Create a client directly from a browser Syncore runtime.
222
+ * Create a same-process Syncore client from a started browser runtime.
223
+ *
224
+ * Use this when the runtime lives in the same context as the client (e.g.
225
+ * main-thread runtime in an Electron renderer or a test harness). For
226
+ * worker-based setups use `createManagedWebWorkerClient()` instead, which
227
+ * communicates with the worker over `postMessage`.
228
+ *
229
+ * ```ts
230
+ * const runtime = await createWebSyncoreRuntime({ schema, functions });
231
+ * await runtime.start();
232
+ * const client = createWebSyncoreClient(runtime);
233
+ * ```
149
234
  */
150
235
  function createWebSyncoreClient(runtime) {
151
236
  return runtime.createClient();
152
237
  }
153
238
  /**
154
- * Create a full Syncore runtime directly in the browser.
239
+ * Alias of {@link createWebSyncoreRuntime} for the `syncorejs/browser` surface.
240
+ * @see createWebSyncoreRuntime
155
241
  */
156
242
  function createBrowserSyncoreRuntime(options) {
157
243
  return createWebSyncoreRuntime(options);
158
244
  }
159
245
  /**
160
- * Create a client directly from a browser Syncore runtime.
246
+ * Alias of {@link createWebSyncoreClient} for the `syncorejs/browser` surface.
247
+ * @see createWebSyncoreClient
161
248
  */
162
249
  function createBrowserSyncoreClient(runtime) {
163
250
  return createWebSyncoreClient(runtime);
164
251
  }
252
+ async function resolveDefaultWebWasmUrl() {
253
+ try {
254
+ return (await import("./web-sqljs-wasm.js")).resolveDefaultWebSqlJsWasmUrl();
255
+ } catch (error) {
256
+ if (!isBrowserLikeRuntime()) return;
257
+ throw new Error("Syncore could not resolve the default sql.js WebAssembly asset. Pass wasmUrl or locateFile to createWebSyncoreRuntime/createBrowserWorkerRuntime for this bundler.", { cause: error });
258
+ }
259
+ }
260
+ function isBrowserLikeRuntime() {
261
+ return typeof window !== "undefined" || globalThis.WorkerGlobalScope !== void 0;
262
+ }
263
+ /**
264
+ * Create a WebSocket-based devtools sink that connects to the Syncore devtools
265
+ * server and forwards runtime events in real time.
266
+ *
267
+ * The sink auto-reconnects if the connection drops (e.g. while the devtools
268
+ * dashboard is restarting) and buffers events that arrive before the socket is
269
+ * open.
270
+ *
271
+ * In most cases you do not need to call this directly — `createWebSyncoreRuntime`
272
+ * creates and attaches the sink automatically when `devtools` is omitted and the
273
+ * page is served from a local/private hostname.
274
+ *
275
+ * ```ts
276
+ * const sink = createBrowserWebSocketDevtoolsSink({
277
+ * url: "ws://127.0.0.1:4311",
278
+ * appName: "My App",
279
+ * });
280
+ * const runtime = await createWebSyncoreRuntime({ schema, functions, devtools: sink });
281
+ * ```
282
+ */
165
283
  function createBrowserWebSocketDevtoolsSink(options) {
166
284
  let socket;
167
285
  let disposed = false;
@@ -188,7 +306,9 @@ function createBrowserWebSocketDevtoolsSink(options) {
188
306
  ...options.targetKind ? { targetKind: options.targetKind } : {},
189
307
  ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
190
308
  ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
191
- ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
309
+ ...options.dataSourceAlias ? { dataSourceAlias: options.dataSourceAlias } : {},
310
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {},
311
+ capabilities: options.capabilities ?? createBrowserDevtoolsCapabilities()
192
312
  });
193
313
  flushPendingMessages();
194
314
  };
@@ -279,7 +399,9 @@ function createBrowserWebSocketDevtoolsSink(options) {
279
399
  ...options.targetKind ? { targetKind: options.targetKind } : {},
280
400
  ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
281
401
  ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
282
- ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
402
+ ...options.dataSourceAlias ? { dataSourceAlias: options.dataSourceAlias } : {},
403
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {},
404
+ capabilities: options.capabilities ?? createBrowserDevtoolsCapabilities()
283
405
  });
284
406
  }
285
407
  send({
@@ -313,7 +435,51 @@ function withRuntimeSummaryMeta(summary, options) {
313
435
  ...options.targetKind ? { targetKind: options.targetKind } : {},
314
436
  ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
315
437
  ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
316
- ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
438
+ ...options.dataSourceAlias ? { dataSourceAlias: options.dataSourceAlias } : {},
439
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {},
440
+ capabilities: options.capabilities ?? createBrowserDevtoolsCapabilities()
441
+ };
442
+ }
443
+ function createBrowserRuntimeCapabilities(persistence, storage, hasExplicitStorage) {
444
+ if (!hasExplicitStorage && persistence.storageProtocol !== "opfs") return { storage: {
445
+ available: false,
446
+ reason: BROWSER_STORAGE_UNAVAILABLE_REASON,
447
+ protocol: persistence.storageProtocol,
448
+ supportsRange: false
449
+ } };
450
+ return { storage: {
451
+ available: true,
452
+ protocol: hasExplicitStorage ? "custom" : persistence.storageProtocol,
453
+ ...storage.supportsRange ? { supportsRange: storage.supportsRange() !== false } : {}
454
+ } };
455
+ }
456
+ function createBrowserDevtoolsCapabilities(runtimeCapabilities) {
457
+ const storageCapability = runtimeCapabilities?.storage;
458
+ const storageAvailable = storageCapability?.available !== false;
459
+ return {
460
+ sql: {
461
+ read: false,
462
+ write: false,
463
+ live: false,
464
+ reason: "SQL Console is not available for browser runtimes."
465
+ },
466
+ data: {
467
+ browse: true,
468
+ mutate: true,
469
+ importExport: true
470
+ },
471
+ storage: {
472
+ browse: storageAvailable,
473
+ download: storageAvailable,
474
+ readRange: storageCapability?.supportsRange === true,
475
+ delete: storageAvailable,
476
+ maxPreviewBytes: 8e4,
477
+ ...!storageAvailable && storageCapability?.reason ? { reason: storageCapability.reason } : {}
478
+ },
479
+ scheduler: {
480
+ read: true,
481
+ edit: true
482
+ }
317
483
  };
318
484
  }
319
485
  function shouldAutoConnectDevtools() {
@@ -431,6 +597,17 @@ async function resolvePersistedStorageScopeId(persistence, databaseLabel) {
431
597
  await persistence.putFile(DEVTOOLS_META_NAMESPACE, id, new TextEncoder().encode(nextValue), "text/plain");
432
598
  return nextValue;
433
599
  }
600
+ async function resolvePersistedDataSourceAlias(persistence, databaseLabel) {
601
+ const id = `${DATA_SOURCE_ALIAS_PREFIX}:${databaseLabel}`;
602
+ const existing = await persistence.getFile(DEVTOOLS_META_NAMESPACE, id);
603
+ if (existing) {
604
+ const value = new TextDecoder().decode(existing.bytes).trim();
605
+ if (value.length > 0) return value;
606
+ }
607
+ const nextValue = generateUniqueSessionName();
608
+ await persistence.putFile(DEVTOOLS_META_NAMESPACE, id, new TextEncoder().encode(nextValue), "text/plain");
609
+ return nextValue;
610
+ }
434
611
  function announceBrowserSession(options) {
435
612
  if (!options.enabled || !options.sessionLabel) return;
436
613
  const announcedSessions = getAnnouncedBrowserSessions();
@@ -555,16 +732,33 @@ const SESSION_NOUNS = [
555
732
  "Thunder",
556
733
  "Drift"
557
734
  ];
735
+ const BROWSER_STORAGE_UNAVAILABLE_REASON = "Browser file storage requires OPFS. IndexedDB is used for data only.";
558
736
  function generateUniqueSessionName() {
559
737
  return `${SESSION_ADJECTIVES[Math.floor(Math.random() * SESSION_ADJECTIVES.length)]} ${SESSION_NOUNS[Math.floor(Math.random() * SESSION_NOUNS.length)]}`;
560
738
  }
561
739
  /**
562
- * Browser file/blob storage built on top of Syncore web persistence.
740
+ * Browser file/blob storage adapter backed by `SyncoreWebPersistence`.
741
+ *
742
+ * Stores binary blobs (images, documents, etc.) in OPFS alongside the SQLite
743
+ * database. Pass an instance to
744
+ * `CreateWebRuntimeOptions.storage` to enable Syncore's Storage API
745
+ * (`ctx.storage.put`, `ctx.storage.get`, etc.) in browser functions.
746
+ *
747
+ * ```ts
748
+ * const runtime = await createWebSyncoreRuntime({
749
+ * schema,
750
+ * functions,
751
+ * storage: new BrowserFileStorageAdapter(persistence, "files"),
752
+ * });
753
+ * ```
563
754
  */
564
755
  var BrowserFileStorageAdapter = class {
756
+ persistence;
757
+ namespace;
565
758
  constructor(persistence, namespace) {
566
759
  this.persistence = persistence;
567
760
  this.namespace = namespace;
761
+ if (persistence.storageProtocol !== "opfs") throw new Error(BROWSER_STORAGE_UNAVAILABLE_REASON);
568
762
  }
569
763
  async put(id, input) {
570
764
  const bytes = normalizeBinary(input.data);
@@ -589,11 +783,18 @@ var BrowserFileStorageAdapter = class {
589
783
  async read(id) {
590
784
  return (await this.persistence.getFile(this.namespace, id))?.bytes ?? null;
591
785
  }
786
+ supportsRange() {
787
+ return Boolean(this.persistence.getFileRange);
788
+ }
789
+ async readRange(id, offset, length) {
790
+ if (!this.persistence.getFileRange) return null;
791
+ return (await this.persistence.getFileRange(this.namespace, id, offset, length))?.bytes ?? null;
792
+ }
592
793
  async delete(id) {
593
794
  await this.persistence.deleteFile(this.namespace, id);
594
795
  }
595
796
  async list() {
596
- return (await this.persistence.listFiles(this.namespace)).map((file) => ({
797
+ return (this.persistence.listFileMetadata ? await this.persistence.listFileMetadata(this.namespace) : await this.persistence.listFiles(this.namespace)).map((file) => ({
597
798
  id: file.id,
598
799
  path: `${this.persistence.storageProtocol}://${this.namespace}/${file.id}`,
599
800
  size: file.size,
@@ -601,6 +802,27 @@ var BrowserFileStorageAdapter = class {
601
802
  }));
602
803
  }
603
804
  };
805
+ var UnavailableBrowserStorageAdapter = class {
806
+ reason;
807
+ constructor(reason) {
808
+ this.reason = reason;
809
+ }
810
+ async put() {
811
+ throw new Error(this.reason);
812
+ }
813
+ async get() {
814
+ throw new Error(this.reason);
815
+ }
816
+ async read() {
817
+ throw new Error(this.reason);
818
+ }
819
+ supportsRange() {
820
+ return false;
821
+ }
822
+ async delete() {
823
+ throw new Error(this.reason);
824
+ }
825
+ };
604
826
  function normalizeBinary(data) {
605
827
  if (typeof data === "string") return new TextEncoder().encode(data);
606
828
  if (data instanceof Uint8Array) return data;