@livestore/adapter-web 0.4.0-dev.2 → 0.4.0-dev.21
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/.tsbuildinfo +1 -1
- package/dist/in-memory/in-memory-adapter.d.ts +49 -5
- package/dist/in-memory/in-memory-adapter.d.ts.map +1 -1
- package/dist/in-memory/in-memory-adapter.js +69 -16
- package/dist/in-memory/in-memory-adapter.js.map +1 -1
- package/dist/web-worker/client-session/client-session-devtools.d.ts +1 -1
- package/dist/web-worker/client-session/client-session-devtools.d.ts.map +1 -1
- package/dist/web-worker/client-session/client-session-devtools.js +14 -3
- package/dist/web-worker/client-session/client-session-devtools.js.map +1 -1
- package/dist/web-worker/client-session/persisted-adapter.d.ts +15 -0
- package/dist/web-worker/client-session/persisted-adapter.d.ts.map +1 -1
- package/dist/web-worker/client-session/persisted-adapter.js +68 -46
- package/dist/web-worker/client-session/persisted-adapter.js.map +1 -1
- package/dist/web-worker/client-session/sqlite-loader.d.ts +2 -0
- package/dist/web-worker/client-session/sqlite-loader.d.ts.map +1 -0
- package/dist/web-worker/client-session/sqlite-loader.js +16 -0
- package/dist/web-worker/client-session/sqlite-loader.js.map +1 -0
- package/dist/web-worker/common/persisted-sqlite.d.ts +23 -7
- package/dist/web-worker/common/persisted-sqlite.d.ts.map +1 -1
- package/dist/web-worker/common/persisted-sqlite.js +125 -76
- package/dist/web-worker/common/persisted-sqlite.js.map +1 -1
- package/dist/web-worker/common/shutdown-channel.d.ts +3 -2
- package/dist/web-worker/common/shutdown-channel.d.ts.map +1 -1
- package/dist/web-worker/common/shutdown-channel.js +2 -2
- package/dist/web-worker/common/shutdown-channel.js.map +1 -1
- package/dist/web-worker/common/worker-disconnect-channel.d.ts +2 -6
- package/dist/web-worker/common/worker-disconnect-channel.d.ts.map +1 -1
- package/dist/web-worker/common/worker-disconnect-channel.js +3 -2
- package/dist/web-worker/common/worker-disconnect-channel.js.map +1 -1
- package/dist/web-worker/common/worker-schema.d.ts +147 -56
- package/dist/web-worker/common/worker-schema.d.ts.map +1 -1
- package/dist/web-worker/common/worker-schema.js +55 -36
- package/dist/web-worker/common/worker-schema.js.map +1 -1
- package/dist/web-worker/leader-worker/make-leader-worker.d.ts +4 -2
- package/dist/web-worker/leader-worker/make-leader-worker.d.ts.map +1 -1
- package/dist/web-worker/leader-worker/make-leader-worker.js +63 -27
- package/dist/web-worker/leader-worker/make-leader-worker.js.map +1 -1
- package/dist/web-worker/shared-worker/make-shared-worker.d.ts +2 -1
- package/dist/web-worker/shared-worker/make-shared-worker.d.ts.map +1 -1
- package/dist/web-worker/shared-worker/make-shared-worker.js +66 -49
- package/dist/web-worker/shared-worker/make-shared-worker.js.map +1 -1
- package/dist/web-worker/vite-dev-polyfill.js +1 -0
- package/dist/web-worker/vite-dev-polyfill.js.map +1 -1
- package/package.json +8 -9
- package/src/in-memory/in-memory-adapter.ts +83 -21
- package/src/web-worker/ambient.d.ts +7 -24
- package/src/web-worker/client-session/client-session-devtools.ts +18 -3
- package/src/web-worker/client-session/persisted-adapter.ts +117 -59
- package/src/web-worker/client-session/sqlite-loader.ts +19 -0
- package/src/web-worker/common/persisted-sqlite.ts +225 -107
- package/src/web-worker/common/shutdown-channel.ts +10 -3
- package/src/web-worker/common/worker-disconnect-channel.ts +10 -3
- package/src/web-worker/common/worker-schema.ts +74 -35
- package/src/web-worker/leader-worker/make-leader-worker.ts +86 -41
- package/src/web-worker/shared-worker/make-shared-worker.ts +96 -75
- package/src/web-worker/vite-dev-polyfill.ts +1 -0
- package/dist/opfs-utils.d.ts +0 -5
- package/dist/opfs-utils.d.ts.map +0 -1
- package/dist/opfs-utils.js +0 -43
- package/dist/opfs-utils.js.map +0 -1
- package/src/opfs-utils.ts +0 -61
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { type Adapter, type SyncOptions,
|
|
1
|
+
import { type Adapter, type SyncOptions, UnknownError } from '@livestore/common';
|
|
2
2
|
import type { LiveStoreSchema } from '@livestore/common/schema';
|
|
3
3
|
import type * as WebmeshWorker from '@livestore/devtools-web-common/worker';
|
|
4
4
|
import type { MakeWebSqliteDb } from '@livestore/sqlite-wasm/browser';
|
|
5
|
-
import type
|
|
6
|
-
import { Fiber, Worker } from '@livestore/utils/effect';
|
|
5
|
+
import { Fiber, type Schema, Worker } from '@livestore/utils/effect';
|
|
7
6
|
export interface InMemoryAdapterOptions {
|
|
8
7
|
importSnapshot?: Uint8Array<ArrayBuffer>;
|
|
9
8
|
sync?: SyncOptions;
|
|
@@ -28,6 +27,50 @@ export interface InMemoryAdapterOptions {
|
|
|
28
27
|
}) => globalThis.SharedWorker);
|
|
29
28
|
};
|
|
30
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates a web-only in-memory LiveStore adapter.
|
|
32
|
+
*
|
|
33
|
+
* This adapter runs entirely in memory with no persistence. Ideal for:
|
|
34
|
+
* - Unit tests and integration tests
|
|
35
|
+
* - Sandboxes and demos
|
|
36
|
+
* - Ephemeral sessions where persistence isn't needed
|
|
37
|
+
*
|
|
38
|
+
* **Characteristics:**
|
|
39
|
+
* - Fast, zero I/O overhead
|
|
40
|
+
* - Works in all browser contexts: Window, WebWorker, SharedWorker, ServiceWorker
|
|
41
|
+
* - Supports optional sync backends for real-time collaboration
|
|
42
|
+
* - No data persists after page reload
|
|
43
|
+
*
|
|
44
|
+
* For persistent storage, use `makePersistedAdapter` instead.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { makeInMemoryAdapter } from '@livestore/adapter-web'
|
|
49
|
+
*
|
|
50
|
+
* const adapter = makeInMemoryAdapter()
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* // With sync backend for real-time collaboration
|
|
56
|
+
* import { makeInMemoryAdapter } from '@livestore/adapter-web'
|
|
57
|
+
* import { makeWsSync } from '@livestore/sync-cf/client'
|
|
58
|
+
*
|
|
59
|
+
* const adapter = makeInMemoryAdapter({
|
|
60
|
+
* sync: {
|
|
61
|
+
* backend: makeWsSync({ url: 'wss://api.example.com/sync' }),
|
|
62
|
+
* },
|
|
63
|
+
* })
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* // Pre-populate with existing data
|
|
69
|
+
* const adapter = makeInMemoryAdapter({
|
|
70
|
+
* importSnapshot: existingDbSnapshot,
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
31
74
|
export declare const makeInMemoryAdapter: (options?: InMemoryAdapterOptions) => Adapter;
|
|
32
75
|
export interface MakeLeaderThreadArgs {
|
|
33
76
|
schema: LiveStoreSchema;
|
|
@@ -35,11 +78,12 @@ export interface MakeLeaderThreadArgs {
|
|
|
35
78
|
clientId: string;
|
|
36
79
|
makeSqliteDb: MakeWebSqliteDb;
|
|
37
80
|
syncOptions: SyncOptions | undefined;
|
|
38
|
-
|
|
81
|
+
syncPayloadEncoded: Schema.JsonValue | undefined;
|
|
82
|
+
syncPayloadSchema: Schema.Schema<any> | undefined;
|
|
39
83
|
importSnapshot: Uint8Array<ArrayBuffer> | undefined;
|
|
40
84
|
devtoolsEnabled: boolean;
|
|
41
85
|
sharedWorkerFiber: SharedWorkerFiber | undefined;
|
|
42
86
|
}
|
|
43
|
-
type SharedWorkerFiber = Fiber.Fiber<Worker.SerializedWorkerPool<typeof WebmeshWorker.Schema.Request.Type>,
|
|
87
|
+
type SharedWorkerFiber = Fiber.Fiber<Worker.SerializedWorkerPool<typeof WebmeshWorker.Schema.Request.Type>, UnknownError>;
|
|
44
88
|
export {};
|
|
45
89
|
//# sourceMappingURL=in-memory-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-adapter.d.ts","sourceRoot":"","sources":["../../src/in-memory/in-memory-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAMZ,KAAK,WAAW,EAChB,
|
|
1
|
+
{"version":3,"file":"in-memory-adapter.d.ts","sourceRoot":"","sources":["../../src/in-memory/in-memory-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAMZ,KAAK,WAAW,EAChB,YAAY,EACb,MAAM,mBAAmB,CAAA;AAS1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAG/D,OAAO,KAAK,KAAK,aAAa,MAAM,uCAAuC,CAAA;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAIrE,OAAO,EAA2B,KAAK,EAAS,KAAK,MAAM,EAAmB,MAAM,EAAE,MAAM,yBAAyB,CAAA;AASrH,MAAM,WAAW,sBAAsB;IACrC,cAAc,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IACxC,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB,sGAAsG;IACtG,QAAQ,CAAC,EAAE;QACT,YAAY,EACR,CAAC,CAAC,OAAO,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,KAAK,UAAU,CAAC,YAAY,CAAC,GACxD,CAAC,KAAK,OAAO,EAAE;YACb,IAAI,EAAE,MAAM,CAAA;SACb,KAAK,UAAU,CAAC,YAAY,CAAC,CAAA;KACnC,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,eAAO,MAAM,mBAAmB,GAC7B,UAAS,sBAA2B,KAAG,OA+EwC,CAAA;AAElF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,eAAe,CAAA;IAC7B,WAAW,EAAE,WAAW,GAAG,SAAS,CAAA;IACpC,kBAAkB,EAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAA;IAChD,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;IACjD,cAAc,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,CAAA;IACnD,eAAe,EAAE,OAAO,CAAA;IACxB,iBAAiB,EAAE,iBAAiB,GAAG,SAAS,CAAA;CACjD;AAgGD,KAAK,iBAAiB,GAAG,KAAK,CAAC,KAAK,CAClC,MAAM,CAAC,oBAAoB,CAAC,OAAO,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EACrE,YAAY,CACb,CAAA"}
|
|
@@ -1,20 +1,63 @@
|
|
|
1
|
-
import { ClientSessionLeaderThreadProxy, Devtools, makeClientSession, migrateDb,
|
|
2
|
-
import { configureConnection, Eventlog, LeaderThreadCtx, makeLeaderThreadLayer } from '@livestore/common/leader-thread';
|
|
1
|
+
import { ClientSessionLeaderThreadProxy, Devtools, makeClientSession, migrateDb, UnknownError, } from '@livestore/common';
|
|
2
|
+
import { configureConnection, Eventlog, LeaderThreadCtx, makeLeaderThreadLayer, streamEventsWithSyncState, } from '@livestore/common/leader-thread';
|
|
3
3
|
import { LiveStoreEvent } from '@livestore/common/schema';
|
|
4
4
|
import * as DevtoolsWeb from '@livestore/devtools-web-common/web-channel';
|
|
5
5
|
import { sqliteDbFactory } from '@livestore/sqlite-wasm/browser';
|
|
6
|
-
import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm';
|
|
7
6
|
import { tryAsFunctionAndNew } from '@livestore/utils';
|
|
8
|
-
import {
|
|
7
|
+
import { Effect, FetchHttpClient, Fiber, Layer, SubscriptionRef, Worker } from '@livestore/utils/effect';
|
|
8
|
+
import { BrowserWorker } from '@livestore/utils/effect/browser';
|
|
9
9
|
import { nanoid } from '@livestore/utils/nanoid';
|
|
10
10
|
import * as Webmesh from '@livestore/webmesh';
|
|
11
11
|
import { connectWebmeshNodeClientSession } from "../web-worker/client-session/client-session-devtools.js";
|
|
12
|
+
import { loadSqlite3 } from "../web-worker/client-session/sqlite-loader.js";
|
|
12
13
|
import { makeShutdownChannel } from "../web-worker/common/shutdown-channel.js";
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Creates a web-only in-memory LiveStore adapter.
|
|
16
|
+
*
|
|
17
|
+
* This adapter runs entirely in memory with no persistence. Ideal for:
|
|
18
|
+
* - Unit tests and integration tests
|
|
19
|
+
* - Sandboxes and demos
|
|
20
|
+
* - Ephemeral sessions where persistence isn't needed
|
|
21
|
+
*
|
|
22
|
+
* **Characteristics:**
|
|
23
|
+
* - Fast, zero I/O overhead
|
|
24
|
+
* - Works in all browser contexts: Window, WebWorker, SharedWorker, ServiceWorker
|
|
25
|
+
* - Supports optional sync backends for real-time collaboration
|
|
26
|
+
* - No data persists after page reload
|
|
27
|
+
*
|
|
28
|
+
* For persistent storage, use `makePersistedAdapter` instead.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { makeInMemoryAdapter } from '@livestore/adapter-web'
|
|
33
|
+
*
|
|
34
|
+
* const adapter = makeInMemoryAdapter()
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // With sync backend for real-time collaboration
|
|
40
|
+
* import { makeInMemoryAdapter } from '@livestore/adapter-web'
|
|
41
|
+
* import { makeWsSync } from '@livestore/sync-cf/client'
|
|
42
|
+
*
|
|
43
|
+
* const adapter = makeInMemoryAdapter({
|
|
44
|
+
* sync: {
|
|
45
|
+
* backend: makeWsSync({ url: 'wss://api.example.com/sync' }),
|
|
46
|
+
* },
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* // Pre-populate with existing data
|
|
53
|
+
* const adapter = makeInMemoryAdapter({
|
|
54
|
+
* importSnapshot: existingDbSnapshot,
|
|
55
|
+
* })
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
15
58
|
export const makeInMemoryAdapter = (options = {}) => (adapterArgs) => Effect.gen(function* () {
|
|
16
|
-
const { schema, shutdown,
|
|
17
|
-
const sqlite3 = yield* Effect.promise(() =>
|
|
59
|
+
const { schema, shutdown, syncPayloadEncoded, syncPayloadSchema, storeId, devtoolsEnabled } = adapterArgs;
|
|
60
|
+
const sqlite3 = yield* Effect.promise(() => loadSqlite3());
|
|
18
61
|
const sqliteDb = yield* sqliteDbFactory({ sqlite3 })({ _tag: 'in-memory' });
|
|
19
62
|
const clientId = options.clientId ?? nanoid(6);
|
|
20
63
|
const sessionId = options.sessionId ?? nanoid(6);
|
|
@@ -27,7 +70,7 @@ export const makeInMemoryAdapter = (options = {}) => (adapterArgs) => Effect.gen
|
|
|
27
70
|
? yield* Worker.makePoolSerialized({
|
|
28
71
|
size: 1,
|
|
29
72
|
concurrency: 100,
|
|
30
|
-
}).pipe(Effect.provide(BrowserWorker.layer(() => sharedWebWorker)), Effect.tapCauseLogPretty,
|
|
73
|
+
}).pipe(Effect.provide(BrowserWorker.layer(() => sharedWebWorker)), Effect.tapCauseLogPretty, UnknownError.mapToUnknownError, Effect.forkScoped)
|
|
31
74
|
: undefined;
|
|
32
75
|
const { leaderThread, initialSnapshot } = yield* makeLeaderThread({
|
|
33
76
|
schema,
|
|
@@ -35,7 +78,8 @@ export const makeInMemoryAdapter = (options = {}) => (adapterArgs) => Effect.gen
|
|
|
35
78
|
clientId,
|
|
36
79
|
makeSqliteDb: sqliteDbFactory({ sqlite3 }),
|
|
37
80
|
syncOptions: options.sync,
|
|
38
|
-
|
|
81
|
+
syncPayloadEncoded,
|
|
82
|
+
syncPayloadSchema,
|
|
39
83
|
importSnapshot: options.importSnapshot,
|
|
40
84
|
devtoolsEnabled,
|
|
41
85
|
sharedWorkerFiber,
|
|
@@ -52,6 +96,8 @@ export const makeInMemoryAdapter = (options = {}) => (adapterArgs) => Effect.gen
|
|
|
52
96
|
lockStatus,
|
|
53
97
|
shutdown,
|
|
54
98
|
webmeshMode: 'direct',
|
|
99
|
+
// Can be undefined in Node.js
|
|
100
|
+
origin: globalThis.location?.origin,
|
|
55
101
|
connectWebmeshNode: ({ sessionInfo, webmeshNode }) => Effect.gen(function* () {
|
|
56
102
|
if (sharedWorkerFiber === undefined || devtoolsEnabled === false) {
|
|
57
103
|
return;
|
|
@@ -68,8 +114,8 @@ export const makeInMemoryAdapter = (options = {}) => (adapterArgs) => Effect.gen
|
|
|
68
114
|
},
|
|
69
115
|
});
|
|
70
116
|
return clientSession;
|
|
71
|
-
}).pipe(
|
|
72
|
-
const makeLeaderThread = ({ schema, storeId, clientId, makeSqliteDb, syncOptions,
|
|
117
|
+
}).pipe(UnknownError.mapToUnknownError, Effect.provide(FetchHttpClient.layer));
|
|
118
|
+
const makeLeaderThread = ({ schema, storeId, clientId, makeSqliteDb, syncOptions, syncPayloadEncoded, syncPayloadSchema, importSnapshot, devtoolsEnabled, sharedWorkerFiber, }) => Effect.gen(function* () {
|
|
73
119
|
const runtime = yield* Effect.runtime();
|
|
74
120
|
const makeDb = (_kind) => {
|
|
75
121
|
return makeSqliteDb({
|
|
@@ -102,21 +148,28 @@ const makeLeaderThread = ({ schema, storeId, clientId, makeSqliteDb, syncOptions
|
|
|
102
148
|
dbEventlog,
|
|
103
149
|
devtoolsOptions,
|
|
104
150
|
shutdownChannel,
|
|
105
|
-
|
|
151
|
+
syncPayloadEncoded,
|
|
152
|
+
syncPayloadSchema,
|
|
106
153
|
}));
|
|
107
154
|
return yield* Effect.gen(function* () {
|
|
108
|
-
const { dbState, dbEventlog, syncProcessor, extraIncomingMessagesQueue, initialState } = yield* LeaderThreadCtx;
|
|
155
|
+
const { dbState, dbEventlog, syncProcessor, extraIncomingMessagesQueue, initialState, networkStatus } = yield* LeaderThreadCtx;
|
|
109
156
|
const initialLeaderHead = Eventlog.getClientHeadFromDb(dbEventlog);
|
|
110
157
|
const leaderThread = ClientSessionLeaderThreadProxy.of({
|
|
111
158
|
events: {
|
|
112
159
|
pull: ({ cursor }) => syncProcessor.pull({ cursor }),
|
|
113
|
-
push: (batch) => syncProcessor.push(batch.map((item) => new LiveStoreEvent.EncodedWithMeta(item)), { waitForProcessing: true }),
|
|
160
|
+
push: (batch) => syncProcessor.push(batch.map((item) => new LiveStoreEvent.Client.EncodedWithMeta(item)), { waitForProcessing: true }),
|
|
161
|
+
stream: (options) => streamEventsWithSyncState({
|
|
162
|
+
dbEventlog,
|
|
163
|
+
syncState: syncProcessor.syncState,
|
|
164
|
+
options,
|
|
165
|
+
}),
|
|
114
166
|
},
|
|
115
167
|
initialState: { leaderHead: initialLeaderHead, migrationsReport: initialState.migrationsReport },
|
|
116
168
|
export: Effect.sync(() => dbState.export()),
|
|
117
169
|
getEventlogData: Effect.sync(() => dbEventlog.export()),
|
|
118
|
-
|
|
170
|
+
syncState: syncProcessor.syncState,
|
|
119
171
|
sendDevtoolsMessage: (message) => extraIncomingMessagesQueue.offer(message),
|
|
172
|
+
networkStatus,
|
|
120
173
|
});
|
|
121
174
|
const initialSnapshot = dbState.export();
|
|
122
175
|
return { leaderThread, initialSnapshot };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-adapter.js","sourceRoot":"","sources":["../../src/in-memory/in-memory-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,8BAA8B,EAC9B,QAAQ,EAER,iBAAiB,EACjB,SAAS,EAET,
|
|
1
|
+
{"version":3,"file":"in-memory-adapter.js","sourceRoot":"","sources":["../../src/in-memory/in-memory-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,5 +16,5 @@ export declare const connectWebmeshNodeClientSession: (args_0: {
|
|
|
16
16
|
sharedWorker: Worker.SerializedWorkerPool<typeof DevtoolsWeb.WorkerSchema.Request.Type>;
|
|
17
17
|
devtoolsEnabled: boolean;
|
|
18
18
|
schema: LiveStoreSchema;
|
|
19
|
-
}) => Effect.Effect<void, import("@livestore/common").
|
|
19
|
+
}) => Effect.Effect<void, import("@livestore/common").UnknownError, import("effect/Scope").Scope>;
|
|
20
20
|
//# sourceMappingURL=client-session-devtools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-session-devtools.d.ts","sourceRoot":"","sources":["../../../src/web-worker/client-session/client-session-devtools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"client-session-devtools.d.ts","sourceRoot":"","sources":["../../../src/web-worker/client-session/client-session-devtools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAoB,MAAM,mBAAmB,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,KAAK,WAAW,MAAM,4CAA4C,CAAA;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAE,MAAM,EAAU,MAAM,yBAAyB,CAAA;AAExD,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAA;AAE7C,eAAO,MAAM,cAAc,GAAI,2CAK5B;IACD,MAAM,EAAE,eAAe,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB,sCA8B0F,CAAA;AAE3F,eAAO,MAAM,+BAA+B;iBAO7B,OAAO,CAAC,QAAQ;iBAChB,QAAQ,CAAC,WAAW,CAAC,WAAW;kBAC/B,MAAM,CAAC,oBAAoB,CAAC,OAAO,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;qBACtE,OAAO;YAChB,eAAe;iGA4CvB,CAAA"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { Devtools } from '@livestore/common';
|
|
1
|
+
import { Devtools, liveStoreVersion } from '@livestore/common';
|
|
2
2
|
import * as DevtoolsWeb from '@livestore/devtools-web-common/web-channel';
|
|
3
3
|
import { isDevEnv } from '@livestore/utils';
|
|
4
|
-
import { Effect, Stream
|
|
4
|
+
import { Effect, Stream } from '@livestore/utils/effect';
|
|
5
|
+
import { WebChannelBrowser } from '@livestore/utils/effect/browser';
|
|
5
6
|
import * as Webmesh from '@livestore/webmesh';
|
|
6
7
|
export const logDevtoolsUrl = ({ schema, storeId, clientId, sessionId, }) => Effect.gen(function* () {
|
|
7
8
|
if (isDevEnv()) {
|
|
@@ -15,6 +16,16 @@ export const logDevtoolsUrl = ({ schema, storeId, clientId, sessionId, }) => Eff
|
|
|
15
16
|
const url = `${devtoolsBaseUrl}/web/${storeId}/${clientId}/${sessionId}/${schema.devtools.alias}`;
|
|
16
17
|
yield* Effect.log(`[@livestore/adapter-web] Devtools ready on ${url}`);
|
|
17
18
|
}
|
|
19
|
+
// Check for DevTools Chrome extension presence via iframe container the extension injects
|
|
20
|
+
const hasExt = document.querySelector('[id^="livestore-devtools-iframe-"]') !== null;
|
|
21
|
+
if (!hasExt) {
|
|
22
|
+
const g = globalThis;
|
|
23
|
+
if (g.__livestoreDevtoolsChromeNoticeShown !== true) {
|
|
24
|
+
g.__livestoreDevtoolsChromeNoticeShown = true;
|
|
25
|
+
const urlToLog = `https://github.com/livestorejs/livestore/releases/download/v${liveStoreVersion}/livestore-devtools-chrome-${liveStoreVersion}.zip`;
|
|
26
|
+
yield* Effect.log(`[@livestore/adapter-web] LiveStore DevTools Chrome extension not detected. Install v${liveStoreVersion}: ${urlToLog}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
18
29
|
}
|
|
19
30
|
}
|
|
20
31
|
}).pipe(Effect.withSpan('@livestore/adapter-web:client-session:devtools:logDevtoolsUrl'));
|
|
@@ -33,7 +44,7 @@ export const connectWebmeshNodeClientSession = Effect.fn(function* ({ webmeshNod
|
|
|
33
44
|
yield* clientSessionStaticChannel.send(DevtoolsWeb.ClientSessionContentscriptMainReq.make({ clientId, sessionId, storeId }));
|
|
34
45
|
const { tabId } = yield* clientSessionStaticChannel.listen.pipe(Stream.flatten(), Stream.runHead, Effect.flatten);
|
|
35
46
|
const contentscriptMainNodeName = DevtoolsWeb.makeNodeName.browserExtension.contentscriptMain(tabId);
|
|
36
|
-
const contentscriptMainChannel = yield*
|
|
47
|
+
const contentscriptMainChannel = yield* WebChannelBrowser.windowChannel({
|
|
37
48
|
listenWindow: window,
|
|
38
49
|
sendWindow: window,
|
|
39
50
|
schema: Webmesh.WebmeshSchema.Packet,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-session-devtools.js","sourceRoot":"","sources":["../../../src/web-worker/client-session/client-session-devtools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"client-session-devtools.js","sourceRoot":"","sources":["../../../src/web-worker/client-session/client-session-devtools.ts"],"names":[],"mappings":"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"}
|
|
@@ -54,6 +54,21 @@ export type WebAdapterOptions = {
|
|
|
54
54
|
* @default false
|
|
55
55
|
*/
|
|
56
56
|
disableFastPath?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Controls whether to wait for the shared worker to be terminated when LiveStore gets shut down.
|
|
59
|
+
* This prevents a race condition where a new LiveStore instance connects to a shutting-down shared
|
|
60
|
+
* worker from a previous instance.
|
|
61
|
+
*
|
|
62
|
+
* @default false
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
*
|
|
66
|
+
* In multi-tab scenarios, we don't want to await shared worker termination because the shared worker
|
|
67
|
+
* won't actually shut down when one tab closes - it stays alive to serve other tabs. Awaiting
|
|
68
|
+
* termination would cause unnecessary blocking since the termination will never happen until all
|
|
69
|
+
* tabs are closed.
|
|
70
|
+
*/
|
|
71
|
+
awaitSharedWorkerTermination?: boolean;
|
|
57
72
|
};
|
|
58
73
|
};
|
|
59
74
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persisted-adapter.d.ts","sourceRoot":"","sources":["../../../src/web-worker/client-session/persisted-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,mBAAmB,CAAA;
|
|
1
|
+
{"version":3,"file":"persisted-adapter.d.ts","sourceRoot":"","sources":["../../../src/web-worker/client-session/persisted-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,mBAAmB,CAAA;AAuC3E,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAA;AAW1D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,UAAU,CAAC,MAAM,CAAC,CAAA;IACnH;;;;;;;;;;;;;OAaG;IACH,YAAY,EACR,CAAC,CAAC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,UAAU,CAAC,YAAY,CAAC,GACxD,CAAC,KAAK,OAAO,EAAE;QACb,IAAI,EAAE,MAAM,CAAA;KACb,KAAK,UAAU,CAAC,YAAY,CAAC,CAAA;IAClC;;OAEG;IACH,OAAO,EAAE,YAAY,CAAC,kBAAkB,CAAA;IACxC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE;QACb;;;;;WAKG;QACH,eAAe,CAAC,EAAE,OAAO,CAAA;QACzB;;;;;;;;;;;;;WAaG;QACH,4BAA4B,CAAC,EAAE,OAAO,CAAA;KACvC,CAAA;CACF,CAAA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oBAAoB,GAC9B,SAAS,iBAAiB,KAAG,OA+Y8C,CAAA"}
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import { IntentionalShutdownCause, liveStoreVersion, makeClientSession, StoreInterrupted, sessionChangesetMetaTable,
|
|
1
|
+
import { IntentionalShutdownCause, liveStoreVersion, makeClientSession, StoreInterrupted, sessionChangesetMetaTable, UnknownError, } from '@livestore/common';
|
|
2
2
|
// TODO bring back - this currently doesn't work due to https://github.com/vitejs/vite/issues/8427
|
|
3
3
|
// NOTE We're using a non-relative import here for Vite to properly resolve the import during app builds
|
|
4
4
|
// import LiveStoreSharedWorker from '@livestore/adapter-web/internal-shared-worker?sharedworker'
|
|
5
5
|
import { EventSequenceNumber } from '@livestore/common/schema';
|
|
6
6
|
import { sqliteDbFactory } from '@livestore/sqlite-wasm/browser';
|
|
7
|
-
import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm';
|
|
8
7
|
import { isDevEnv, shouldNeverHappen, tryAsFunctionAndNew } from '@livestore/utils';
|
|
9
|
-
import {
|
|
8
|
+
import { Cause, Deferred, Effect, Exit, Fiber, Layer, ParseResult, Queue, Schema, Stream, Subscribable, SubscriptionRef, Worker, WorkerError, } from '@livestore/utils/effect';
|
|
9
|
+
import { BrowserWorker, Opfs, WebLock } from '@livestore/utils/effect/browser';
|
|
10
10
|
import { nanoid } from '@livestore/utils/nanoid';
|
|
11
|
-
import
|
|
12
|
-
import { readPersistedAppDbFromClientSession, resetPersistedDataFromClientSession } from "../common/persisted-sqlite.js";
|
|
11
|
+
import { readPersistedStateDbFromClientSession, resetPersistedDataFromClientSession, } from "../common/persisted-sqlite.js";
|
|
13
12
|
import { makeShutdownChannel } from "../common/shutdown-channel.js";
|
|
14
13
|
import { DedicatedWorkerDisconnectBroadcast, makeWorkerDisconnectChannel } from "../common/worker-disconnect-channel.js";
|
|
15
14
|
import * as WorkerSchema from "../common/worker-schema.js";
|
|
16
15
|
import { connectWebmeshNodeClientSession } from "./client-session-devtools.js";
|
|
17
|
-
|
|
18
|
-
const sqlite3Promise = loadSqlite3Wasm();
|
|
16
|
+
import { loadSqlite3 } from "./sqlite-loader.js";
|
|
19
17
|
if (isDevEnv()) {
|
|
20
18
|
globalThis.__debugLiveStoreUtils = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
runFork: (effect) => Effect.runFork(effect),
|
|
19
|
+
...globalThis.__debugLiveStoreUtils,
|
|
20
|
+
opfs: Opfs.debugUtils,
|
|
24
21
|
};
|
|
25
22
|
}
|
|
26
23
|
/**
|
|
@@ -41,11 +38,18 @@ if (isDevEnv()) {
|
|
|
41
38
|
* ```
|
|
42
39
|
*/
|
|
43
40
|
export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(function* () {
|
|
44
|
-
const { schema, storeId, devtoolsEnabled, debugInstanceId, bootStatusQueue, shutdown,
|
|
41
|
+
const { schema, storeId, devtoolsEnabled, debugInstanceId, bootStatusQueue, shutdown, syncPayloadSchema: _syncPayloadSchema, syncPayloadEncoded, } = adapterArgs;
|
|
42
|
+
// NOTE: The schema travels with the worker bundle (developers call
|
|
43
|
+
// `makeWorker({ schema, syncPayloadSchema })`). We only keep the
|
|
44
|
+
// destructured value here to document availability on the client session
|
|
45
|
+
// side—structured cloning the Effect schema into the worker is not
|
|
46
|
+
// possible, so we intentionally do not forward it.
|
|
47
|
+
void _syncPayloadSchema;
|
|
45
48
|
yield* ensureBrowserRequirements;
|
|
46
49
|
yield* Queue.offer(bootStatusQueue, { stage: 'loading' });
|
|
47
|
-
const sqlite3 = yield* Effect.promise(() =>
|
|
50
|
+
const sqlite3 = yield* Effect.promise(() => loadSqlite3());
|
|
48
51
|
const LIVESTORE_TAB_LOCK = `livestore-tab-lock-${storeId}`;
|
|
52
|
+
const LIVESTORE_SHARED_WORKER_TERMINATION_LOCK = `livestore-shared-worker-termination-lock-${storeId}`;
|
|
49
53
|
const storageOptions = yield* Schema.decode(WorkerSchema.StorageType)(options.storage);
|
|
50
54
|
const shutdownChannel = yield* makeShutdownChannel(storeId);
|
|
51
55
|
if (options.resetPersistence === true) {
|
|
@@ -60,7 +64,11 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
60
64
|
// TODO also verify persisted data
|
|
61
65
|
const dataFromFile = options.experimental?.disableFastPath === true
|
|
62
66
|
? undefined
|
|
63
|
-
: yield*
|
|
67
|
+
: yield* readPersistedStateDbFromClientSession({ storageOptions, storeId, schema }).pipe(Effect.tapError((error) => Effect.logDebug('[@livestore/adapter-web:client-session] Could not read persisted state db', error, {
|
|
68
|
+
storeId,
|
|
69
|
+
})),
|
|
70
|
+
// If we get any error here, we return `undefined` to fall back to the slow path
|
|
71
|
+
Effect.orElseSucceed(() => undefined));
|
|
64
72
|
// The same across all client sessions (i.e. tabs, windows)
|
|
65
73
|
const clientId = options.clientId ?? getPersistedId(`clientId:${storeId}`, 'local');
|
|
66
74
|
// Unique per client session (i.e. tab, window)
|
|
@@ -68,24 +76,16 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
68
76
|
const workerDisconnectChannel = yield* makeWorkerDisconnectChannel(storeId);
|
|
69
77
|
yield* shutdownChannel.listen.pipe(Stream.flatten(), Stream.tap((cause) => shutdown(cause._tag === 'LiveStore.IntentionalShutdownCause' ? Exit.succeed(cause) : Exit.fail(cause))), Stream.runDrain, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
70
78
|
const sharedWebWorker = tryAsFunctionAndNew(options.sharedWorker, { name: `livestore-shared-worker-${storeId}` });
|
|
79
|
+
if (options.experimental?.awaitSharedWorkerTermination) {
|
|
80
|
+
// Relying on the lock being available is currently the only mechanism we're aware of
|
|
81
|
+
// to know whether the shared worker has terminated.
|
|
82
|
+
yield* Effect.addFinalizer(() => WebLock.waitForLock(LIVESTORE_SHARED_WORKER_TERMINATION_LOCK));
|
|
83
|
+
}
|
|
84
|
+
const sharedWorkerContext = yield* Layer.build(BrowserWorker.layer(() => sharedWebWorker));
|
|
71
85
|
const sharedWorkerFiber = yield* Worker.makePoolSerialized({
|
|
72
86
|
size: 1,
|
|
73
87
|
concurrency: 100,
|
|
74
|
-
|
|
75
|
-
liveStoreVersion,
|
|
76
|
-
payload: {
|
|
77
|
-
_tag: 'FromClientSession',
|
|
78
|
-
initialMessage: new WorkerSchema.LeaderWorkerInnerInitialMessage({
|
|
79
|
-
storageOptions,
|
|
80
|
-
storeId,
|
|
81
|
-
clientId,
|
|
82
|
-
devtoolsEnabled,
|
|
83
|
-
debugInstanceId,
|
|
84
|
-
syncPayload,
|
|
85
|
-
}),
|
|
86
|
-
},
|
|
87
|
-
}),
|
|
88
|
-
}).pipe(Effect.provide(BrowserWorker.layer(() => sharedWebWorker)), Effect.tapCauseLogPretty, UnexpectedError.mapToUnexpectedError, Effect.tapErrorCause((cause) => shutdown(Exit.failCause(cause))), Effect.withSpan('@livestore/adapter-web:client-session:setupSharedWorker'), Effect.forkScoped);
|
|
88
|
+
}).pipe(Effect.provide(sharedWorkerContext), Effect.tapCauseLogPretty, UnknownError.mapToUnknownError, Effect.tapErrorCause((cause) => shutdown(Exit.failCause(cause))), Effect.withSpan('@livestore/adapter-web:client-session:setupSharedWorker'), Effect.forkScoped);
|
|
89
89
|
const lockDeferred = yield* Deferred.make();
|
|
90
90
|
// It's important that we resolve the leader election in a blocking way, so there's always a leader.
|
|
91
91
|
// Otherwise events could end up being dropped.
|
|
@@ -109,10 +109,23 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
109
109
|
const worker = tryAsFunctionAndNew(options.worker, { name: `livestore-worker-${storeId}-${sessionId}` });
|
|
110
110
|
yield* Worker.makeSerialized({
|
|
111
111
|
initialMessage: () => new WorkerSchema.LeaderWorkerOuterInitialMessage({ port: mc.port1, storeId, clientId }),
|
|
112
|
-
}).pipe(Effect.provide(BrowserWorker.layer(() => worker)),
|
|
112
|
+
}).pipe(Effect.provide(BrowserWorker.layer(() => worker)), UnknownError.mapToUnknownError, Effect.tapErrorCause((cause) => shutdown(Exit.failCause(cause))), Effect.withSpan('@livestore/adapter-web:client-session:setupDedicatedWorker'), Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
113
113
|
yield* workerDisconnectChannel.send(DedicatedWorkerDisconnectBroadcast.make({}));
|
|
114
114
|
const sharedWorker = yield* Fiber.join(sharedWorkerFiber);
|
|
115
|
-
yield* sharedWorker
|
|
115
|
+
yield* sharedWorker
|
|
116
|
+
.executeEffect(new WorkerSchema.SharedWorkerUpdateMessagePort({
|
|
117
|
+
port: mc.port2,
|
|
118
|
+
liveStoreVersion,
|
|
119
|
+
initial: new WorkerSchema.LeaderWorkerInnerInitialMessage({
|
|
120
|
+
storageOptions,
|
|
121
|
+
storeId,
|
|
122
|
+
clientId,
|
|
123
|
+
devtoolsEnabled,
|
|
124
|
+
debugInstanceId,
|
|
125
|
+
syncPayloadEncoded,
|
|
126
|
+
}),
|
|
127
|
+
}))
|
|
128
|
+
.pipe(UnknownError.mapToUnknownError, Effect.tapErrorCause((cause) => shutdown(Exit.failCause(cause))));
|
|
116
129
|
yield* Deferred.succeed(waitForSharedWorkerInitialized, undefined);
|
|
117
130
|
return yield* Effect.never;
|
|
118
131
|
}).pipe(Effect.withSpan('@livestore/adapter-web:client-session:lock'));
|
|
@@ -137,17 +150,17 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
137
150
|
Effect.logWarnIfTakesLongerThan({
|
|
138
151
|
label: `@livestore/adapter-web:client-session:runInWorker:${req._tag}`,
|
|
139
152
|
duration: 2000,
|
|
140
|
-
}), Effect.withSpan(`@livestore/adapter-web:client-session:runInWorker:${req._tag}`), Effect.mapError((cause) => Schema.is(
|
|
153
|
+
}), Effect.withSpan(`@livestore/adapter-web:client-session:runInWorker:${req._tag}`), Effect.mapError((cause) => Schema.is(UnknownError)(cause)
|
|
141
154
|
? cause
|
|
142
155
|
: ParseResult.isParseError(cause) || Schema.is(WorkerError.WorkerError)(cause)
|
|
143
|
-
? new
|
|
144
|
-
: cause), Effect.catchAllDefect((cause) => new
|
|
156
|
+
? new UnknownError({ cause })
|
|
157
|
+
: cause), Effect.catchAllDefect((cause) => new UnknownError({ cause })));
|
|
145
158
|
const runInWorkerStream = (req) => Effect.gen(function* () {
|
|
146
159
|
const sharedWorker = yield* Fiber.join(sharedWorkerFiber);
|
|
147
|
-
return sharedWorker.execute(req).pipe(Stream.mapError((cause) => Schema.is(
|
|
160
|
+
return sharedWorker.execute(req).pipe(Stream.mapError((cause) => Schema.is(UnknownError)(cause)
|
|
148
161
|
? cause
|
|
149
162
|
: ParseResult.isParseError(cause) || Schema.is(WorkerError.WorkerError)(cause)
|
|
150
|
-
? new
|
|
163
|
+
? new UnknownError({ cause })
|
|
151
164
|
: cause), Stream.withSpan(`@livestore/adapter-web:client-session:runInWorkerStream:${req._tag}`));
|
|
152
165
|
}).pipe(Stream.unwrap);
|
|
153
166
|
const bootStatusFiber = yield* runInWorkerStream(new WorkerSchema.LeaderWorkerInnerBootStatusStream()).pipe(Stream.tap((_) => Queue.offer(bootStatusQueue, _)), Stream.runDrain, Effect.tapErrorCause((cause) => Cause.isInterruptedOnly(cause) ? Effect.void : shutdown(Exit.failCause(cause))), Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
@@ -167,7 +180,7 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
167
180
|
sqliteDb.import(initialResult.snapshot);
|
|
168
181
|
const numberOfTables = sqliteDb.select(`select count(*) as count from sqlite_master`)[0]?.count ?? 0;
|
|
169
182
|
if (numberOfTables === 0) {
|
|
170
|
-
return yield*
|
|
183
|
+
return yield* UnknownError.make({
|
|
171
184
|
cause: `Encountered empty or corrupted database`,
|
|
172
185
|
payload: { snapshotByteLength: initialResult.snapshot.byteLength, storageOptions: options.storage },
|
|
173
186
|
});
|
|
@@ -182,12 +195,12 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
182
195
|
])
|
|
183
196
|
.first());
|
|
184
197
|
const initialLeaderHead = initialLeaderHeadRes
|
|
185
|
-
? EventSequenceNumber.make({
|
|
198
|
+
? EventSequenceNumber.Client.Composite.make({
|
|
186
199
|
global: initialLeaderHeadRes.seqNumGlobal,
|
|
187
200
|
client: initialLeaderHeadRes.seqNumClient,
|
|
188
201
|
rebaseGeneration: initialLeaderHeadRes.seqNumRebaseGeneration,
|
|
189
202
|
})
|
|
190
|
-
: EventSequenceNumber.ROOT;
|
|
203
|
+
: EventSequenceNumber.Client.ROOT;
|
|
191
204
|
// console.debug('[@livestore/adapter-web:client-session] initialLeaderHead', initialLeaderHead)
|
|
192
205
|
yield* Effect.addFinalizer((ex) => Effect.gen(function* () {
|
|
193
206
|
if (Exit.isFailure(ex) &&
|
|
@@ -204,17 +217,25 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
204
217
|
}
|
|
205
218
|
}).pipe(Effect.tapCauseLogPretty, Effect.orDie));
|
|
206
219
|
const leaderThread = {
|
|
207
|
-
export: runInWorker(new WorkerSchema.LeaderWorkerInnerExport()).pipe(Effect.timeout(10_000),
|
|
220
|
+
export: runInWorker(new WorkerSchema.LeaderWorkerInnerExport()).pipe(Effect.timeout(10_000), UnknownError.mapToUnknownError, Effect.withSpan('@livestore/adapter-web:client-session:export')),
|
|
208
221
|
events: {
|
|
209
222
|
pull: ({ cursor }) => runInWorkerStream(new WorkerSchema.LeaderWorkerInnerPullStream({ cursor })).pipe(Stream.orDie),
|
|
210
223
|
push: (batch) => runInWorker(new WorkerSchema.LeaderWorkerInnerPushToLeader({ batch })).pipe(Effect.withSpan('@livestore/adapter-web:client-session:pushToLeader', {
|
|
211
224
|
attributes: { batchSize: batch.length },
|
|
212
225
|
})),
|
|
226
|
+
stream: (options) => runInWorkerStream(new WorkerSchema.LeaderWorkerInnerStreamEvents(options)).pipe(Stream.withSpan('@livestore/adapter-web:client-session:streamEvents'), Stream.orDie),
|
|
213
227
|
},
|
|
214
228
|
initialState: { leaderHead: initialLeaderHead, migrationsReport },
|
|
215
|
-
getEventlogData: runInWorker(new WorkerSchema.LeaderWorkerInnerExportEventlog()).pipe(Effect.timeout(10_000),
|
|
216
|
-
|
|
217
|
-
|
|
229
|
+
getEventlogData: runInWorker(new WorkerSchema.LeaderWorkerInnerExportEventlog()).pipe(Effect.timeout(10_000), UnknownError.mapToUnknownError, Effect.withSpan('@livestore/adapter-web:client-session:getEventlogData')),
|
|
230
|
+
syncState: Subscribable.make({
|
|
231
|
+
get: runInWorker(new WorkerSchema.LeaderWorkerInnerGetLeaderSyncState()).pipe(UnknownError.mapToUnknownError, Effect.withSpan('@livestore/adapter-web:client-session:getLeaderSyncState')),
|
|
232
|
+
changes: runInWorkerStream(new WorkerSchema.LeaderWorkerInnerSyncStateStream()).pipe(Stream.orDie),
|
|
233
|
+
}),
|
|
234
|
+
sendDevtoolsMessage: (message) => runInWorker(new WorkerSchema.LeaderWorkerInnerExtraDevtoolsMessage({ message })).pipe(UnknownError.mapToUnknownError, Effect.withSpan('@livestore/adapter-web:client-session:devtoolsMessageForLeader')),
|
|
235
|
+
networkStatus: Subscribable.make({
|
|
236
|
+
get: runInWorker(new WorkerSchema.LeaderWorkerInnerGetNetworkStatus()).pipe(Effect.orDie),
|
|
237
|
+
changes: runInWorkerStream(new WorkerSchema.LeaderWorkerInnerNetworkStatusStream()).pipe(Stream.orDie),
|
|
238
|
+
}),
|
|
218
239
|
};
|
|
219
240
|
const sharedWorker = yield* Fiber.join(sharedWorkerFiber);
|
|
220
241
|
const clientSession = yield* makeClientSession({
|
|
@@ -223,10 +244,11 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
223
244
|
lockStatus,
|
|
224
245
|
clientId,
|
|
225
246
|
sessionId,
|
|
226
|
-
|
|
227
|
-
isLeader: true,
|
|
247
|
+
isLeader: gotLocky,
|
|
228
248
|
leaderThread,
|
|
229
249
|
webmeshMode: 'direct',
|
|
250
|
+
// Can be undefined in Node.js
|
|
251
|
+
origin: globalThis.location?.origin,
|
|
230
252
|
connectWebmeshNode: ({ sessionInfo, webmeshNode }) => connectWebmeshNodeClientSession({ webmeshNode, sessionInfo, sharedWorker, devtoolsEnabled, schema }),
|
|
231
253
|
registerBeforeUnload: (onBeforeUnload) => {
|
|
232
254
|
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
@@ -237,7 +259,7 @@ export const makePersistedAdapter = (options) => (adapterArgs) => Effect.gen(fun
|
|
|
237
259
|
},
|
|
238
260
|
});
|
|
239
261
|
return clientSession;
|
|
240
|
-
}).pipe(
|
|
262
|
+
}).pipe(Effect.provide(Opfs.Opfs.Default), UnknownError.mapToUnknownError);
|
|
241
263
|
// NOTE for `local` storage we could also use the eventlog db to store the data
|
|
242
264
|
const getPersistedId = (key, storageType) => {
|
|
243
265
|
const makeId = () => nanoid(5);
|
|
@@ -264,7 +286,7 @@ const getPersistedId = (key, storageType) => {
|
|
|
264
286
|
const ensureBrowserRequirements = Effect.gen(function* () {
|
|
265
287
|
const validate = (condition, label) => Effect.gen(function* () {
|
|
266
288
|
if (condition) {
|
|
267
|
-
return yield*
|
|
289
|
+
return yield* UnknownError.make({
|
|
268
290
|
cause: `[@livestore/adapter-web] Browser not supported. The LiveStore web adapter needs '${label}' to work properly`,
|
|
269
291
|
});
|
|
270
292
|
}
|