syncorejs 0.1.0 → 0.2.0

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 (200) hide show
  1. package/dist/{core/src/cli.d.ts → _vendor/cli/app.d.mts} +4 -2
  2. package/dist/_vendor/cli/app.d.mts.map +1 -0
  3. package/dist/_vendor/cli/app.mjs +997 -0
  4. package/dist/_vendor/cli/app.mjs.map +1 -0
  5. package/dist/_vendor/cli/context.mjs +180 -0
  6. package/dist/_vendor/cli/context.mjs.map +1 -0
  7. package/dist/_vendor/cli/dev-session.mjs +49 -0
  8. package/dist/_vendor/cli/dev-session.mjs.map +1 -0
  9. package/dist/_vendor/cli/doctor.mjs +80 -0
  10. package/dist/_vendor/cli/doctor.mjs.map +1 -0
  11. package/dist/_vendor/cli/errors.mjs +22 -0
  12. package/dist/_vendor/cli/errors.mjs.map +1 -0
  13. package/dist/_vendor/cli/help.mjs +26 -0
  14. package/dist/_vendor/cli/help.mjs.map +1 -0
  15. package/dist/_vendor/cli/index.d.mts +2 -0
  16. package/dist/_vendor/cli/index.mjs +23 -0
  17. package/dist/_vendor/cli/index.mjs.map +1 -0
  18. package/dist/_vendor/cli/messages.mjs +32 -0
  19. package/dist/_vendor/cli/messages.mjs.map +1 -0
  20. package/dist/_vendor/cli/preflight.mjs +35 -0
  21. package/dist/_vendor/cli/preflight.mjs.map +1 -0
  22. package/dist/_vendor/cli/project.mjs +583 -0
  23. package/dist/_vendor/cli/project.mjs.map +1 -0
  24. package/dist/_vendor/cli/render.mjs +133 -0
  25. package/dist/_vendor/cli/render.mjs.map +1 -0
  26. package/dist/_vendor/cli/targets.mjs +87 -0
  27. package/dist/_vendor/cli/targets.mjs.map +1 -0
  28. package/dist/_vendor/core/cli.d.mts +59 -1
  29. package/dist/_vendor/core/cli.d.mts.map +1 -1
  30. package/dist/_vendor/core/cli.mjs +528 -75
  31. package/dist/_vendor/core/cli.mjs.map +1 -1
  32. package/dist/_vendor/core/index.d.mts +12 -4
  33. package/dist/_vendor/core/index.d.mts.map +1 -0
  34. package/dist/_vendor/core/index.mjs +4 -3
  35. package/dist/_vendor/core/index.mjs.map +1 -1
  36. package/dist/_vendor/core/runtime/devtools.d.mts +32 -6
  37. package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
  38. package/dist/_vendor/core/runtime/devtools.mjs +397 -182
  39. package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
  40. package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
  41. package/dist/_vendor/core/runtime/runtime.d.mts +89 -7
  42. package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
  43. package/dist/_vendor/core/runtime/runtime.mjs +303 -32
  44. package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
  45. package/dist/_vendor/devtools-protocol/index.d.ts +189 -82
  46. package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
  47. package/dist/_vendor/devtools-protocol/index.js +39 -0
  48. package/dist/_vendor/devtools-protocol/index.js.map +1 -0
  49. package/dist/_vendor/next/config.d.ts.map +1 -1
  50. package/dist/_vendor/next/config.js +2 -5
  51. package/dist/_vendor/next/config.js.map +1 -1
  52. package/dist/_vendor/platform-expo/index.d.ts +15 -5
  53. package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
  54. package/dist/_vendor/platform-expo/index.js +33 -3
  55. package/dist/_vendor/platform-expo/index.js.map +1 -1
  56. package/dist/_vendor/platform-expo/react.js.map +1 -1
  57. package/dist/_vendor/platform-node/index.d.mts +10 -5
  58. package/dist/_vendor/platform-node/index.d.mts.map +1 -1
  59. package/dist/_vendor/platform-node/index.mjs +145 -35
  60. package/dist/_vendor/platform-node/index.mjs.map +1 -1
  61. package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
  62. package/dist/_vendor/platform-web/external-change.d.ts +39 -0
  63. package/dist/_vendor/platform-web/external-change.d.ts.map +1 -0
  64. package/dist/_vendor/platform-web/external-change.js +61 -0
  65. package/dist/_vendor/platform-web/external-change.js.map +1 -0
  66. package/dist/_vendor/platform-web/index.d.ts +27 -5
  67. package/dist/_vendor/platform-web/index.d.ts.map +1 -1
  68. package/dist/_vendor/platform-web/index.js +310 -44
  69. package/dist/_vendor/platform-web/index.js.map +1 -1
  70. package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
  71. package/dist/_vendor/platform-web/opfs.js.map +1 -1
  72. package/dist/_vendor/platform-web/persistence.js.map +1 -1
  73. package/dist/_vendor/platform-web/react.js.map +1 -1
  74. package/dist/_vendor/platform-web/sqljs.js +22 -2
  75. package/dist/_vendor/platform-web/sqljs.js.map +1 -1
  76. package/dist/_vendor/schema/definition.js.map +1 -1
  77. package/dist/_vendor/schema/planner.js.map +1 -1
  78. package/dist/_vendor/schema/validators.js.map +1 -1
  79. package/dist/browser-react.d.ts +1 -1
  80. package/dist/browser-react.js +1 -1
  81. package/dist/browser.d.ts +6 -7
  82. package/dist/browser.d.ts.map +1 -1
  83. package/dist/browser.js +4 -5
  84. package/dist/browser.js.map +1 -1
  85. package/dist/cli.d.ts +1 -1
  86. package/dist/cli.js +12 -3
  87. package/dist/cli.js.map +1 -1
  88. package/dist/expo-react.d.ts +1 -1
  89. package/dist/expo-react.js +1 -1
  90. package/dist/expo.d.ts +1 -2
  91. package/dist/expo.js +1 -2
  92. package/dist/index.d.ts +3 -7
  93. package/dist/index.js +3 -8
  94. package/dist/next-config.d.ts +1 -2
  95. package/dist/next-config.js +1 -2
  96. package/dist/next.d.ts +1 -3
  97. package/dist/next.js +1 -3
  98. package/dist/node-ipc-react.d.ts +1 -1
  99. package/dist/node-ipc-react.js +1 -1
  100. package/dist/node-ipc.d.ts +1 -2
  101. package/dist/node-ipc.js +1 -2
  102. package/dist/node.d.ts +1 -4
  103. package/dist/node.js +1 -3
  104. package/dist/react.d.ts +1 -2
  105. package/dist/react.js +1 -2
  106. package/dist/svelte.d.ts +1 -2
  107. package/dist/svelte.js +1 -2
  108. package/package.json +6 -3
  109. package/dist/core/src/cli.d.ts.map +0 -1
  110. package/dist/core/src/cli.js +0 -1196
  111. package/dist/core/src/cli.js.map +0 -1
  112. package/dist/core/src/index.js +0 -7
  113. package/dist/core/src/runtime/devtools.d.ts +0 -7
  114. package/dist/core/src/runtime/devtools.d.ts.map +0 -1
  115. package/dist/core/src/runtime/devtools.js +0 -300
  116. package/dist/core/src/runtime/devtools.js.map +0 -1
  117. package/dist/core/src/runtime/functions.d.ts +0 -123
  118. package/dist/core/src/runtime/functions.d.ts.map +0 -1
  119. package/dist/core/src/runtime/functions.js +0 -71
  120. package/dist/core/src/runtime/functions.js.map +0 -1
  121. package/dist/core/src/runtime/id.d.ts +0 -13
  122. package/dist/core/src/runtime/id.d.ts.map +0 -1
  123. package/dist/core/src/runtime/id.js +0 -28
  124. package/dist/core/src/runtime/id.js.map +0 -1
  125. package/dist/core/src/runtime/runtime.d.ts +0 -371
  126. package/dist/core/src/runtime/runtime.d.ts.map +0 -1
  127. package/dist/core/src/runtime/runtime.js +0 -1143
  128. package/dist/core/src/runtime/runtime.js.map +0 -1
  129. package/dist/devtools-protocol/src/index.d.ts +0 -201
  130. package/dist/devtools-protocol/src/index.d.ts.map +0 -1
  131. package/dist/next/src/config.d.ts +0 -17
  132. package/dist/next/src/config.d.ts.map +0 -1
  133. package/dist/next/src/config.js +0 -73
  134. package/dist/next/src/config.js.map +0 -1
  135. package/dist/next/src/index.d.ts +0 -80
  136. package/dist/next/src/index.d.ts.map +0 -1
  137. package/dist/next/src/index.js +0 -82
  138. package/dist/next/src/index.js.map +0 -1
  139. package/dist/platform-expo/src/index.d.ts +0 -96
  140. package/dist/platform-expo/src/index.d.ts.map +0 -1
  141. package/dist/platform-expo/src/index.js +0 -198
  142. package/dist/platform-expo/src/index.js.map +0 -1
  143. package/dist/platform-expo/src/react.d.ts +0 -26
  144. package/dist/platform-expo/src/react.d.ts.map +0 -1
  145. package/dist/platform-expo/src/react.js +0 -30
  146. package/dist/platform-expo/src/react.js.map +0 -1
  147. package/dist/platform-node/src/index.d.ts +0 -145
  148. package/dist/platform-node/src/index.d.ts.map +0 -1
  149. package/dist/platform-node/src/index.js +0 -407
  150. package/dist/platform-node/src/index.js.map +0 -1
  151. package/dist/platform-node/src/ipc-react.d.ts +0 -25
  152. package/dist/platform-node/src/ipc-react.d.ts.map +0 -1
  153. package/dist/platform-node/src/ipc-react.js +0 -21
  154. package/dist/platform-node/src/ipc-react.js.map +0 -1
  155. package/dist/platform-node/src/ipc.d.ts +0 -76
  156. package/dist/platform-node/src/ipc.d.ts.map +0 -1
  157. package/dist/platform-node/src/ipc.js +0 -344
  158. package/dist/platform-node/src/ipc.js.map +0 -1
  159. package/dist/platform-web/src/index.d.ts +0 -106
  160. package/dist/platform-web/src/index.d.ts.map +0 -1
  161. package/dist/platform-web/src/index.js +0 -311
  162. package/dist/platform-web/src/index.js.map +0 -1
  163. package/dist/platform-web/src/indexeddb.js +0 -125
  164. package/dist/platform-web/src/indexeddb.js.map +0 -1
  165. package/dist/platform-web/src/opfs.js +0 -146
  166. package/dist/platform-web/src/opfs.js.map +0 -1
  167. package/dist/platform-web/src/persistence.d.ts +0 -20
  168. package/dist/platform-web/src/persistence.d.ts.map +0 -1
  169. package/dist/platform-web/src/persistence.js +0 -23
  170. package/dist/platform-web/src/persistence.js.map +0 -1
  171. package/dist/platform-web/src/react.d.ts +0 -35
  172. package/dist/platform-web/src/react.d.ts.map +0 -1
  173. package/dist/platform-web/src/react.js +0 -42
  174. package/dist/platform-web/src/react.js.map +0 -1
  175. package/dist/platform-web/src/sqljs.js +0 -133
  176. package/dist/platform-web/src/sqljs.js.map +0 -1
  177. package/dist/platform-web/src/worker.d.ts +0 -79
  178. package/dist/platform-web/src/worker.d.ts.map +0 -1
  179. package/dist/platform-web/src/worker.js +0 -308
  180. package/dist/platform-web/src/worker.js.map +0 -1
  181. package/dist/react/src/index.d.ts +0 -59
  182. package/dist/react/src/index.d.ts.map +0 -1
  183. package/dist/react/src/index.js +0 -151
  184. package/dist/react/src/index.js.map +0 -1
  185. package/dist/schema/src/definition.d.ts +0 -98
  186. package/dist/schema/src/definition.d.ts.map +0 -1
  187. package/dist/schema/src/definition.js +0 -84
  188. package/dist/schema/src/definition.js.map +0 -1
  189. package/dist/schema/src/planner.d.ts +0 -42
  190. package/dist/schema/src/planner.d.ts.map +0 -1
  191. package/dist/schema/src/planner.js +0 -131
  192. package/dist/schema/src/planner.js.map +0 -1
  193. package/dist/schema/src/validators.d.ts +0 -194
  194. package/dist/schema/src/validators.d.ts.map +0 -1
  195. package/dist/schema/src/validators.js +0 -158
  196. package/dist/schema/src/validators.js.map +0 -1
  197. package/dist/svelte/src/index.d.ts +0 -44
  198. package/dist/svelte/src/index.d.ts.map +0 -1
  199. package/dist/svelte/src/index.js +0 -75
  200. package/dist/svelte/src/index.js.map +0 -1
@@ -1,9 +1,10 @@
1
1
  import { SyncoreIndexedDbPersistence } from "./indexeddb.js";
2
2
  import { SyncoreOpfsPersistence } from "./opfs.js";
3
3
  import { createWebPersistence, isOpfsAvailable } from "./persistence.js";
4
+ import { BroadcastChannelExternalChangeSignal, SqlJsExternalChangeApplier, createDefaultSyncChannelName } from "./external-change.js";
4
5
  import { SqlJsDriver } from "./sqljs.js";
5
6
  import { SyncoreWebWorkerClient, attachWebWorkerRuntime, createManagedWebWorkerClient, createSyncoreWebWorkerClient, createWebWorkerClient } from "./worker.js";
6
- import { SyncoreRuntime, createDevtoolsRequestHandler } from "../core/index.mjs";
7
+ import { SyncoreRuntime, createDevtoolsCommandHandler, createDevtoolsSubscriptionHost } from "../core/index.mjs";
7
8
  //#region src/index.ts
8
9
  /**
9
10
  * Create a full Syncore runtime directly in the browser.
@@ -24,22 +25,48 @@ async function createWebSyncoreRuntime(options) {
24
25
  ...options.locateFile ? { locateFile: options.locateFile } : {}
25
26
  });
26
27
  const storage = options.storage ?? new BrowserFileStorageAdapter(persistence, options.storageNamespace ?? options.databaseName ?? "syncore");
28
+ const externalChangeSupport = createWebExternalChangeSupport({
29
+ databaseName: options.databaseName ?? "syncore",
30
+ persistence,
31
+ driver
32
+ });
27
33
  const appName = resolveWebAppName();
28
34
  const origin = resolveWebOrigin();
29
35
  const sessionLabel = resolveWebSessionLabel();
36
+ const databaseLabel = options.databaseName ?? "syncore";
37
+ const storageIdentity = [
38
+ origin ?? "unknown-origin",
39
+ persistence.storageProtocol,
40
+ databaseLabel
41
+ ].join("::");
30
42
  const autoDevtools = options.devtools === void 0 && shouldAutoConnectDevtools() ? (() => {
31
- const sinkOptions = { url: resolveDefaultDevtoolsUrl() };
43
+ const sinkOptions = {
44
+ url: resolveDefaultDevtoolsUrl(),
45
+ targetKind: "client",
46
+ storageProtocol: persistence.storageProtocol,
47
+ databaseLabel,
48
+ storageIdentity
49
+ };
32
50
  if (appName) sinkOptions.appName = appName;
33
51
  if (origin) sinkOptions.origin = origin;
34
52
  if (sessionLabel) sinkOptions.sessionLabel = sessionLabel;
35
53
  return createBrowserWebSocketDevtoolsSink(sinkOptions);
36
54
  })() : void 0;
37
55
  const resolvedDevtools = options.devtools === false ? void 0 : options.devtools ?? autoDevtools;
56
+ announceBrowserSession({
57
+ enabled: resolvedDevtools !== void 0,
58
+ sessionLabel,
59
+ appName,
60
+ origin,
61
+ devtoolsUrl: options.devtools && typeof options.devtools === "object" ? void 0 : resolveDefaultDevtoolsUrl()
62
+ });
38
63
  const runtime = new SyncoreRuntime({
39
64
  schema: options.schema,
40
65
  functions: options.functions,
41
66
  driver,
42
67
  storage,
68
+ externalChangeSignal: externalChangeSupport.signal,
69
+ ...externalChangeSupport.applier ? { externalChangeApplier: externalChangeSupport.applier } : {},
43
70
  platform: options.platform ?? "browser",
44
71
  ...options.capabilities ? { capabilities: options.capabilities } : {},
45
72
  ...resolvedDevtools ? { devtools: resolvedDevtools } : {},
@@ -47,8 +74,14 @@ async function createWebSyncoreRuntime(options) {
47
74
  ...options.scheduler ? { scheduler: options.scheduler } : {}
48
75
  });
49
76
  if (autoDevtools) {
50
- autoDevtools.attachRuntime(() => runtime.getDevtoolsSnapshot());
51
- autoDevtools.attachRequestHandler(createDevtoolsRequestHandler({
77
+ autoDevtools.attachRuntime(runtime);
78
+ autoDevtools.attachCommandHandler(createDevtoolsCommandHandler({
79
+ driver,
80
+ schema: options.schema,
81
+ functions: options.functions,
82
+ runtime
83
+ }));
84
+ autoDevtools.attachSubscriptionHost(createDevtoolsSubscriptionHost({
52
85
  driver,
53
86
  schema: options.schema,
54
87
  functions: options.functions,
@@ -57,6 +90,40 @@ async function createWebSyncoreRuntime(options) {
57
90
  }
58
91
  return runtime;
59
92
  }
93
+ function createWebExternalChangeSupport(options) {
94
+ const signal = new BroadcastChannelExternalChangeSignal({ channelName: createDefaultSyncChannelName(options.databaseName) });
95
+ const sqlDriver = options.driver instanceof SqlJsDriver ? options.driver : void 0;
96
+ if (!sqlDriver) return { signal };
97
+ return {
98
+ signal,
99
+ applier: new SqlJsExternalChangeApplier({
100
+ databaseName: options.databaseName,
101
+ persistence: options.persistence,
102
+ createDatabase: (bytes) => sqlDriver.createDatabaseFromBytes(bytes),
103
+ replaceDatabase: (database) => {
104
+ sqlDriver.replaceDatabase(database);
105
+ }
106
+ })
107
+ };
108
+ }
109
+ async function createExpoWebExternalChangeSupport(options) {
110
+ const persistence = await createWebPersistence({
111
+ ...options.persistenceMode ? { mode: options.persistenceMode } : {},
112
+ ...options.persistenceDatabaseName ? { indexedDbDatabaseName: options.persistenceDatabaseName } : {},
113
+ opfsRootDirectoryName: options.opfsRootDirectoryName ?? options.databaseName
114
+ });
115
+ const driver = await SqlJsDriver.create({
116
+ databaseName: options.databaseName,
117
+ persistence,
118
+ ...options.wasmUrl ? { wasmUrl: options.wasmUrl } : {},
119
+ ...options.locateFile ? { locateFile: options.locateFile } : {}
120
+ });
121
+ return createWebExternalChangeSupport({
122
+ databaseName: options.databaseName,
123
+ persistence,
124
+ driver
125
+ });
126
+ }
60
127
  /**
61
128
  * Attach a Syncore runtime to a browser Worker endpoint.
62
129
  */
@@ -94,8 +161,9 @@ function createBrowserWebSocketDevtoolsSink(options) {
94
161
  let socket;
95
162
  let disposed = false;
96
163
  let connectTimer;
97
- let getSnapshot;
98
- let onRequest;
164
+ let getSummary;
165
+ let onCommand;
166
+ let subscriptionHost;
99
167
  const pendingMessages = [];
100
168
  let latestHello;
101
169
  const connect = () => {
@@ -108,11 +176,11 @@ function createBrowserWebSocketDevtoolsSink(options) {
108
176
  platform: latestHello.platform,
109
177
  ...options.appName ? { appName: options.appName } : {},
110
178
  ...options.origin ? { origin: options.origin } : {},
111
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
112
- });
113
- if (getSnapshot) sendNow({
114
- type: "snapshot",
115
- snapshot: withSnapshotMeta(getSnapshot(), options)
179
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
180
+ ...options.targetKind ? { targetKind: options.targetKind } : {},
181
+ ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
182
+ ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
183
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
116
184
  });
117
185
  flushPendingMessages();
118
186
  };
@@ -120,21 +188,21 @@ function createBrowserWebSocketDevtoolsSink(options) {
120
188
  if (typeof event.data !== "string") return;
121
189
  const message = JSON.parse(event.data);
122
190
  if (message.type === "ping") send({ type: "pong" });
123
- else if (message.type === "request" && onRequest) onRequest(message.payload).then((responsePayload) => {
124
- const runtimeId = latestHello?.runtimeId ?? getSnapshot?.().runtimeId;
191
+ else if (message.type === "command" && onCommand) onCommand(message.payload).then((responsePayload) => {
192
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
125
193
  if (!runtimeId) return;
126
194
  send({
127
- type: "response",
128
- requestId: message.requestId,
195
+ type: "command.result",
196
+ commandId: message.commandId,
129
197
  runtimeId,
130
198
  payload: responsePayload
131
199
  });
132
200
  }).catch((err) => {
133
- const runtimeId = latestHello?.runtimeId ?? getSnapshot?.().runtimeId;
201
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
134
202
  if (!runtimeId) return;
135
203
  send({
136
- type: "response",
137
- requestId: message.requestId,
204
+ type: "command.result",
205
+ commandId: message.commandId,
138
206
  runtimeId,
139
207
  payload: {
140
208
  kind: "error",
@@ -142,6 +210,17 @@ function createBrowserWebSocketDevtoolsSink(options) {
142
210
  }
143
211
  });
144
212
  });
213
+ else if (message.type === "subscribe" && subscriptionHost) subscriptionHost.subscribe(message.subscriptionId, message.payload, (payload) => {
214
+ const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
215
+ if (!runtimeId) return;
216
+ send({
217
+ type: "subscription.data",
218
+ subscriptionId: message.subscriptionId,
219
+ runtimeId,
220
+ payload
221
+ });
222
+ });
223
+ else if (message.type === "unsubscribe") subscriptionHost?.unsubscribe(message.subscriptionId);
145
224
  };
146
225
  socket.onclose = scheduleReconnect;
147
226
  socket.onerror = () => {
@@ -185,64 +264,112 @@ function createBrowserWebSocketDevtoolsSink(options) {
185
264
  platform: event.platform,
186
265
  ...options.appName ? { appName: options.appName } : {},
187
266
  ...options.origin ? { origin: options.origin } : {},
188
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
267
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
268
+ ...options.targetKind ? { targetKind: options.targetKind } : {},
269
+ ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
270
+ ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
271
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
189
272
  });
190
273
  }
191
274
  send({
192
275
  type: "event",
193
276
  event
194
277
  });
195
- if (getSnapshot) send({
196
- type: "snapshot",
197
- snapshot: withSnapshotMeta(getSnapshot(), options)
198
- });
199
278
  },
200
- attachRuntime(snapshotGetter) {
201
- getSnapshot = snapshotGetter;
202
- if (socket?.readyState === WebSocket.OPEN) send({
203
- type: "snapshot",
204
- snapshot: withSnapshotMeta(getSnapshot(), options)
205
- });
279
+ attachRuntime(runtime) {
280
+ getSummary = () => withRuntimeSummaryMeta(runtime.getRuntimeSummary(), options);
206
281
  },
207
- attachRequestHandler(handler) {
208
- onRequest = handler;
282
+ attachCommandHandler(handler) {
283
+ onCommand = handler;
284
+ },
285
+ attachSubscriptionHost(host) {
286
+ subscriptionHost = host;
209
287
  },
210
288
  dispose() {
211
289
  disposed = true;
212
290
  if (connectTimer) clearTimeout(connectTimer);
291
+ subscriptionHost?.dispose();
213
292
  socket?.close();
214
293
  }
215
294
  };
216
295
  }
217
- function withSnapshotMeta(snapshot, options) {
296
+ function withRuntimeSummaryMeta(summary, options) {
218
297
  return {
219
- ...snapshot,
298
+ ...summary,
220
299
  ...options.appName ? { appName: options.appName } : {},
221
300
  ...options.origin ? { origin: options.origin } : {},
222
- ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}
301
+ ...options.sessionLabel ? { sessionLabel: options.sessionLabel } : {},
302
+ ...options.targetKind ? { targetKind: options.targetKind } : {},
303
+ ...options.storageProtocol ? { storageProtocol: options.storageProtocol } : {},
304
+ ...options.databaseLabel ? { databaseLabel: options.databaseLabel } : {},
305
+ ...options.storageIdentity ? { storageIdentity: options.storageIdentity } : {}
223
306
  };
224
307
  }
225
308
  function shouldAutoConnectDevtools() {
226
- if (typeof globalThis === "undefined") return false;
309
+ const hostname = resolveWebHostname();
310
+ if (!hostname) return false;
311
+ return hostname === "localhost" || isPrivateNetworkHostname(hostname) || hostname.endsWith(".local");
312
+ }
313
+ function resolveDefaultDevtoolsUrl() {
314
+ return "ws://127.0.0.1:4311";
315
+ }
316
+ function resolveLocationString(key) {
227
317
  try {
228
- return globalThis.location?.hostname === "localhost" || globalThis.location?.hostname === "127.0.0.1" ? true : Boolean(globalThis.location?.hostname?.endsWith?.(".local"));
318
+ const value = globalThis.location?.[key];
319
+ return typeof value === "string" && value.length > 0 ? value : void 0;
229
320
  } catch {
230
- return false;
321
+ return;
231
322
  }
232
323
  }
233
- function resolveDefaultDevtoolsUrl() {
234
- return "ws://127.0.0.1:4311";
324
+ function resolveGlobalOrigin() {
325
+ try {
326
+ const value = globalThis.origin;
327
+ return typeof value === "string" && value.length > 0 ? value : void 0;
328
+ } catch {
329
+ return;
330
+ }
235
331
  }
236
- function resolveWebOrigin() {
332
+ function parseUrlCandidate(candidate) {
333
+ if (!candidate || candidate === "null") return;
237
334
  try {
238
- return globalThis.location?.origin;
335
+ const parsed = new URL(candidate);
336
+ if (parsed.protocol === "blob:" && parsed.pathname.length > 0) try {
337
+ return new URL(parsed.pathname);
338
+ } catch {
339
+ return parsed;
340
+ }
341
+ return parsed;
239
342
  } catch {
240
343
  return;
241
344
  }
242
345
  }
346
+ function resolveWebHostname() {
347
+ const directHostname = resolveLocationString("hostname");
348
+ if (directHostname) return directHostname;
349
+ return parseUrlCandidate(resolveLocationString("href"))?.hostname || parseUrlCandidate(resolveLocationString("origin"))?.hostname || parseUrlCandidate(resolveGlobalOrigin())?.hostname || void 0;
350
+ }
351
+ function isPrivateNetworkHostname(hostname) {
352
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
353
+ if (normalized === "::1") return true;
354
+ if (normalized.startsWith("fc") || normalized.startsWith("fd")) return true;
355
+ const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(normalized);
356
+ if (!match) return false;
357
+ const octets = match.slice(1).map((part) => Number(part));
358
+ if (octets.some((part) => Number.isNaN(part) || part < 0 || part > 255)) return false;
359
+ const first = octets[0];
360
+ const second = octets[1];
361
+ if (first === void 0 || second === void 0) return false;
362
+ return first === 10 || first === 127 || first === 169 && second === 254 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168;
363
+ }
364
+ function resolveWebOrigin() {
365
+ const directOrigin = resolveLocationString("origin");
366
+ if (directOrigin && directOrigin !== "null") return directOrigin;
367
+ const parsedOrigin = parseUrlCandidate(resolveLocationString("href"))?.origin || parseUrlCandidate(resolveGlobalOrigin())?.origin;
368
+ return parsedOrigin && parsedOrigin !== "null" ? parsedOrigin : void 0;
369
+ }
243
370
  function resolveWebAppName() {
244
371
  try {
245
- return globalThis.location?.hostname ?? globalThis.document?.title ?? void 0;
372
+ return resolveWebHostname() ?? globalThis.document?.title ?? void 0;
246
373
  } catch {
247
374
  return;
248
375
  }
@@ -250,11 +377,150 @@ function resolveWebAppName() {
250
377
  function resolveWebSessionLabel() {
251
378
  try {
252
379
  if (typeof navigator === "undefined") return;
253
- return navigator.userAgent.includes("Firefox") ? "Firefox" : navigator.userAgent.includes("Chrome") ? "Chrome" : navigator.userAgent.includes("Safari") ? "Safari" : navigator.userAgent;
380
+ const STORAGE_KEY = "syncore-session-name";
381
+ let uniqueName = null;
382
+ try {
383
+ uniqueName = globalThis.localStorage?.getItem(STORAGE_KEY) ?? null;
384
+ } catch {}
385
+ if (!uniqueName) {
386
+ uniqueName = generateUniqueSessionName();
387
+ try {
388
+ globalThis.localStorage?.setItem(STORAGE_KEY, uniqueName);
389
+ } catch {}
390
+ }
391
+ const browser = navigator.userAgent.includes("Firefox") ? "Firefox" : navigator.userAgent.includes("Chrome") ? "Chrome" : navigator.userAgent.includes("Safari") ? "Safari" : "Browser";
392
+ return `${uniqueName} (${browser})`;
254
393
  } catch {
255
394
  return;
256
395
  }
257
396
  }
397
+ function announceBrowserSession(options) {
398
+ if (!options.enabled || !options.sessionLabel) return;
399
+ const announcedSessions = getAnnouncedBrowserSessions();
400
+ if (announcedSessions.has(options.sessionLabel)) return;
401
+ announcedSessions.add(options.sessionLabel);
402
+ try {
403
+ const details = [
404
+ options.appName ? `app=${options.appName}` : void 0,
405
+ options.origin ? `origin=${options.origin}` : void 0,
406
+ options.devtoolsUrl ? `devtools=${options.devtoolsUrl}` : void 0
407
+ ].filter((value) => value !== void 0);
408
+ console.info(`[syncore] Browser session: ${options.sessionLabel}${details.length > 0 ? ` (${details.join(", ")})` : ""}`);
409
+ } catch {}
410
+ }
411
+ function getAnnouncedBrowserSessions() {
412
+ const key = "__syncoreAnnouncedBrowserSessions";
413
+ const scope = globalThis;
414
+ if (!scope[key]) scope[key] = /* @__PURE__ */ new Set();
415
+ return scope[key];
416
+ }
417
+ const SESSION_ADJECTIVES = [
418
+ "Acrobatic",
419
+ "Bold",
420
+ "Cosmic",
421
+ "Daring",
422
+ "Electric",
423
+ "Fierce",
424
+ "Golden",
425
+ "Hidden",
426
+ "Iron",
427
+ "Jade",
428
+ "Keen",
429
+ "Lunar",
430
+ "Mystic",
431
+ "Noble",
432
+ "Orbital",
433
+ "Primal",
434
+ "Quick",
435
+ "Radiant",
436
+ "Shadow",
437
+ "Turbo",
438
+ "Ultra",
439
+ "Vivid",
440
+ "Wicked",
441
+ "Xenon",
442
+ "Zen",
443
+ "Arctic",
444
+ "Binary",
445
+ "Cyber",
446
+ "Digital",
447
+ "Ember",
448
+ "Frozen",
449
+ "Galactic",
450
+ "Hyper",
451
+ "Infra",
452
+ "Jumbo",
453
+ "Kinetic",
454
+ "Liquid",
455
+ "Magnetic",
456
+ "Neon",
457
+ "Onyx",
458
+ "Phantom",
459
+ "Quantum",
460
+ "Rapid",
461
+ "Sonic",
462
+ "Titan",
463
+ "Velvet",
464
+ "Wild",
465
+ "Blazing",
466
+ "Crystal",
467
+ "Dynamic"
468
+ ];
469
+ const SESSION_NOUNS = [
470
+ "Monkey",
471
+ "Phoenix",
472
+ "Tiger",
473
+ "Dragon",
474
+ "Falcon",
475
+ "Panther",
476
+ "Wolf",
477
+ "Eagle",
478
+ "Cobra",
479
+ "Shark",
480
+ "Raven",
481
+ "Fox",
482
+ "Lynx",
483
+ "Hawk",
484
+ "Bear",
485
+ "Jaguar",
486
+ "Viper",
487
+ "Owl",
488
+ "Stallion",
489
+ "Dolphin",
490
+ "Developer",
491
+ "Hacker",
492
+ "Wizard",
493
+ "Ninja",
494
+ "Pilot",
495
+ "Pioneer",
496
+ "Voyager",
497
+ "Explorer",
498
+ "Runner",
499
+ "Ranger",
500
+ "Maverick",
501
+ "Spartan",
502
+ "Viking",
503
+ "Sentinel",
504
+ "Guardian",
505
+ "Nomad",
506
+ "Cipher",
507
+ "Vector",
508
+ "Matrix",
509
+ "Prism",
510
+ "Nebula",
511
+ "Comet",
512
+ "Pulse",
513
+ "Vertex",
514
+ "Flux",
515
+ "Storm",
516
+ "Blaze",
517
+ "Frost",
518
+ "Thunder",
519
+ "Drift"
520
+ ];
521
+ function generateUniqueSessionName() {
522
+ return `${SESSION_ADJECTIVES[Math.floor(Math.random() * SESSION_ADJECTIVES.length)]} ${SESSION_NOUNS[Math.floor(Math.random() * SESSION_NOUNS.length)]}`;
523
+ }
258
524
  /**
259
525
  * Browser file/blob storage built on top of Syncore web persistence.
260
526
  */
@@ -304,6 +570,6 @@ function normalizeBinary(data) {
304
570
  return new Uint8Array(data);
305
571
  }
306
572
  //#endregion
307
- export { BrowserFileStorageAdapter, SyncoreIndexedDbPersistence, SyncoreOpfsPersistence, SyncoreWebWorkerClient, attachWebWorkerRuntime, createBrowserSyncoreClient, createBrowserSyncoreRuntime, createBrowserWebSocketDevtoolsSink, createBrowserWorkerRuntime, createManagedWebWorkerClient, createSyncoreWebWorkerClient, createWebPersistence, createWebSyncoreClient, createWebSyncoreRuntime, createWebWorkerClient, createWebWorkerRuntime, isOpfsAvailable };
573
+ export { BroadcastChannelExternalChangeSignal, BrowserFileStorageAdapter, SqlJsExternalChangeApplier, SyncoreIndexedDbPersistence, SyncoreOpfsPersistence, SyncoreWebWorkerClient, attachWebWorkerRuntime, createBrowserSyncoreClient, createBrowserSyncoreRuntime, createBrowserWebSocketDevtoolsSink, createBrowserWorkerRuntime, createDefaultSyncChannelName, createExpoWebExternalChangeSupport, createManagedWebWorkerClient, createSyncoreWebWorkerClient, createWebExternalChangeSupport, createWebPersistence, createWebSyncoreClient, createWebSyncoreRuntime, createWebWorkerClient, createWebWorkerRuntime, isOpfsAvailable };
308
574
 
309
575
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n type AnySyncoreSchema,\n createDevtoolsRequestHandler,\n type DevtoolsRequestHandler,\n type DevtoolsSink,\n SyncoreRuntime,\n type SchedulerOptions,\n type SyncoreCapabilities,\n type SyncoreExperimentalPlugin,\n type SyncoreRuntimeOptions,\n type SyncoreStorageAdapter,\n type StorageObject,\n type StorageWriteInput\n} from \"@syncore/core\";\nimport {\n type SyncoreDevtoolsMessage,\n type SyncoreDevtoolsRequest,\n type SyncoreDevtoolsSnapshot\n} from \"@syncore/devtools-protocol\";\nimport {\n createWebPersistence,\n type SyncoreWebPersistence,\n type WebPersistenceMode\n} from \"./persistence.js\";\nimport { SqlJsDriver } from \"./sqljs.js\";\nimport {\n attachWebWorkerRuntime,\n type SyncoreWorkerMessageEndpoint\n} from \"./worker.js\";\nexport * from \"./worker.js\";\nexport * from \"./persistence.js\";\nexport * from \"./indexeddb.js\";\nexport * from \"./opfs.js\";\n\nexport type WebSyncoreSchema = AnySyncoreSchema;\nexport type BrowserSyncoreSchema = WebSyncoreSchema;\n\n/**\n * Options for constructing a browser Syncore runtime.\n *\n * Use this when you want to host the full runtime in a browser tab or worker.\n */\nexport interface CreateWebRuntimeOptions {\n /** The schema for the local Syncore app. */\n schema: WebSyncoreSchema;\n\n /** The generated function registry for the local Syncore app. */\n functions: SyncoreRuntimeOptions<WebSyncoreSchema>[\"functions\"];\n\n /** Optional platform capabilities exposed to function handlers. */\n capabilities?: SyncoreCapabilities;\n\n /** Optional custom SQL driver. Defaults to SQL.js with local persistence. */\n driver?: SyncoreRuntimeOptions<WebSyncoreSchema>[\"driver\"];\n\n /** Optional custom file/blob storage adapter. */\n storage?: SyncoreStorageAdapter;\n\n /** Optional experimental plugins for runtime hooks. */\n experimentalPlugins?: Array<SyncoreExperimentalPlugin<WebSyncoreSchema>>;\n\n /** Optional explicit persistence implementation. */\n persistence?: SyncoreWebPersistence;\n\n /** Which browser persistence mode to use when Syncore creates one for you. */\n persistenceMode?: WebPersistenceMode;\n\n /** Logical database name for SQL.js and local storage namespaces. */\n databaseName?: string;\n\n /** Optional IndexedDB database name for persistence metadata. */\n persistenceDatabaseName?: string;\n\n /** Optional OPFS directory name for persistent files. */\n opfsRootDirectoryName?: string;\n\n /** Optional namespace for file/blob storage. */\n storageNamespace?: string;\n\n /** Optional direct wasm URL for SQL.js. */\n wasmUrl?: string;\n\n /** Optional callback for resolving SQL.js support files. */\n locateFile?: (fileName: string) => string;\n\n /** Optional runtime platform label shown in devtools snapshots. */\n platform?: string;\n\n /** Optional devtools sink used during development. */\n devtools?: DevtoolsSink | false;\n\n /** Optional scheduler configuration for jobs and recurring work. */\n scheduler?: SchedulerOptions;\n}\n\n/**\n * Options for hosting a Syncore runtime inside a browser Worker.\n */\nexport interface CreateWebWorkerRuntimeOptions extends CreateWebRuntimeOptions {\n /** The message endpoint exposed by the current worker global. */\n endpoint: SyncoreWorkerMessageEndpoint;\n}\n\n/**\n * Options for constructing a browser Syncore runtime.\n */\nexport type CreateBrowserRuntimeOptions = CreateWebRuntimeOptions;\n\n/**\n * Options for hosting a Syncore runtime inside a browser Worker.\n */\nexport type CreateBrowserWorkerRuntimeOptions = CreateWebWorkerRuntimeOptions;\n\n/**\n * Create a full Syncore runtime directly in the browser.\n *\n * Most React apps should use a worker runtime instead so queries and SQLite work\n * stay off the main thread.\n */\nexport async function createWebSyncoreRuntime(\n options: CreateWebRuntimeOptions\n): Promise<SyncoreRuntime<WebSyncoreSchema>> {\n const persistence =\n options.persistence ??\n (await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName:\n options.opfsRootDirectoryName ?? options.databaseName ?? \"syncore\"\n }));\n const driver =\n options.driver ??\n (await SqlJsDriver.create({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n ...(options.wasmUrl ? { wasmUrl: options.wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n }));\n const storage =\n options.storage ??\n new BrowserFileStorageAdapter(\n persistence,\n options.storageNamespace ?? options.databaseName ?? \"syncore\"\n );\n const appName = resolveWebAppName();\n const origin = resolveWebOrigin();\n const sessionLabel = resolveWebSessionLabel();\n const autoDevtools =\n options.devtools === undefined && shouldAutoConnectDevtools()\n ? (() => {\n const sinkOptions: BrowserWebSocketDevtoolsSinkOptions = {\n url: resolveDefaultDevtoolsUrl()\n };\n if (appName) {\n sinkOptions.appName = appName;\n }\n if (origin) {\n sinkOptions.origin = origin;\n }\n if (sessionLabel) {\n sinkOptions.sessionLabel = sessionLabel;\n }\n return createBrowserWebSocketDevtoolsSink(sinkOptions);\n })()\n : undefined;\n const resolvedDevtools =\n options.devtools === false ? undefined : (options.devtools ?? autoDevtools);\n\n const runtime = new SyncoreRuntime({\n schema: options.schema,\n functions: options.functions,\n driver,\n storage,\n platform: options.platform ?? \"browser\",\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n ...(resolvedDevtools ? { devtools: resolvedDevtools } : {}),\n ...(options.experimentalPlugins\n ? { experimentalPlugins: options.experimentalPlugins }\n : {}),\n ...(options.scheduler ? { scheduler: options.scheduler } : {})\n });\n\n if (autoDevtools) {\n autoDevtools.attachRuntime(() => runtime.getDevtoolsSnapshot());\n autoDevtools.attachRequestHandler(\n createDevtoolsRequestHandler({\n driver,\n schema: options.schema,\n functions: options.functions,\n runtime\n })\n );\n }\n\n return runtime;\n}\n\n/**\n * Attach a Syncore runtime to a browser Worker endpoint.\n */\nexport function createWebWorkerRuntime(options: CreateWebWorkerRuntimeOptions) {\n return attachWebWorkerRuntime({\n endpoint: options.endpoint,\n createRuntime: () => createWebSyncoreRuntime(options)\n });\n}\n\n/**\n * Attach a Syncore runtime to a browser Worker endpoint.\n */\nexport function createBrowserWorkerRuntime(\n options: CreateBrowserWorkerRuntimeOptions\n) {\n return createWebWorkerRuntime(options);\n}\n\n/**\n * Create a client directly from a browser Syncore runtime.\n */\nexport function createWebSyncoreClient(\n runtime: SyncoreRuntime<WebSyncoreSchema>\n) {\n return runtime.createClient();\n}\n\n/**\n * Create a full Syncore runtime directly in the browser.\n */\nexport function createBrowserSyncoreRuntime(\n options: CreateBrowserRuntimeOptions\n) {\n return createWebSyncoreRuntime(options);\n}\n\n/**\n * Create a client directly from a browser Syncore runtime.\n */\nexport function createBrowserSyncoreClient(\n runtime: SyncoreRuntime<BrowserSyncoreSchema>\n) {\n return createWebSyncoreClient(runtime);\n}\n\nexport interface BrowserWebSocketDevtoolsSinkOptions {\n url: string;\n reconnectDelayMs?: number;\n appName?: string;\n origin?: string;\n sessionLabel?: string;\n}\n\nexport interface BrowserWebSocketDevtoolsSink extends DevtoolsSink {\n attachRuntime(getSnapshot: () => SyncoreDevtoolsSnapshot): void;\n attachRequestHandler(handler: DevtoolsRequestHandler): void;\n dispose(): void;\n}\n\nexport function createBrowserWebSocketDevtoolsSink(\n options: BrowserWebSocketDevtoolsSinkOptions\n): BrowserWebSocketDevtoolsSink {\n let socket: WebSocket | undefined;\n let disposed = false;\n let connectTimer: ReturnType<typeof setTimeout> | undefined;\n let getSnapshot: (() => SyncoreDevtoolsSnapshot) | undefined;\n let onRequest: DevtoolsRequestHandler | undefined;\n const pendingMessages: SyncoreDevtoolsMessage[] = [];\n let latestHello:\n | {\n runtimeId: string;\n platform: string;\n }\n | undefined;\n\n const connect = () => {\n if (disposed || typeof WebSocket === \"undefined\") {\n return;\n }\n socket = new WebSocket(options.url);\n socket.onopen = () => {\n if (latestHello) {\n sendNow({\n type: \"hello\",\n runtimeId: latestHello.runtimeId,\n platform: latestHello.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {})\n });\n }\n if (getSnapshot) {\n sendNow({\n type: \"snapshot\",\n snapshot: withSnapshotMeta(getSnapshot(), options)\n });\n }\n flushPendingMessages();\n };\n socket.onmessage = (event) => {\n if (typeof event.data !== \"string\") {\n return;\n }\n const message = JSON.parse(event.data) as\n | SyncoreDevtoolsMessage\n | SyncoreDevtoolsRequest;\n if (message.type === \"ping\") {\n send({ type: \"pong\" });\n } else if (message.type === \"request\" && onRequest) {\n onRequest(message.payload)\n .then((responsePayload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSnapshot?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"response\",\n requestId: message.requestId,\n runtimeId,\n payload: responsePayload\n });\n })\n .catch((err) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSnapshot?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"response\",\n requestId: message.requestId,\n runtimeId,\n payload: {\n kind: \"error\",\n message: err instanceof Error ? err.message : \"Unknown error\"\n }\n });\n });\n }\n };\n socket.onclose = scheduleReconnect;\n socket.onerror = () => {\n socket?.close();\n };\n };\n\n const scheduleReconnect = () => {\n if (disposed || connectTimer) {\n return;\n }\n connectTimer = setTimeout(() => {\n connectTimer = undefined;\n connect();\n }, options.reconnectDelayMs ?? 1200);\n };\n\n const sendNow = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify(message));\n }\n };\n\n const flushPendingMessages = () => {\n while (pendingMessages.length > 0) {\n const nextMessage = pendingMessages.shift();\n if (nextMessage) {\n sendNow(nextMessage);\n }\n }\n };\n\n const send = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n sendNow(message);\n return;\n }\n pendingMessages.push(message);\n };\n\n connect();\n\n return {\n emit(event) {\n if (event.type === \"runtime.connected\") {\n latestHello = {\n runtimeId: event.runtimeId,\n platform: event.platform\n };\n send({\n type: \"hello\",\n runtimeId: event.runtimeId,\n platform: event.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {})\n });\n }\n send({ type: \"event\", event });\n if (getSnapshot) {\n send({\n type: \"snapshot\",\n snapshot: withSnapshotMeta(getSnapshot(), options)\n });\n }\n },\n attachRuntime(snapshotGetter) {\n getSnapshot = snapshotGetter;\n if (socket?.readyState === WebSocket.OPEN) {\n send({\n type: \"snapshot\",\n snapshot: withSnapshotMeta(getSnapshot(), options)\n });\n }\n },\n attachRequestHandler(handler) {\n onRequest = handler;\n },\n dispose() {\n disposed = true;\n if (connectTimer) {\n clearTimeout(connectTimer);\n }\n socket?.close();\n }\n };\n}\n\nfunction withSnapshotMeta(\n snapshot: SyncoreDevtoolsSnapshot,\n options: BrowserWebSocketDevtoolsSinkOptions\n): SyncoreDevtoolsSnapshot {\n return {\n ...snapshot,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel ? { sessionLabel: options.sessionLabel } : {})\n };\n}\n\nfunction shouldAutoConnectDevtools(): boolean {\n if (typeof globalThis === \"undefined\") {\n return false;\n }\n try {\n return globalThis.location?.hostname === \"localhost\" ||\n globalThis.location?.hostname === \"127.0.0.1\"\n ? true\n : Boolean(globalThis.location?.hostname?.endsWith?.(\".local\"));\n } catch {\n return false;\n }\n}\n\nfunction resolveDefaultDevtoolsUrl(): string {\n return \"ws://127.0.0.1:4311\";\n}\n\nfunction resolveWebOrigin(): string | undefined {\n try {\n return globalThis.location?.origin;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebAppName(): string | undefined {\n try {\n return (\n globalThis.location?.hostname ?? globalThis.document?.title ?? undefined\n );\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebSessionLabel(): string | undefined {\n try {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n return navigator.userAgent.includes(\"Firefox\")\n ? \"Firefox\"\n : navigator.userAgent.includes(\"Chrome\")\n ? \"Chrome\"\n : navigator.userAgent.includes(\"Safari\")\n ? \"Safari\"\n : navigator.userAgent;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Browser file/blob storage built on top of Syncore web persistence.\n */\nexport class BrowserFileStorageAdapter implements SyncoreStorageAdapter {\n constructor(\n private readonly persistence: SyncoreWebPersistence,\n private readonly namespace: string\n ) {}\n\n async put(id: string, input: StorageWriteInput): Promise<StorageObject> {\n const bytes = normalizeBinary(input.data);\n await this.persistence.putFile(\n this.namespace,\n id,\n bytes,\n input.contentType ?? null\n );\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: bytes.byteLength,\n contentType: input.contentType ?? null\n };\n }\n\n async get(id: string): Promise<StorageObject | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n if (!file) {\n return null;\n }\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: file.size,\n contentType: file.contentType\n };\n }\n\n async read(id: string): Promise<Uint8Array | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n return file?.bytes ?? null;\n }\n\n async delete(id: string): Promise<void> {\n await this.persistence.deleteFile(this.namespace, id);\n }\n\n async list(): Promise<StorageObject[]> {\n const files = await this.persistence.listFiles(this.namespace);\n return files.map((file) => ({\n id: file.id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${file.id}`,\n size: file.size,\n contentType: file.contentType\n }));\n }\n}\n\nfunction normalizeBinary(data: StorageWriteInput[\"data\"]): Uint8Array {\n if (typeof data === \"string\") {\n return new TextEncoder().encode(data);\n }\n if (data instanceof Uint8Array) {\n return data;\n }\n return new Uint8Array(data);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import {\n type AnySyncoreSchema,\n createDevtoolsCommandHandler,\n createDevtoolsSubscriptionHost,\n type DevtoolsCommandHandler,\n type DevtoolsSink,\n type DevtoolsSubscriptionHost,\n SyncoreRuntime,\n type SchedulerOptions,\n type SyncoreCapabilities,\n type SyncoreExperimentalPlugin,\n type SyncoreRuntimeOptions,\n type SyncoreStorageAdapter,\n type StorageObject,\n type StorageWriteInput\n} from \"@syncore/core\";\nimport {\n type SyncoreDevtoolsClientMessage,\n type SyncoreDevtoolsMessage,\n type SyncoreRuntimeSummary\n} from \"@syncore/devtools-protocol\";\nimport {\n createWebPersistence,\n type SyncoreWebPersistence,\n type WebPersistenceMode\n} from \"./persistence.js\";\nimport {\n BroadcastChannelExternalChangeSignal,\n createDefaultSyncChannelName,\n SqlJsExternalChangeApplier\n} from \"./external-change.js\";\nimport { SqlJsDriver } from \"./sqljs.js\";\nimport {\n attachWebWorkerRuntime,\n type SyncoreWorkerMessageEndpoint\n} from \"./worker.js\";\nexport * from \"./worker.js\";\nexport * from \"./persistence.js\";\nexport * from \"./indexeddb.js\";\nexport * from \"./opfs.js\";\nexport * from \"./external-change.js\";\n\nexport type WebSyncoreSchema = AnySyncoreSchema;\nexport type BrowserSyncoreSchema = WebSyncoreSchema;\n\n/**\n * Options for constructing a browser Syncore runtime.\n *\n * Use this when you want to host the full runtime in a browser tab or worker.\n */\nexport interface CreateWebRuntimeOptions {\n /** The schema for the local Syncore app. */\n schema: WebSyncoreSchema;\n\n /** The generated function registry for the local Syncore app. */\n functions: SyncoreRuntimeOptions<WebSyncoreSchema>[\"functions\"];\n\n /** Optional platform capabilities exposed to function handlers. */\n capabilities?: SyncoreCapabilities;\n\n /** Optional custom SQL driver. Defaults to SQL.js with local persistence. */\n driver?: SyncoreRuntimeOptions<WebSyncoreSchema>[\"driver\"];\n\n /** Optional custom file/blob storage adapter. */\n storage?: SyncoreStorageAdapter;\n\n /** Optional experimental plugins for runtime hooks. */\n experimentalPlugins?: Array<SyncoreExperimentalPlugin<WebSyncoreSchema>>;\n\n /** Optional explicit persistence implementation. */\n persistence?: SyncoreWebPersistence;\n\n /** Which browser persistence mode to use when Syncore creates one for you. */\n persistenceMode?: WebPersistenceMode;\n\n /** Logical database name for SQL.js and local storage namespaces. */\n databaseName?: string;\n\n /** Optional IndexedDB database name for persistence metadata. */\n persistenceDatabaseName?: string;\n\n /** Optional OPFS directory name for persistent files. */\n opfsRootDirectoryName?: string;\n\n /** Optional namespace for file/blob storage. */\n storageNamespace?: string;\n\n /** Optional direct wasm URL for SQL.js. */\n wasmUrl?: string;\n\n /** Optional callback for resolving SQL.js support files. */\n locateFile?: (fileName: string) => string;\n\n /** Optional runtime platform label shown in devtools snapshots. */\n platform?: string;\n\n /** Optional devtools sink used during development. */\n devtools?: DevtoolsSink | false;\n\n /** Optional scheduler configuration for jobs and recurring work. */\n scheduler?: SchedulerOptions;\n}\n\n/**\n * Options for hosting a Syncore runtime inside a browser Worker.\n */\nexport interface CreateWebWorkerRuntimeOptions extends CreateWebRuntimeOptions {\n /** The message endpoint exposed by the current worker global. */\n endpoint: SyncoreWorkerMessageEndpoint;\n}\n\n/**\n * Options for constructing a browser Syncore runtime.\n */\nexport type CreateBrowserRuntimeOptions = CreateWebRuntimeOptions;\n\n/**\n * Options for hosting a Syncore runtime inside a browser Worker.\n */\nexport type CreateBrowserWorkerRuntimeOptions = CreateWebWorkerRuntimeOptions;\n\nexport interface WebExternalChangeSupport {\n signal: BroadcastChannelExternalChangeSignal;\n applier?: SqlJsExternalChangeApplier;\n}\n\n/**\n * Create a full Syncore runtime directly in the browser.\n *\n * Most React apps should use a worker runtime instead so queries and SQLite work\n * stay off the main thread.\n */\nexport async function createWebSyncoreRuntime(\n options: CreateWebRuntimeOptions\n): Promise<SyncoreRuntime<WebSyncoreSchema>> {\n const persistence =\n options.persistence ??\n (await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName:\n options.opfsRootDirectoryName ?? options.databaseName ?? \"syncore\"\n }));\n const driver =\n options.driver ??\n (await SqlJsDriver.create({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n ...(options.wasmUrl ? { wasmUrl: options.wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n }));\n const storage =\n options.storage ??\n new BrowserFileStorageAdapter(\n persistence,\n options.storageNamespace ?? options.databaseName ?? \"syncore\"\n );\n const externalChangeSupport = createWebExternalChangeSupport({\n databaseName: options.databaseName ?? \"syncore\",\n persistence,\n driver\n });\n const appName = resolveWebAppName();\n const origin = resolveWebOrigin();\n const sessionLabel = resolveWebSessionLabel();\n const databaseLabel = options.databaseName ?? \"syncore\";\n const storageIdentity = [\n origin ?? \"unknown-origin\",\n persistence.storageProtocol,\n databaseLabel\n ].join(\"::\");\n const autoDevtools =\n options.devtools === undefined && shouldAutoConnectDevtools()\n ? (() => {\n const sinkOptions: BrowserWebSocketDevtoolsSinkOptions = {\n url: resolveDefaultDevtoolsUrl(),\n targetKind: \"client\",\n storageProtocol: persistence.storageProtocol,\n databaseLabel,\n storageIdentity\n };\n if (appName) {\n sinkOptions.appName = appName;\n }\n if (origin) {\n sinkOptions.origin = origin;\n }\n if (sessionLabel) {\n sinkOptions.sessionLabel = sessionLabel;\n }\n return createBrowserWebSocketDevtoolsSink(sinkOptions);\n })()\n : undefined;\n const resolvedDevtools =\n options.devtools === false ? undefined : (options.devtools ?? autoDevtools);\n\n announceBrowserSession({\n enabled: resolvedDevtools !== undefined,\n sessionLabel,\n appName,\n origin,\n devtoolsUrl:\n options.devtools && typeof options.devtools === \"object\"\n ? undefined\n : resolveDefaultDevtoolsUrl()\n });\n\n const runtime = new SyncoreRuntime({\n schema: options.schema,\n functions: options.functions,\n driver,\n storage,\n externalChangeSignal: externalChangeSupport.signal,\n ...(externalChangeSupport.applier\n ? { externalChangeApplier: externalChangeSupport.applier }\n : {}),\n platform: options.platform ?? \"browser\",\n ...(options.capabilities ? { capabilities: options.capabilities } : {}),\n ...(resolvedDevtools ? { devtools: resolvedDevtools } : {}),\n ...(options.experimentalPlugins\n ? { experimentalPlugins: options.experimentalPlugins }\n : {}),\n ...(options.scheduler ? { scheduler: options.scheduler } : {})\n });\n\n if (autoDevtools) {\n autoDevtools.attachRuntime(runtime);\n autoDevtools.attachCommandHandler(\n createDevtoolsCommandHandler({\n driver,\n schema: options.schema,\n functions: options.functions,\n runtime\n })\n );\n autoDevtools.attachSubscriptionHost(\n createDevtoolsSubscriptionHost({\n driver,\n schema: options.schema,\n functions: options.functions,\n runtime\n })\n );\n }\n\n return runtime;\n}\n\nexport function createWebExternalChangeSupport(options: {\n databaseName: string;\n persistence: SyncoreWebPersistence;\n driver: CreateWebRuntimeOptions[\"driver\"] | undefined;\n}): WebExternalChangeSupport {\n const signal = new BroadcastChannelExternalChangeSignal({\n channelName: createDefaultSyncChannelName(options.databaseName)\n });\n const sqlDriver =\n options.driver instanceof SqlJsDriver ? options.driver : undefined;\n\n if (!sqlDriver) {\n return { signal };\n }\n\n return {\n signal,\n applier: new SqlJsExternalChangeApplier({\n databaseName: options.databaseName,\n persistence: options.persistence,\n createDatabase: (bytes) => sqlDriver.createDatabaseFromBytes(bytes),\n replaceDatabase: (database) => {\n sqlDriver.replaceDatabase(database);\n }\n })\n };\n}\n\nexport async function createExpoWebExternalChangeSupport(options: {\n databaseName: string;\n locateFile?: (fileName: string) => string;\n wasmUrl?: string;\n persistenceDatabaseName?: string;\n opfsRootDirectoryName?: string;\n persistenceMode?: WebPersistenceMode;\n}): Promise<WebExternalChangeSupport> {\n const persistence = await createWebPersistence({\n ...(options.persistenceMode ? { mode: options.persistenceMode } : {}),\n ...(options.persistenceDatabaseName\n ? { indexedDbDatabaseName: options.persistenceDatabaseName }\n : {}),\n opfsRootDirectoryName: options.opfsRootDirectoryName ?? options.databaseName\n });\n const driver = await SqlJsDriver.create({\n databaseName: options.databaseName,\n persistence,\n ...(options.wasmUrl ? { wasmUrl: options.wasmUrl } : {}),\n ...(options.locateFile ? { locateFile: options.locateFile } : {})\n });\n\n return createWebExternalChangeSupport({\n databaseName: options.databaseName,\n persistence,\n driver\n });\n}\n\n/**\n * Attach a Syncore runtime to a browser Worker endpoint.\n */\nexport function createWebWorkerRuntime(options: CreateWebWorkerRuntimeOptions) {\n return attachWebWorkerRuntime({\n endpoint: options.endpoint,\n createRuntime: () => createWebSyncoreRuntime(options)\n });\n}\n\n/**\n * Attach a Syncore runtime to a browser Worker endpoint.\n */\nexport function createBrowserWorkerRuntime(\n options: CreateBrowserWorkerRuntimeOptions\n) {\n return createWebWorkerRuntime(options);\n}\n\n/**\n * Create a client directly from a browser Syncore runtime.\n */\nexport function createWebSyncoreClient(\n runtime: SyncoreRuntime<WebSyncoreSchema>\n) {\n return runtime.createClient();\n}\n\n/**\n * Create a full Syncore runtime directly in the browser.\n */\nexport function createBrowserSyncoreRuntime(\n options: CreateBrowserRuntimeOptions\n) {\n return createWebSyncoreRuntime(options);\n}\n\n/**\n * Create a client directly from a browser Syncore runtime.\n */\nexport function createBrowserSyncoreClient(\n runtime: SyncoreRuntime<BrowserSyncoreSchema>\n) {\n return createWebSyncoreClient(runtime);\n}\n\nexport interface BrowserWebSocketDevtoolsSinkOptions {\n url: string;\n reconnectDelayMs?: number;\n appName?: string;\n origin?: string;\n sessionLabel?: string;\n targetKind?: \"client\";\n storageProtocol?: string;\n databaseLabel?: string;\n storageIdentity?: string;\n}\n\nexport interface BrowserWebSocketDevtoolsSink extends DevtoolsSink {\n attachRuntime(runtime: SyncoreRuntime<AnySyncoreSchema>): void;\n attachCommandHandler(handler: DevtoolsCommandHandler): void;\n attachSubscriptionHost(host: DevtoolsSubscriptionHost): void;\n dispose(): void;\n}\n\nexport function createBrowserWebSocketDevtoolsSink(\n options: BrowserWebSocketDevtoolsSinkOptions\n): BrowserWebSocketDevtoolsSink {\n let socket: WebSocket | undefined;\n let disposed = false;\n let connectTimer: ReturnType<typeof setTimeout> | undefined;\n let getSummary: (() => SyncoreRuntimeSummary) | undefined;\n let onCommand: DevtoolsCommandHandler | undefined;\n let subscriptionHost: DevtoolsSubscriptionHost | undefined;\n const pendingMessages: SyncoreDevtoolsMessage[] = [];\n let latestHello:\n | {\n runtimeId: string;\n platform: string;\n }\n | undefined;\n\n const connect = () => {\n if (disposed || typeof WebSocket === \"undefined\") {\n return;\n }\n socket = new WebSocket(options.url);\n socket.onopen = () => {\n if (latestHello) {\n sendNow({\n type: \"hello\",\n runtimeId: latestHello.runtimeId,\n platform: latestHello.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {})\n });\n }\n flushPendingMessages();\n };\n socket.onmessage = (event) => {\n if (typeof event.data !== \"string\") {\n return;\n }\n const message = JSON.parse(event.data) as\n | SyncoreDevtoolsMessage\n | SyncoreDevtoolsClientMessage;\n if (message.type === \"ping\") {\n send({ type: \"pong\" });\n } else if (message.type === \"command\" && onCommand) {\n onCommand(message.payload)\n .then((responsePayload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"command.result\",\n commandId: message.commandId,\n runtimeId,\n payload: responsePayload\n });\n })\n .catch((err) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"command.result\",\n commandId: message.commandId,\n runtimeId,\n payload: {\n kind: \"error\",\n message: err instanceof Error ? err.message : \"Unknown error\"\n }\n });\n });\n } else if (message.type === \"subscribe\" && subscriptionHost) {\n void subscriptionHost.subscribe(\n message.subscriptionId,\n message.payload,\n (payload) => {\n const runtimeId =\n latestHello?.runtimeId ?? getSummary?.().runtimeId;\n if (!runtimeId) {\n return;\n }\n send({\n type: \"subscription.data\",\n subscriptionId: message.subscriptionId,\n runtimeId,\n payload\n });\n }\n );\n } else if (message.type === \"unsubscribe\") {\n subscriptionHost?.unsubscribe(message.subscriptionId);\n }\n };\n socket.onclose = scheduleReconnect;\n socket.onerror = () => {\n socket?.close();\n };\n };\n\n const scheduleReconnect = () => {\n if (disposed || connectTimer) {\n return;\n }\n connectTimer = setTimeout(() => {\n connectTimer = undefined;\n connect();\n }, options.reconnectDelayMs ?? 1200);\n };\n\n const sendNow = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n socket.send(JSON.stringify(message));\n }\n };\n\n const flushPendingMessages = () => {\n while (pendingMessages.length > 0) {\n const nextMessage = pendingMessages.shift();\n if (nextMessage) {\n sendNow(nextMessage);\n }\n }\n };\n\n const send = (message: SyncoreDevtoolsMessage) => {\n if (socket?.readyState === WebSocket.OPEN) {\n sendNow(message);\n return;\n }\n pendingMessages.push(message);\n };\n\n connect();\n\n return {\n emit(event) {\n if (event.type === \"runtime.connected\") {\n latestHello = {\n runtimeId: event.runtimeId,\n platform: event.platform\n };\n send({\n type: \"hello\",\n runtimeId: event.runtimeId,\n platform: event.platform,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel\n ? { sessionLabel: options.sessionLabel }\n : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {})\n });\n }\n send({ type: \"event\", event });\n },\n attachRuntime(runtime) {\n getSummary = () =>\n withRuntimeSummaryMeta(runtime.getRuntimeSummary(), options);\n },\n attachCommandHandler(handler) {\n onCommand = handler;\n },\n attachSubscriptionHost(host) {\n subscriptionHost = host;\n },\n dispose() {\n disposed = true;\n if (connectTimer) {\n clearTimeout(connectTimer);\n }\n subscriptionHost?.dispose();\n socket?.close();\n }\n };\n}\n\nfunction withRuntimeSummaryMeta(\n summary: SyncoreRuntimeSummary,\n options: BrowserWebSocketDevtoolsSinkOptions\n): SyncoreRuntimeSummary {\n return {\n ...summary,\n ...(options.appName ? { appName: options.appName } : {}),\n ...(options.origin ? { origin: options.origin } : {}),\n ...(options.sessionLabel ? { sessionLabel: options.sessionLabel } : {}),\n ...(options.targetKind ? { targetKind: options.targetKind } : {}),\n ...(options.storageProtocol\n ? { storageProtocol: options.storageProtocol }\n : {}),\n ...(options.databaseLabel ? { databaseLabel: options.databaseLabel } : {}),\n ...(options.storageIdentity\n ? { storageIdentity: options.storageIdentity }\n : {})\n };\n}\n\nfunction shouldAutoConnectDevtools(): boolean {\n const hostname = resolveWebHostname();\n if (!hostname) {\n return false;\n }\n return (\n hostname === \"localhost\" ||\n isPrivateNetworkHostname(hostname) ||\n hostname.endsWith(\".local\")\n );\n}\n\nfunction resolveDefaultDevtoolsUrl(): string {\n return \"ws://127.0.0.1:4311\";\n}\n\nfunction resolveLocationString(\n key: \"href\" | \"origin\" | \"hostname\"\n): string | undefined {\n try {\n const value = globalThis.location?.[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveGlobalOrigin(): string | undefined {\n try {\n const value = (globalThis as { origin?: unknown }).origin;\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction parseUrlCandidate(candidate: string | undefined): URL | undefined {\n if (!candidate || candidate === \"null\") {\n return undefined;\n }\n try {\n const parsed = new URL(candidate);\n if (parsed.protocol === \"blob:\" && parsed.pathname.length > 0) {\n try {\n return new URL(parsed.pathname);\n } catch {\n return parsed;\n }\n }\n return parsed;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebHostname(): string | undefined {\n const directHostname = resolveLocationString(\"hostname\");\n if (directHostname) {\n return directHostname;\n }\n return (\n parseUrlCandidate(resolveLocationString(\"href\"))?.hostname ||\n parseUrlCandidate(resolveLocationString(\"origin\"))?.hostname ||\n parseUrlCandidate(resolveGlobalOrigin())?.hostname ||\n undefined\n );\n}\n\nfunction isPrivateNetworkHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (normalized === \"::1\") {\n return true;\n }\n if (normalized.startsWith(\"fc\") || normalized.startsWith(\"fd\")) {\n return true;\n }\n const match = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(normalized);\n if (!match) {\n return false;\n }\n const octets = match.slice(1).map((part) => Number(part));\n if (octets.some((part) => Number.isNaN(part) || part < 0 || part > 255)) {\n return false;\n }\n const first = octets[0];\n const second = octets[1];\n if (first === undefined || second === undefined) {\n return false;\n }\n return (\n first === 10 ||\n first === 127 ||\n (first === 169 && second === 254) ||\n (first === 172 && second >= 16 && second <= 31) ||\n (first === 192 && second === 168)\n );\n}\n\nfunction resolveWebOrigin(): string | undefined {\n const directOrigin = resolveLocationString(\"origin\");\n if (directOrigin && directOrigin !== \"null\") {\n return directOrigin;\n }\n const parsedOrigin =\n parseUrlCandidate(resolveLocationString(\"href\"))?.origin ||\n parseUrlCandidate(resolveGlobalOrigin())?.origin;\n return parsedOrigin && parsedOrigin !== \"null\" ? parsedOrigin : undefined;\n}\n\nfunction resolveWebAppName(): string | undefined {\n try {\n return resolveWebHostname() ?? globalThis.document?.title ?? undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveWebSessionLabel(): string | undefined {\n try {\n if (typeof navigator === \"undefined\") {\n return undefined;\n }\n\n // Generate or retrieve a persistent unique name for this browser instance.\n // This makes it much easier to identify which browser tab/window you're\n // looking at in the devtools dashboard.\n const STORAGE_KEY = \"syncore-session-name\";\n let uniqueName: string | null = null;\n\n try {\n uniqueName = globalThis.localStorage?.getItem(STORAGE_KEY) ?? null;\n } catch {\n /* localStorage may not be available */\n }\n\n if (!uniqueName) {\n uniqueName = generateUniqueSessionName();\n\n try {\n globalThis.localStorage?.setItem(STORAGE_KEY, uniqueName);\n } catch {\n /* ignore storage errors */\n }\n }\n\n // Detect browser type for additional context\n const browser = navigator.userAgent.includes(\"Firefox\")\n ? \"Firefox\"\n : navigator.userAgent.includes(\"Chrome\")\n ? \"Chrome\"\n : navigator.userAgent.includes(\"Safari\")\n ? \"Safari\"\n : \"Browser\";\n\n return `${uniqueName} (${browser})`;\n } catch {\n return undefined;\n }\n}\n\nfunction announceBrowserSession(options: {\n enabled: boolean;\n sessionLabel?: string | undefined;\n appName?: string | undefined;\n origin?: string | undefined;\n devtoolsUrl?: string | undefined;\n}): void {\n if (!options.enabled || !options.sessionLabel) {\n return;\n }\n\n const announcedSessions = getAnnouncedBrowserSessions();\n if (announcedSessions.has(options.sessionLabel)) {\n return;\n }\n announcedSessions.add(options.sessionLabel);\n\n try {\n const details = [\n options.appName ? `app=${options.appName}` : undefined,\n options.origin ? `origin=${options.origin}` : undefined,\n options.devtoolsUrl ? `devtools=${options.devtoolsUrl}` : undefined\n ].filter((value): value is string => value !== undefined);\n\n console.info(\n `[syncore] Browser session: ${options.sessionLabel}${details.length > 0 ? ` (${details.join(\", \")})` : \"\"}`\n );\n } catch {\n /* ignore console failures */\n }\n}\n\nfunction getAnnouncedBrowserSessions(): Set<string> {\n const key = \"__syncoreAnnouncedBrowserSessions\";\n const scope = globalThis as typeof globalThis & {\n [key]?: Set<string>;\n };\n if (!scope[key]) {\n scope[key] = new Set<string>();\n }\n return scope[key];\n}\n\n/* ------------------------------------------------------------------ */\n/* Unique session name generator */\n/* ------------------------------------------------------------------ */\n\nconst SESSION_ADJECTIVES = [\n \"Acrobatic\",\n \"Bold\",\n \"Cosmic\",\n \"Daring\",\n \"Electric\",\n \"Fierce\",\n \"Golden\",\n \"Hidden\",\n \"Iron\",\n \"Jade\",\n \"Keen\",\n \"Lunar\",\n \"Mystic\",\n \"Noble\",\n \"Orbital\",\n \"Primal\",\n \"Quick\",\n \"Radiant\",\n \"Shadow\",\n \"Turbo\",\n \"Ultra\",\n \"Vivid\",\n \"Wicked\",\n \"Xenon\",\n \"Zen\",\n \"Arctic\",\n \"Binary\",\n \"Cyber\",\n \"Digital\",\n \"Ember\",\n \"Frozen\",\n \"Galactic\",\n \"Hyper\",\n \"Infra\",\n \"Jumbo\",\n \"Kinetic\",\n \"Liquid\",\n \"Magnetic\",\n \"Neon\",\n \"Onyx\",\n \"Phantom\",\n \"Quantum\",\n \"Rapid\",\n \"Sonic\",\n \"Titan\",\n \"Velvet\",\n \"Wild\",\n \"Blazing\",\n \"Crystal\",\n \"Dynamic\"\n] as const;\n\nconst SESSION_NOUNS = [\n \"Monkey\",\n \"Phoenix\",\n \"Tiger\",\n \"Dragon\",\n \"Falcon\",\n \"Panther\",\n \"Wolf\",\n \"Eagle\",\n \"Cobra\",\n \"Shark\",\n \"Raven\",\n \"Fox\",\n \"Lynx\",\n \"Hawk\",\n \"Bear\",\n \"Jaguar\",\n \"Viper\",\n \"Owl\",\n \"Stallion\",\n \"Dolphin\",\n \"Developer\",\n \"Hacker\",\n \"Wizard\",\n \"Ninja\",\n \"Pilot\",\n \"Pioneer\",\n \"Voyager\",\n \"Explorer\",\n \"Runner\",\n \"Ranger\",\n \"Maverick\",\n \"Spartan\",\n \"Viking\",\n \"Sentinel\",\n \"Guardian\",\n \"Nomad\",\n \"Cipher\",\n \"Vector\",\n \"Matrix\",\n \"Prism\",\n \"Nebula\",\n \"Comet\",\n \"Pulse\",\n \"Vertex\",\n \"Flux\",\n \"Storm\",\n \"Blaze\",\n \"Frost\",\n \"Thunder\",\n \"Drift\"\n] as const;\n\nfunction generateUniqueSessionName(): string {\n const adj =\n SESSION_ADJECTIVES[Math.floor(Math.random() * SESSION_ADJECTIVES.length)]!;\n const noun = SESSION_NOUNS[Math.floor(Math.random() * SESSION_NOUNS.length)]!;\n return `${adj} ${noun}`;\n}\n\n/**\n * Browser file/blob storage built on top of Syncore web persistence.\n */\nexport class BrowserFileStorageAdapter implements SyncoreStorageAdapter {\n constructor(\n private readonly persistence: SyncoreWebPersistence,\n private readonly namespace: string\n ) {}\n\n async put(id: string, input: StorageWriteInput): Promise<StorageObject> {\n const bytes = normalizeBinary(input.data);\n await this.persistence.putFile(\n this.namespace,\n id,\n bytes,\n input.contentType ?? null\n );\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: bytes.byteLength,\n contentType: input.contentType ?? null\n };\n }\n\n async get(id: string): Promise<StorageObject | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n if (!file) {\n return null;\n }\n return {\n id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${id}`,\n size: file.size,\n contentType: file.contentType\n };\n }\n\n async read(id: string): Promise<Uint8Array | null> {\n const file = await this.persistence.getFile(this.namespace, id);\n return file?.bytes ?? null;\n }\n\n async delete(id: string): Promise<void> {\n await this.persistence.deleteFile(this.namespace, id);\n }\n\n async list(): Promise<StorageObject[]> {\n const files = await this.persistence.listFiles(this.namespace);\n return files.map((file) => ({\n id: file.id,\n path: `${this.persistence.storageProtocol}://${this.namespace}/${file.id}`,\n size: file.size,\n contentType: file.contentType\n }));\n }\n}\n\nfunction normalizeBinary(data: StorageWriteInput[\"data\"]): Uint8Array {\n if (typeof data === \"string\") {\n return new TextEncoder().encode(data);\n }\n if (data instanceof Uint8Array) {\n return data;\n }\n return new Uint8Array(data);\n}\n"],"mappings":"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"}