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.
- package/dist/{core/src/cli.d.ts → _vendor/cli/app.d.mts} +4 -2
- package/dist/_vendor/cli/app.d.mts.map +1 -0
- package/dist/_vendor/cli/app.mjs +997 -0
- package/dist/_vendor/cli/app.mjs.map +1 -0
- package/dist/_vendor/cli/context.mjs +180 -0
- package/dist/_vendor/cli/context.mjs.map +1 -0
- package/dist/_vendor/cli/dev-session.mjs +49 -0
- package/dist/_vendor/cli/dev-session.mjs.map +1 -0
- package/dist/_vendor/cli/doctor.mjs +80 -0
- package/dist/_vendor/cli/doctor.mjs.map +1 -0
- package/dist/_vendor/cli/errors.mjs +22 -0
- package/dist/_vendor/cli/errors.mjs.map +1 -0
- package/dist/_vendor/cli/help.mjs +26 -0
- package/dist/_vendor/cli/help.mjs.map +1 -0
- package/dist/_vendor/cli/index.d.mts +2 -0
- package/dist/_vendor/cli/index.mjs +23 -0
- package/dist/_vendor/cli/index.mjs.map +1 -0
- package/dist/_vendor/cli/messages.mjs +32 -0
- package/dist/_vendor/cli/messages.mjs.map +1 -0
- package/dist/_vendor/cli/preflight.mjs +35 -0
- package/dist/_vendor/cli/preflight.mjs.map +1 -0
- package/dist/_vendor/cli/project.mjs +583 -0
- package/dist/_vendor/cli/project.mjs.map +1 -0
- package/dist/_vendor/cli/render.mjs +133 -0
- package/dist/_vendor/cli/render.mjs.map +1 -0
- package/dist/_vendor/cli/targets.mjs +87 -0
- package/dist/_vendor/cli/targets.mjs.map +1 -0
- package/dist/_vendor/core/cli.d.mts +59 -1
- package/dist/_vendor/core/cli.d.mts.map +1 -1
- package/dist/_vendor/core/cli.mjs +528 -75
- package/dist/_vendor/core/cli.mjs.map +1 -1
- package/dist/_vendor/core/index.d.mts +12 -4
- package/dist/_vendor/core/index.d.mts.map +1 -0
- package/dist/_vendor/core/index.mjs +4 -3
- package/dist/_vendor/core/index.mjs.map +1 -1
- package/dist/_vendor/core/runtime/devtools.d.mts +32 -6
- package/dist/_vendor/core/runtime/devtools.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/devtools.mjs +397 -182
- package/dist/_vendor/core/runtime/devtools.mjs.map +1 -1
- package/dist/_vendor/core/runtime/functions.mjs.map +1 -1
- package/dist/_vendor/core/runtime/runtime.d.mts +89 -7
- package/dist/_vendor/core/runtime/runtime.d.mts.map +1 -1
- package/dist/_vendor/core/runtime/runtime.mjs +303 -32
- package/dist/_vendor/core/runtime/runtime.mjs.map +1 -1
- package/dist/_vendor/devtools-protocol/index.d.ts +189 -82
- package/dist/_vendor/devtools-protocol/index.d.ts.map +1 -1
- package/dist/_vendor/devtools-protocol/index.js +39 -0
- package/dist/_vendor/devtools-protocol/index.js.map +1 -0
- package/dist/_vendor/next/config.d.ts.map +1 -1
- package/dist/_vendor/next/config.js +2 -5
- package/dist/_vendor/next/config.js.map +1 -1
- package/dist/_vendor/platform-expo/index.d.ts +15 -5
- package/dist/_vendor/platform-expo/index.d.ts.map +1 -1
- package/dist/_vendor/platform-expo/index.js +33 -3
- package/dist/_vendor/platform-expo/index.js.map +1 -1
- package/dist/_vendor/platform-expo/react.js.map +1 -1
- package/dist/_vendor/platform-node/index.d.mts +10 -5
- package/dist/_vendor/platform-node/index.d.mts.map +1 -1
- package/dist/_vendor/platform-node/index.mjs +145 -35
- package/dist/_vendor/platform-node/index.mjs.map +1 -1
- package/dist/_vendor/platform-node/ipc-react.mjs.map +1 -1
- package/dist/_vendor/platform-web/external-change.d.ts +39 -0
- package/dist/_vendor/platform-web/external-change.d.ts.map +1 -0
- package/dist/_vendor/platform-web/external-change.js +61 -0
- package/dist/_vendor/platform-web/external-change.js.map +1 -0
- package/dist/_vendor/platform-web/index.d.ts +27 -5
- package/dist/_vendor/platform-web/index.d.ts.map +1 -1
- package/dist/_vendor/platform-web/index.js +310 -44
- package/dist/_vendor/platform-web/index.js.map +1 -1
- package/dist/_vendor/platform-web/indexeddb.js.map +1 -1
- package/dist/_vendor/platform-web/opfs.js.map +1 -1
- package/dist/_vendor/platform-web/persistence.js.map +1 -1
- package/dist/_vendor/platform-web/react.js.map +1 -1
- package/dist/_vendor/platform-web/sqljs.js +22 -2
- package/dist/_vendor/platform-web/sqljs.js.map +1 -1
- package/dist/_vendor/schema/definition.js.map +1 -1
- package/dist/_vendor/schema/planner.js.map +1 -1
- package/dist/_vendor/schema/validators.js.map +1 -1
- package/dist/browser-react.d.ts +1 -1
- package/dist/browser-react.js +1 -1
- package/dist/browser.d.ts +6 -7
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +4 -5
- package/dist/browser.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +12 -3
- package/dist/cli.js.map +1 -1
- package/dist/expo-react.d.ts +1 -1
- package/dist/expo-react.js +1 -1
- package/dist/expo.d.ts +1 -2
- package/dist/expo.js +1 -2
- package/dist/index.d.ts +3 -7
- package/dist/index.js +3 -8
- package/dist/next-config.d.ts +1 -2
- package/dist/next-config.js +1 -2
- package/dist/next.d.ts +1 -3
- package/dist/next.js +1 -3
- package/dist/node-ipc-react.d.ts +1 -1
- package/dist/node-ipc-react.js +1 -1
- package/dist/node-ipc.d.ts +1 -2
- package/dist/node-ipc.js +1 -2
- package/dist/node.d.ts +1 -4
- package/dist/node.js +1 -3
- package/dist/react.d.ts +1 -2
- package/dist/react.js +1 -2
- package/dist/svelte.d.ts +1 -2
- package/dist/svelte.js +1 -2
- package/package.json +6 -3
- package/dist/core/src/cli.d.ts.map +0 -1
- package/dist/core/src/cli.js +0 -1196
- package/dist/core/src/cli.js.map +0 -1
- package/dist/core/src/index.js +0 -7
- package/dist/core/src/runtime/devtools.d.ts +0 -7
- package/dist/core/src/runtime/devtools.d.ts.map +0 -1
- package/dist/core/src/runtime/devtools.js +0 -300
- package/dist/core/src/runtime/devtools.js.map +0 -1
- package/dist/core/src/runtime/functions.d.ts +0 -123
- package/dist/core/src/runtime/functions.d.ts.map +0 -1
- package/dist/core/src/runtime/functions.js +0 -71
- package/dist/core/src/runtime/functions.js.map +0 -1
- package/dist/core/src/runtime/id.d.ts +0 -13
- package/dist/core/src/runtime/id.d.ts.map +0 -1
- package/dist/core/src/runtime/id.js +0 -28
- package/dist/core/src/runtime/id.js.map +0 -1
- package/dist/core/src/runtime/runtime.d.ts +0 -371
- package/dist/core/src/runtime/runtime.d.ts.map +0 -1
- package/dist/core/src/runtime/runtime.js +0 -1143
- package/dist/core/src/runtime/runtime.js.map +0 -1
- package/dist/devtools-protocol/src/index.d.ts +0 -201
- package/dist/devtools-protocol/src/index.d.ts.map +0 -1
- package/dist/next/src/config.d.ts +0 -17
- package/dist/next/src/config.d.ts.map +0 -1
- package/dist/next/src/config.js +0 -73
- package/dist/next/src/config.js.map +0 -1
- package/dist/next/src/index.d.ts +0 -80
- package/dist/next/src/index.d.ts.map +0 -1
- package/dist/next/src/index.js +0 -82
- package/dist/next/src/index.js.map +0 -1
- package/dist/platform-expo/src/index.d.ts +0 -96
- package/dist/platform-expo/src/index.d.ts.map +0 -1
- package/dist/platform-expo/src/index.js +0 -198
- package/dist/platform-expo/src/index.js.map +0 -1
- package/dist/platform-expo/src/react.d.ts +0 -26
- package/dist/platform-expo/src/react.d.ts.map +0 -1
- package/dist/platform-expo/src/react.js +0 -30
- package/dist/platform-expo/src/react.js.map +0 -1
- package/dist/platform-node/src/index.d.ts +0 -145
- package/dist/platform-node/src/index.d.ts.map +0 -1
- package/dist/platform-node/src/index.js +0 -407
- package/dist/platform-node/src/index.js.map +0 -1
- package/dist/platform-node/src/ipc-react.d.ts +0 -25
- package/dist/platform-node/src/ipc-react.d.ts.map +0 -1
- package/dist/platform-node/src/ipc-react.js +0 -21
- package/dist/platform-node/src/ipc-react.js.map +0 -1
- package/dist/platform-node/src/ipc.d.ts +0 -76
- package/dist/platform-node/src/ipc.d.ts.map +0 -1
- package/dist/platform-node/src/ipc.js +0 -344
- package/dist/platform-node/src/ipc.js.map +0 -1
- package/dist/platform-web/src/index.d.ts +0 -106
- package/dist/platform-web/src/index.d.ts.map +0 -1
- package/dist/platform-web/src/index.js +0 -311
- package/dist/platform-web/src/index.js.map +0 -1
- package/dist/platform-web/src/indexeddb.js +0 -125
- package/dist/platform-web/src/indexeddb.js.map +0 -1
- package/dist/platform-web/src/opfs.js +0 -146
- package/dist/platform-web/src/opfs.js.map +0 -1
- package/dist/platform-web/src/persistence.d.ts +0 -20
- package/dist/platform-web/src/persistence.d.ts.map +0 -1
- package/dist/platform-web/src/persistence.js +0 -23
- package/dist/platform-web/src/persistence.js.map +0 -1
- package/dist/platform-web/src/react.d.ts +0 -35
- package/dist/platform-web/src/react.d.ts.map +0 -1
- package/dist/platform-web/src/react.js +0 -42
- package/dist/platform-web/src/react.js.map +0 -1
- package/dist/platform-web/src/sqljs.js +0 -133
- package/dist/platform-web/src/sqljs.js.map +0 -1
- package/dist/platform-web/src/worker.d.ts +0 -79
- package/dist/platform-web/src/worker.d.ts.map +0 -1
- package/dist/platform-web/src/worker.js +0 -308
- package/dist/platform-web/src/worker.js.map +0 -1
- package/dist/react/src/index.d.ts +0 -59
- package/dist/react/src/index.d.ts.map +0 -1
- package/dist/react/src/index.js +0 -151
- package/dist/react/src/index.js.map +0 -1
- package/dist/schema/src/definition.d.ts +0 -98
- package/dist/schema/src/definition.d.ts.map +0 -1
- package/dist/schema/src/definition.js +0 -84
- package/dist/schema/src/definition.js.map +0 -1
- package/dist/schema/src/planner.d.ts +0 -42
- package/dist/schema/src/planner.d.ts.map +0 -1
- package/dist/schema/src/planner.js +0 -131
- package/dist/schema/src/planner.js.map +0 -1
- package/dist/schema/src/validators.d.ts +0 -194
- package/dist/schema/src/validators.d.ts.map +0 -1
- package/dist/schema/src/validators.js +0 -158
- package/dist/schema/src/validators.js.map +0 -1
- package/dist/svelte/src/index.d.ts +0 -44
- package/dist/svelte/src/index.d.ts.map +0 -1
- package/dist/svelte/src/index.js +0 -75
- 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,
|
|
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 = {
|
|
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(
|
|
51
|
-
autoDevtools.
|
|
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
|
|
98
|
-
let
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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 === "
|
|
124
|
-
const runtimeId = latestHello?.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: "
|
|
128
|
-
|
|
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 ??
|
|
201
|
+
const runtimeId = latestHello?.runtimeId ?? getSummary?.().runtimeId;
|
|
134
202
|
if (!runtimeId) return;
|
|
135
203
|
send({
|
|
136
|
-
type: "
|
|
137
|
-
|
|
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(
|
|
201
|
-
|
|
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
|
-
|
|
208
|
-
|
|
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
|
|
296
|
+
function withRuntimeSummaryMeta(summary, options) {
|
|
218
297
|
return {
|
|
219
|
-
...
|
|
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
|
-
|
|
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
|
-
|
|
318
|
+
const value = globalThis.location?.[key];
|
|
319
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
229
320
|
} catch {
|
|
230
|
-
return
|
|
321
|
+
return;
|
|
231
322
|
}
|
|
232
323
|
}
|
|
233
|
-
function
|
|
234
|
-
|
|
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
|
|
332
|
+
function parseUrlCandidate(candidate) {
|
|
333
|
+
if (!candidate || candidate === "null") return;
|
|
237
334
|
try {
|
|
238
|
-
|
|
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
|
|
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
|
-
|
|
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":";;;;;;;;;;;;;AAuHA,eAAsB,wBACpB,SAC2C;CAC3C,MAAM,cACJ,QAAQ,eACP,MAAM,qBAAqB;EAC1B,GAAI,QAAQ,kBAAkB,EAAE,MAAM,QAAQ,iBAAiB,GAAG,EAAE;EACpE,GAAI,QAAQ,0BACR,EAAE,uBAAuB,QAAQ,yBAAyB,GAC1D,EAAE;EACN,uBACE,QAAQ,yBAAyB,QAAQ,gBAAgB;EAC5D,CAAC;CACJ,MAAM,SACJ,QAAQ,UACP,MAAM,YAAY,OAAO;EACxB,cAAc,QAAQ,gBAAgB;EACtC;EACA,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;EACvD,GAAI,QAAQ,aAAa,EAAE,YAAY,QAAQ,YAAY,GAAG,EAAE;EACjE,CAAC;CACJ,MAAM,UACJ,QAAQ,WACR,IAAI,0BACF,aACA,QAAQ,oBAAoB,QAAQ,gBAAgB,UACrD;CACH,MAAM,UAAU,mBAAmB;CACnC,MAAM,SAAS,kBAAkB;CACjC,MAAM,eAAe,wBAAwB;CAC7C,MAAM,eACJ,QAAQ,aAAa,KAAA,KAAa,2BAA2B,UAClD;EACL,MAAM,cAAmD,EACvD,KAAK,2BAA2B,EACjC;AACD,MAAI,QACF,aAAY,UAAU;AAExB,MAAI,OACF,aAAY,SAAS;AAEvB,MAAI,aACF,aAAY,eAAe;AAE7B,SAAO,mCAAmC,YAAY;KACpD,GACJ,KAAA;CACN,MAAM,mBACJ,QAAQ,aAAa,QAAQ,KAAA,IAAa,QAAQ,YAAY;CAEhE,MAAM,UAAU,IAAI,eAAe;EACjC,QAAQ,QAAQ;EAChB,WAAW,QAAQ;EACnB;EACA;EACA,UAAU,QAAQ,YAAY;EAC9B,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,cAAc,GAAG,EAAE;EACtE,GAAI,mBAAmB,EAAE,UAAU,kBAAkB,GAAG,EAAE;EAC1D,GAAI,QAAQ,sBACR,EAAE,qBAAqB,QAAQ,qBAAqB,GACpD,EAAE;EACN,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,WAAW,GAAG,EAAE;EAC9D,CAAC;AAEF,KAAI,cAAc;AAChB,eAAa,oBAAoB,QAAQ,qBAAqB,CAAC;AAC/D,eAAa,qBACX,6BAA6B;GAC3B;GACA,QAAQ,QAAQ;GAChB,WAAW,QAAQ;GACnB;GACD,CAAC,CACH;;AAGH,QAAO;;;;;AAMT,SAAgB,uBAAuB,SAAwC;AAC7E,QAAO,uBAAuB;EAC5B,UAAU,QAAQ;EAClB,qBAAqB,wBAAwB,QAAQ;EACtD,CAAC;;;;;AAMJ,SAAgB,2BACd,SACA;AACA,QAAO,uBAAuB,QAAQ;;;;;AAMxC,SAAgB,uBACd,SACA;AACA,QAAO,QAAQ,cAAc;;;;;AAM/B,SAAgB,4BACd,SACA;AACA,QAAO,wBAAwB,QAAQ;;;;;AAMzC,SAAgB,2BACd,SACA;AACA,QAAO,uBAAuB,QAAQ;;AAiBxC,SAAgB,mCACd,SAC8B;CAC9B,IAAI;CACJ,IAAI,WAAW;CACf,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM,kBAA4C,EAAE;CACpD,IAAI;CAOJ,MAAM,gBAAgB;AACpB,MAAI,YAAY,OAAO,cAAc,YACnC;AAEF,WAAS,IAAI,UAAU,QAAQ,IAAI;AACnC,SAAO,eAAe;AACpB,OAAI,YACF,SAAQ;IACN,MAAM;IACN,WAAW,YAAY;IACvB,UAAU,YAAY;IACtB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;IACvD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;IACpD,GAAI,QAAQ,eACR,EAAE,cAAc,QAAQ,cAAc,GACtC,EAAE;IACP,CAAC;AAEJ,OAAI,YACF,SAAQ;IACN,MAAM;IACN,UAAU,iBAAiB,aAAa,EAAE,QAAQ;IACnD,CAAC;AAEJ,yBAAsB;;AAExB,SAAO,aAAa,UAAU;AAC5B,OAAI,OAAO,MAAM,SAAS,SACxB;GAEF,MAAM,UAAU,KAAK,MAAM,MAAM,KAAK;AAGtC,OAAI,QAAQ,SAAS,OACnB,MAAK,EAAE,MAAM,QAAQ,CAAC;YACb,QAAQ,SAAS,aAAa,UACvC,WAAU,QAAQ,QAAQ,CACvB,MAAM,oBAAoB;IACzB,MAAM,YACJ,aAAa,aAAa,eAAe,CAAC;AAC5C,QAAI,CAAC,UACH;AAEF,SAAK;KACH,MAAM;KACN,WAAW,QAAQ;KACnB;KACA,SAAS;KACV,CAAC;KACF,CACD,OAAO,QAAQ;IACd,MAAM,YACJ,aAAa,aAAa,eAAe,CAAC;AAC5C,QAAI,CAAC,UACH;AAEF,SAAK;KACH,MAAM;KACN,WAAW,QAAQ;KACnB;KACA,SAAS;MACP,MAAM;MACN,SAAS,eAAe,QAAQ,IAAI,UAAU;MAC/C;KACF,CAAC;KACF;;AAGR,SAAO,UAAU;AACjB,SAAO,gBAAgB;AACrB,WAAQ,OAAO;;;CAInB,MAAM,0BAA0B;AAC9B,MAAI,YAAY,aACd;AAEF,iBAAe,iBAAiB;AAC9B,kBAAe,KAAA;AACf,YAAS;KACR,QAAQ,oBAAoB,KAAK;;CAGtC,MAAM,WAAW,YAAoC;AACnD,MAAI,QAAQ,eAAe,UAAU,KACnC,QAAO,KAAK,KAAK,UAAU,QAAQ,CAAC;;CAIxC,MAAM,6BAA6B;AACjC,SAAO,gBAAgB,SAAS,GAAG;GACjC,MAAM,cAAc,gBAAgB,OAAO;AAC3C,OAAI,YACF,SAAQ,YAAY;;;CAK1B,MAAM,QAAQ,YAAoC;AAChD,MAAI,QAAQ,eAAe,UAAU,MAAM;AACzC,WAAQ,QAAQ;AAChB;;AAEF,kBAAgB,KAAK,QAAQ;;AAG/B,UAAS;AAET,QAAO;EACL,KAAK,OAAO;AACV,OAAI,MAAM,SAAS,qBAAqB;AACtC,kBAAc;KACZ,WAAW,MAAM;KACjB,UAAU,MAAM;KACjB;AACD,SAAK;KACH,MAAM;KACN,WAAW,MAAM;KACjB,UAAU,MAAM;KAChB,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;KACvD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;KACpD,GAAI,QAAQ,eACR,EAAE,cAAc,QAAQ,cAAc,GACtC,EAAE;KACP,CAAC;;AAEJ,QAAK;IAAE,MAAM;IAAS;IAAO,CAAC;AAC9B,OAAI,YACF,MAAK;IACH,MAAM;IACN,UAAU,iBAAiB,aAAa,EAAE,QAAQ;IACnD,CAAC;;EAGN,cAAc,gBAAgB;AAC5B,iBAAc;AACd,OAAI,QAAQ,eAAe,UAAU,KACnC,MAAK;IACH,MAAM;IACN,UAAU,iBAAiB,aAAa,EAAE,QAAQ;IACnD,CAAC;;EAGN,qBAAqB,SAAS;AAC5B,eAAY;;EAEd,UAAU;AACR,cAAW;AACX,OAAI,aACF,cAAa,aAAa;AAE5B,WAAQ,OAAO;;EAElB;;AAGH,SAAS,iBACP,UACA,SACyB;AACzB,QAAO;EACL,GAAG;EACH,GAAI,QAAQ,UAAU,EAAE,SAAS,QAAQ,SAAS,GAAG,EAAE;EACvD,GAAI,QAAQ,SAAS,EAAE,QAAQ,QAAQ,QAAQ,GAAG,EAAE;EACpD,GAAI,QAAQ,eAAe,EAAE,cAAc,QAAQ,cAAc,GAAG,EAAE;EACvE;;AAGH,SAAS,4BAAqC;AAC5C,KAAI,OAAO,eAAe,YACxB,QAAO;AAET,KAAI;AACF,SAAO,WAAW,UAAU,aAAa,eACvC,WAAW,UAAU,aAAa,cAChC,OACA,QAAQ,WAAW,UAAU,UAAU,WAAW,SAAS,CAAC;SAC1D;AACN,SAAO;;;AAIX,SAAS,4BAAoC;AAC3C,QAAO;;AAGT,SAAS,mBAAuC;AAC9C,KAAI;AACF,SAAO,WAAW,UAAU;SACtB;AACN;;;AAIJ,SAAS,oBAAwC;AAC/C,KAAI;AACF,SACE,WAAW,UAAU,YAAY,WAAW,UAAU,SAAS,KAAA;SAE3D;AACN;;;AAIJ,SAAS,yBAA6C;AACpD,KAAI;AACF,MAAI,OAAO,cAAc,YACvB;AAEF,SAAO,UAAU,UAAU,SAAS,UAAU,GAC1C,YACA,UAAU,UAAU,SAAS,SAAS,GACpC,WACA,UAAU,UAAU,SAAS,SAAS,GACpC,WACA,UAAU;SACZ;AACN;;;;;;AAOJ,IAAa,4BAAb,MAAwE;CACtE,YACE,aACA,WACA;AAFiB,OAAA,cAAA;AACA,OAAA,YAAA;;CAGnB,MAAM,IAAI,IAAY,OAAkD;EACtE,MAAM,QAAQ,gBAAgB,MAAM,KAAK;AACzC,QAAM,KAAK,YAAY,QACrB,KAAK,WACL,IACA,OACA,MAAM,eAAe,KACtB;AACD,SAAO;GACL;GACA,MAAM,GAAG,KAAK,YAAY,gBAAgB,KAAK,KAAK,UAAU,GAAG;GACjE,MAAM,MAAM;GACZ,aAAa,MAAM,eAAe;GACnC;;CAGH,MAAM,IAAI,IAA2C;EACnD,MAAM,OAAO,MAAM,KAAK,YAAY,QAAQ,KAAK,WAAW,GAAG;AAC/D,MAAI,CAAC,KACH,QAAO;AAET,SAAO;GACL;GACA,MAAM,GAAG,KAAK,YAAY,gBAAgB,KAAK,KAAK,UAAU,GAAG;GACjE,MAAM,KAAK;GACX,aAAa,KAAK;GACnB;;CAGH,MAAM,KAAK,IAAwC;AAEjD,UADa,MAAM,KAAK,YAAY,QAAQ,KAAK,WAAW,GAAG,GAClD,SAAS;;CAGxB,MAAM,OAAO,IAA2B;AACtC,QAAM,KAAK,YAAY,WAAW,KAAK,WAAW,GAAG;;CAGvD,MAAM,OAAiC;AAErC,UADc,MAAM,KAAK,YAAY,UAAU,KAAK,UAAU,EACjD,KAAK,UAAU;GAC1B,IAAI,KAAK;GACT,MAAM,GAAG,KAAK,YAAY,gBAAgB,KAAK,KAAK,UAAU,GAAG,KAAK;GACtE,MAAM,KAAK;GACX,aAAa,KAAK;GACnB,EAAE;;;AAIP,SAAS,gBAAgB,MAA6C;AACpE,KAAI,OAAO,SAAS,SAClB,QAAO,IAAI,aAAa,CAAC,OAAO,KAAK;AAEvC,KAAI,gBAAgB,WAClB,QAAO;AAET,QAAO,IAAI,WAAW,KAAK"}
|
|
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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"}
|