@livestore/adapter-web 0.0.0-snapshot-a953343ad2d7468c6573bcb5e26f0eab4302078f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.eslintrc.cjs +6 -0
  2. package/README.md +12 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/common/connection.d.ts +7 -0
  5. package/dist/common/connection.d.ts.map +1 -0
  6. package/dist/common/connection.js +25 -0
  7. package/dist/common/connection.js.map +1 -0
  8. package/dist/devtools-bridge/background-browser-channel.d.ts +9 -0
  9. package/dist/devtools-bridge/background-browser-channel.d.ts.map +1 -0
  10. package/dist/devtools-bridge/background-browser-channel.js +31 -0
  11. package/dist/devtools-bridge/background-browser-channel.js.map +1 -0
  12. package/dist/devtools-bridge/background-message.d.ts +75 -0
  13. package/dist/devtools-bridge/background-message.d.ts.map +1 -0
  14. package/dist/devtools-bridge/background-message.js +53 -0
  15. package/dist/devtools-bridge/background-message.js.map +1 -0
  16. package/dist/devtools-bridge/bridge-shared.d.ts +14 -0
  17. package/dist/devtools-bridge/bridge-shared.d.ts.map +1 -0
  18. package/dist/devtools-bridge/bridge-shared.js +67 -0
  19. package/dist/devtools-bridge/bridge-shared.js.map +1 -0
  20. package/dist/devtools-bridge/browser-extension-bridge.d.ts +3 -0
  21. package/dist/devtools-bridge/browser-extension-bridge.d.ts.map +1 -0
  22. package/dist/devtools-bridge/browser-extension-bridge.js +59 -0
  23. package/dist/devtools-bridge/browser-extension-bridge.js.map +1 -0
  24. package/dist/devtools-bridge/iframe-message.d.ts +16 -0
  25. package/dist/devtools-bridge/iframe-message.d.ts.map +1 -0
  26. package/dist/devtools-bridge/iframe-message.js +11 -0
  27. package/dist/devtools-bridge/iframe-message.js.map +1 -0
  28. package/dist/devtools-bridge/index.d.ts +6 -0
  29. package/dist/devtools-bridge/index.d.ts.map +1 -0
  30. package/dist/devtools-bridge/index.js +5 -0
  31. package/dist/devtools-bridge/index.js.map +1 -0
  32. package/dist/devtools-bridge/web-bridge.d.ts +31 -0
  33. package/dist/devtools-bridge/web-bridge.d.ts.map +1 -0
  34. package/dist/devtools-bridge/web-bridge.js +131 -0
  35. package/dist/devtools-bridge/web-bridge.js.map +1 -0
  36. package/dist/in-memory/index.d.ts +4 -0
  37. package/dist/in-memory/index.d.ts.map +1 -0
  38. package/dist/in-memory/index.js +50 -0
  39. package/dist/in-memory/index.js.map +1 -0
  40. package/dist/index.d.ts +4 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.js +4 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/opfs-utils.d.ts +5 -0
  45. package/dist/opfs-utils.d.ts.map +1 -0
  46. package/dist/opfs-utils.js +43 -0
  47. package/dist/opfs-utils.js.map +1 -0
  48. package/dist/web-worker/client-session/client-session-devtools.d.ts +7 -0
  49. package/dist/web-worker/client-session/client-session-devtools.d.ts.map +1 -0
  50. package/dist/web-worker/client-session/client-session-devtools.js +107 -0
  51. package/dist/web-worker/client-session/client-session-devtools.js.map +1 -0
  52. package/dist/web-worker/client-session/index.d.ts +41 -0
  53. package/dist/web-worker/client-session/index.d.ts.map +1 -0
  54. package/dist/web-worker/client-session/index.js +299 -0
  55. package/dist/web-worker/client-session/index.js.map +1 -0
  56. package/dist/web-worker/client-session/trim-batch.d.ts +4 -0
  57. package/dist/web-worker/client-session/trim-batch.d.ts.map +1 -0
  58. package/dist/web-worker/client-session/trim-batch.js +13 -0
  59. package/dist/web-worker/client-session/trim-batch.js.map +1 -0
  60. package/dist/web-worker/client-session/trim-batch.test.d.ts +2 -0
  61. package/dist/web-worker/client-session/trim-batch.test.d.ts.map +1 -0
  62. package/dist/web-worker/client-session/trim-batch.test.js +38 -0
  63. package/dist/web-worker/client-session/trim-batch.test.js.map +1 -0
  64. package/dist/web-worker/common/persisted-sqlite.d.ts +23 -0
  65. package/dist/web-worker/common/persisted-sqlite.d.ts.map +1 -0
  66. package/dist/web-worker/common/persisted-sqlite.js +92 -0
  67. package/dist/web-worker/common/persisted-sqlite.js.map +1 -0
  68. package/dist/web-worker/common/shutdown-channel.d.ts +7 -0
  69. package/dist/web-worker/common/shutdown-channel.d.ts.map +1 -0
  70. package/dist/web-worker/common/shutdown-channel.js +7 -0
  71. package/dist/web-worker/common/shutdown-channel.js.map +1 -0
  72. package/dist/web-worker/common/worker-schema.d.ts +226 -0
  73. package/dist/web-worker/common/worker-schema.d.ts.map +1 -0
  74. package/dist/web-worker/common/worker-schema.js +176 -0
  75. package/dist/web-worker/common/worker-schema.js.map +1 -0
  76. package/dist/web-worker/leader-worker/make-leader-worker.d.ts +15 -0
  77. package/dist/web-worker/leader-worker/make-leader-worker.d.ts.map +1 -0
  78. package/dist/web-worker/leader-worker/make-leader-worker.js +144 -0
  79. package/dist/web-worker/leader-worker/make-leader-worker.js.map +1 -0
  80. package/dist/web-worker/shared-worker/make-shared-worker.d.ts +2 -0
  81. package/dist/web-worker/shared-worker/make-shared-worker.d.ts.map +1 -0
  82. package/dist/web-worker/shared-worker/make-shared-worker.js +160 -0
  83. package/dist/web-worker/shared-worker/make-shared-worker.js.map +1 -0
  84. package/dist/web-worker/vite-dev-polyfill.d.ts +2 -0
  85. package/dist/web-worker/vite-dev-polyfill.d.ts.map +1 -0
  86. package/dist/web-worker/vite-dev-polyfill.js +37 -0
  87. package/dist/web-worker/vite-dev-polyfill.js.map +1 -0
  88. package/package.json +78 -0
  89. package/src/common/connection.ts +32 -0
  90. package/src/devtools-bridge/background-browser-channel.ts +57 -0
  91. package/src/devtools-bridge/background-message.ts +42 -0
  92. package/src/devtools-bridge/bridge-shared.ts +97 -0
  93. package/src/devtools-bridge/browser-extension-bridge.ts +64 -0
  94. package/src/devtools-bridge/iframe-message.ts +9 -0
  95. package/src/devtools-bridge/index.ts +9 -0
  96. package/src/devtools-bridge/web-bridge.ts +169 -0
  97. package/src/in-memory/index.ts +66 -0
  98. package/src/index.ts +3 -0
  99. package/src/opfs-utils.ts +61 -0
  100. package/src/web-worker/ambient.d.ts +37 -0
  101. package/src/web-worker/client-session/client-session-devtools.ts +167 -0
  102. package/src/web-worker/client-session/index.ts +537 -0
  103. package/src/web-worker/client-session/trim-batch.test.ts +48 -0
  104. package/src/web-worker/client-session/trim-batch.ts +15 -0
  105. package/src/web-worker/common/persisted-sqlite.ts +136 -0
  106. package/src/web-worker/common/shutdown-channel.ts +8 -0
  107. package/src/web-worker/common/worker-schema.ts +206 -0
  108. package/src/web-worker/leader-worker/make-leader-worker.ts +276 -0
  109. package/src/web-worker/shared-worker/make-shared-worker.ts +300 -0
  110. package/src/web-worker/vite-dev-polyfill.ts +36 -0
  111. package/tsconfig.json +17 -0
@@ -0,0 +1,299 @@
1
+ import { Devtools, IntentionalShutdownCause, UnexpectedError } from '@livestore/common';
2
+ // TODO bring back - this currently doesn't work due to https://github.com/vitejs/vite/issues/8427
3
+ // NOTE We're using a non-relative import here for Vite to properly resolve the import during app builds
4
+ // import LiveStoreSharedWorker from '@livestore/adapter-web/internal-shared-worker?sharedworker'
5
+ import { ShutdownChannel } from '@livestore/common/leader-thread';
6
+ import { EventId, SESSION_CHANGESET_META_TABLE } from '@livestore/common/schema';
7
+ import { makeWebDevtoolsChannel } from '@livestore/devtools-web-common/web-channel';
8
+ import { sqliteDbFactory } from '@livestore/sqlite-wasm/browser';
9
+ import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm';
10
+ import { isDevEnv, shouldNeverHappen, tryAsFunctionAndNew } from '@livestore/utils';
11
+ import { BrowserWorker, BucketQueue, Cause, Deferred, Effect, Exit, Fiber, ParseResult, Queue, Schema, Stream, SubscriptionRef, WebLock, Worker, WorkerError, } from '@livestore/utils/effect';
12
+ import { nanoid } from '@livestore/utils/nanoid';
13
+ import * as OpfsUtils from '../../opfs-utils.js';
14
+ import { readPersistedAppDbFromClientSession, resetPersistedDataFromClientSession } from '../common/persisted-sqlite.js';
15
+ import { makeShutdownChannel } from '../common/shutdown-channel.js';
16
+ import * as WorkerSchema from '../common/worker-schema.js';
17
+ import { bootDevtools } from './client-session-devtools.js';
18
+ import { trimPushBatch } from './trim-batch.js';
19
+ // NOTE we're starting to initialize the sqlite wasm binary here to speed things up
20
+ const sqlite3Promise = loadSqlite3Wasm();
21
+ if (isDevEnv()) {
22
+ globalThis.__debugLiveStoreUtils = {
23
+ opfs: OpfsUtils,
24
+ runSync: (effect) => Effect.runSync(effect),
25
+ runFork: (effect) => Effect.runFork(effect),
26
+ };
27
+ }
28
+ export const makeAdapter = (options) => ({ schema, storeId, devtoolsEnabled, debugInstanceId, bootStatusQueue, shutdown, connectDevtoolsToStore }) => Effect.gen(function* () {
29
+ yield* ensureBrowserRequirements;
30
+ yield* Queue.offer(bootStatusQueue, { stage: 'loading' });
31
+ const sqlite3 = yield* Effect.promise(() => sqlite3Promise);
32
+ const LIVESTORE_TAB_LOCK = `livestore-tab-lock-${storeId}`;
33
+ const storageOptions = yield* Schema.decode(WorkerSchema.StorageType)(options.storage);
34
+ if (options.resetPersistence === true) {
35
+ yield* resetPersistedDataFromClientSession({ storageOptions, storeId });
36
+ }
37
+ // Note on fast-path booting:
38
+ // Instead of waiting for the leader worker to boot and then get a database snapshot from it,
39
+ // we're here trying to get the snapshot directly from storage
40
+ // we usually speeds up the boot process by a lot.
41
+ // We need to be extra careful though to not run into any race conditions or inconsistencies.
42
+ // TODO also verify persisted data
43
+ const dataFromFile = yield* readPersistedAppDbFromClientSession({ storageOptions, storeId, schema });
44
+ // The same across all client sessions (i.e. tabs, windows)
45
+ const clientId = getPersistedId(`clientId:${storeId}`, 'local');
46
+ // Unique per client session (i.e. tab, window)
47
+ const sessionId = getPersistedId(`sessionId:${storeId}`, 'session');
48
+ const shutdownChannel = yield* makeShutdownChannel(storeId);
49
+ yield* shutdownChannel.listen.pipe(Stream.flatten(), Stream.filter(Schema.is(IntentionalShutdownCause)), Stream.tap((msg) => shutdown(Cause.fail(msg))), Stream.runDrain, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
50
+ const sharedWebWorker = tryAsFunctionAndNew(options.sharedWorker, { name: `livestore-shared-worker-${storeId}` });
51
+ const sharedWorkerFiber = yield* Worker.makePoolSerialized({
52
+ size: 1,
53
+ concurrency: 100,
54
+ initialMessage: () => new WorkerSchema.SharedWorker.InitialMessage({
55
+ payload: {
56
+ _tag: 'FromClientSession',
57
+ initialMessage: new WorkerSchema.LeaderWorkerInner.InitialMessage({
58
+ storageOptions,
59
+ storeId,
60
+ clientId,
61
+ devtoolsEnabled,
62
+ debugInstanceId,
63
+ }),
64
+ },
65
+ }),
66
+ }).pipe(Effect.provide(BrowserWorker.layer(() => sharedWebWorker)), Effect.tapCauseLogPretty, UnexpectedError.mapToUnexpectedError, Effect.tapErrorCause(shutdown), Effect.withSpan('@livestore/adapter-web:client-session:setupSharedWorker'), Effect.forkScoped);
67
+ const lockDeferred = yield* Deferred.make();
68
+ // It's important that we resolve the leader election in a blocking way, so there's always a leader.
69
+ // Otherwise mutations could end up being dropped.
70
+ //
71
+ // Sorry for this pun ...
72
+ let gotLocky = yield* WebLock.tryGetDeferredLock(lockDeferred, LIVESTORE_TAB_LOCK);
73
+ const lockStatus = yield* SubscriptionRef.make(gotLocky ? 'has-lock' : 'no-lock');
74
+ // Ideally we can come up with a simpler implementation that doesn't require this
75
+ const waitForSharedWorkerInitialized = yield* Deferred.make();
76
+ if (gotLocky === false) {
77
+ // Don't need to wait if we're not the leader
78
+ yield* Deferred.succeed(waitForSharedWorkerInitialized, undefined);
79
+ }
80
+ const runLocked = Effect.gen(function* () {
81
+ yield* Effect.logDebug(`[@livestore/adapter-web:client-session] ✅ Got lock '${LIVESTORE_TAB_LOCK}' (sessionId: ${sessionId})`);
82
+ yield* Effect.addFinalizer(() => Effect.logDebug(`[@livestore/adapter-web:client-session] Releasing lock for '${LIVESTORE_TAB_LOCK}'`));
83
+ yield* SubscriptionRef.set(lockStatus, 'has-lock');
84
+ const mc = new MessageChannel();
85
+ // NOTE we're adding the `storeId` to the worker name to make it unique
86
+ // and adding the `sessionId` to make it easier to debug which session a worker belongs to in logs
87
+ const worker = tryAsFunctionAndNew(options.worker, { name: `livestore-worker-${storeId}-${sessionId}` });
88
+ yield* Worker.makeSerialized({
89
+ initialMessage: () => new WorkerSchema.LeaderWorkerOuter.InitialMessage({ port: mc.port1, storeId, clientId }),
90
+ }).pipe(Effect.provide(BrowserWorker.layer(() => worker)), UnexpectedError.mapToUnexpectedError, Effect.tapErrorCause(shutdown), Effect.withSpan('@livestore/adapter-web:client-session:setupDedicatedWorker'), Effect.tapCauseLogPretty, Effect.forkScoped);
91
+ yield* shutdownChannel.send(ShutdownChannel.DedicatedWorkerDisconnectBroadcast.make({}));
92
+ const sharedWorker = yield* Fiber.join(sharedWorkerFiber);
93
+ yield* sharedWorker
94
+ .executeEffect(new WorkerSchema.SharedWorker.UpdateMessagePort({ port: mc.port2 }))
95
+ .pipe(UnexpectedError.mapToUnexpectedError, Effect.tapErrorCause(shutdown));
96
+ yield* Deferred.succeed(waitForSharedWorkerInitialized, undefined);
97
+ yield* Effect.addFinalizer(() => Effect.gen(function* () {
98
+ // console.log('[@livestore/adapter-web:client-session] Shutting down leader worker')
99
+ // We first try to gracefully shutdown the leader worker and then forcefully terminate it
100
+ // yield* Effect.raceFirst(
101
+ // sharedWorker
102
+ // .executeEffect(new WorkerSchema.LeaderWorkerInner.Shutdown({}))
103
+ // .pipe(Effect.andThen(() => worker.terminate())),
104
+ // Effect.sync(() => {
105
+ // console.warn(
106
+ // '[@livestore/adapter-web:client-session] Worker did not gracefully shutdown in time, terminating it',
107
+ // )
108
+ // worker.terminate()
109
+ // }).pipe(
110
+ // // Seems like we still need to wait a bit for the worker to terminate
111
+ // // TODO improve this implementation (possibly via another weblock?)
112
+ // Effect.delay(1000),
113
+ // ),
114
+ // )
115
+ // yield* Effect.logDebug('[@livestore/adapter-web:client-session] client-session shutdown. worker terminated')
116
+ }).pipe(Effect.withSpan('@livestore/adapter-web:client-session:lock:shutdown'), Effect.ignoreLogged));
117
+ yield* Effect.never;
118
+ }).pipe(Effect.withSpan('@livestore/adapter-web:client-session:lock'));
119
+ // TODO take/give up lock when tab becomes active/passive
120
+ if (gotLocky === false) {
121
+ yield* Effect.logDebug(`[@livestore/adapter-web:client-session] ⏳ Waiting for lock '${LIVESTORE_TAB_LOCK}' (sessionId: ${sessionId})`);
122
+ // TODO find a cleaner implementation for the lock handling as we don't make use of the deferred properly right now
123
+ yield* WebLock.waitForDeferredLock(lockDeferred, LIVESTORE_TAB_LOCK).pipe(Effect.andThen(() => {
124
+ gotLocky = true;
125
+ return runLocked;
126
+ }), Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
127
+ }
128
+ else {
129
+ yield* runLocked.pipe(Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
130
+ }
131
+ const runInWorker = (req) => Fiber.join(sharedWorkerFiber).pipe(
132
+ // NOTE we need to wait for the shared worker to be initialized before we can send requests to it
133
+ Effect.tap(() => waitForSharedWorkerInitialized), Effect.flatMap((worker) => worker.executeEffect(req)),
134
+ // NOTE we want to treat worker requests as atomic and therefore not allow them to be interrupted
135
+ // Interruption usually only happens during leader re-election or store shutdown
136
+ // Effect.uninterruptible,
137
+ Effect.logWarnIfTakesLongerThan({
138
+ label: `@livestore/adapter-web:client-session:runInWorker:${req._tag}`,
139
+ duration: 2000,
140
+ }), Effect.withSpan(`@livestore/adapter-web:client-session:runInWorker:${req._tag}`), Effect.mapError((cause) => Schema.is(UnexpectedError)(cause)
141
+ ? cause
142
+ : ParseResult.isParseError(cause) || Schema.is(WorkerError.WorkerError)(cause)
143
+ ? new UnexpectedError({ cause })
144
+ : cause), Effect.catchAllDefect((cause) => new UnexpectedError({ cause })));
145
+ const runInWorkerStream = (req) => Effect.gen(function* () {
146
+ const sharedWorker = yield* Fiber.join(sharedWorkerFiber);
147
+ return sharedWorker.execute(req).pipe(Stream.mapError((cause) => Schema.is(UnexpectedError)(cause)
148
+ ? cause
149
+ : ParseResult.isParseError(cause) || Schema.is(WorkerError.WorkerError)(cause)
150
+ ? new UnexpectedError({ cause })
151
+ : cause), Stream.withSpan(`@livestore/adapter-web:client-session:runInWorkerStream:${req._tag}`));
152
+ }).pipe(Stream.unwrap);
153
+ const networkStatus = yield* SubscriptionRef.make({
154
+ isConnected: false,
155
+ timestampMs: Date.now(),
156
+ latchClosed: false,
157
+ });
158
+ yield* runInWorkerStream(new WorkerSchema.LeaderWorkerInner.NetworkStatusStream()).pipe(Stream.tap((_) => SubscriptionRef.set(networkStatus, _)), Stream.runDrain, Effect.forever, // NOTE Whenever the leader changes, we need to re-start the stream
159
+ Effect.tapErrorCause(shutdown), Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
160
+ const bootStatusFiber = yield* runInWorkerStream(new WorkerSchema.LeaderWorkerInner.BootStatusStream()).pipe(Stream.tap((_) => Queue.offer(bootStatusQueue, _)), Stream.runDrain, Effect.tapErrorCause((cause) => (Cause.isInterruptedOnly(cause) ? Effect.void : shutdown(cause))), Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
161
+ yield* Queue.awaitShutdown(bootStatusQueue).pipe(Effect.andThen(Fiber.interrupt(bootStatusFiber)), Effect.tapCauseLogPretty, Effect.forkScoped);
162
+ // TODO maybe bring back transfering the initially created in-memory db snapshot instead of
163
+ // re-exporting the db
164
+ const initialResult = dataFromFile === undefined
165
+ ? yield* runInWorker(new WorkerSchema.LeaderWorkerInner.GetRecreateSnapshot()).pipe(Effect.map(({ snapshot, migrationsReport }) => ({
166
+ _tag: 'from-leader-worker',
167
+ snapshot,
168
+ migrationsReport,
169
+ })))
170
+ : { _tag: 'fast-path', snapshot: dataFromFile };
171
+ const migrationsReport = initialResult._tag === 'from-leader-worker' ? initialResult.migrationsReport : { migrations: [] };
172
+ const makeSqliteDb = sqliteDbFactory({ sqlite3 });
173
+ const sqliteDb = yield* makeSqliteDb({ _tag: 'in-memory' });
174
+ sqliteDb.import(initialResult.snapshot);
175
+ const numberOfTables = sqliteDb.select(`select count(*) as count from sqlite_master`)[0]?.count ?? 0;
176
+ if (numberOfTables === 0) {
177
+ yield* UnexpectedError.make({
178
+ cause: `Encountered empty or corrupted database`,
179
+ payload: { snapshotByteLength: initialResult.snapshot.byteLength, storageOptions: options.storage },
180
+ });
181
+ }
182
+ // We're restoring the leader head from the SESSION_CHANGESET_META_TABLE, not from the mutationlog db/table
183
+ // in order to avoid exporting/transferring the mutationlog db/table, which is important to speed up the fast path.
184
+ const initialLeaderHeadRes = sqliteDb.select(`select idGlobal, idClient from ${SESSION_CHANGESET_META_TABLE} order by idGlobal desc, idClient desc limit 1`)[0];
185
+ const initialLeaderHead = initialLeaderHeadRes
186
+ ? EventId.make({ global: initialLeaderHeadRes.idGlobal, client: initialLeaderHeadRes.idClient })
187
+ : EventId.ROOT;
188
+ // console.debug('[@livestore/adapter-web:client-session] initialLeaderHead', initialLeaderHead)
189
+ yield* Effect.addFinalizer((ex) => Effect.gen(function* () {
190
+ if (Exit.isFailure(ex) &&
191
+ Exit.isInterrupted(ex) === false &&
192
+ Schema.is(IntentionalShutdownCause)(Cause.squash(ex.cause)) === false) {
193
+ yield* Effect.logError('[@livestore/adapter-web:client-session] client-session shutdown', ex.cause);
194
+ }
195
+ else {
196
+ yield* Effect.logDebug('[@livestore/adapter-web:client-session] client-session shutdown', gotLocky, ex);
197
+ }
198
+ if (gotLocky) {
199
+ yield* Deferred.succeed(lockDeferred, undefined);
200
+ }
201
+ }).pipe(Effect.tapCauseLogPretty, Effect.orDie));
202
+ const pushQueue = yield* BucketQueue.make();
203
+ yield* Effect.gen(function* () {
204
+ const batch = yield* BucketQueue.takeBetween(pushQueue, 1, 100);
205
+ // We need to trim "old batches" which can happen during client session rebasing
206
+ const trimmedBatch = trimPushBatch(batch);
207
+ yield* runInWorker(new WorkerSchema.LeaderWorkerInner.PushToLeader({ batch: trimmedBatch })).pipe(Effect.withSpan('@livestore/adapter-web:client-session:pushToLeader', {
208
+ attributes: { batchSize: batch.length },
209
+ }),
210
+ // We can ignore the error here because the ClientSessionSyncProcessor will retry after rebasing
211
+ Effect.ignoreLogged);
212
+ }).pipe(Effect.forever, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
213
+ const devtools = devtoolsEnabled
214
+ ? { enabled: true, pullLatch: yield* Effect.makeLatch(true), pushLatch: yield* Effect.makeLatch(true) }
215
+ : { enabled: false };
216
+ const clientSession = {
217
+ sqliteDb,
218
+ devtools,
219
+ lockStatus,
220
+ clientId,
221
+ sessionId,
222
+ leaderThread: {
223
+ export: runInWorker(new WorkerSchema.LeaderWorkerInner.Export()).pipe(Effect.timeout(10_000), UnexpectedError.mapToUnexpectedError, Effect.withSpan('@livestore/adapter-web:client-session:export')),
224
+ mutations: {
225
+ pull: runInWorkerStream(new WorkerSchema.LeaderWorkerInner.PullStream({ cursor: initialLeaderHead })).pipe(Stream.orDie),
226
+ // NOTE instead of sending the worker message right away, we're batching the events in order to
227
+ // - maintain a consistent order of events
228
+ // - improve efficiency by reducing the number of messages
229
+ push: (batch) => BucketQueue.offerAll(pushQueue, batch),
230
+ },
231
+ initialState: { leaderHead: initialLeaderHead, migrationsReport },
232
+ getMutationLogData: runInWorker(new WorkerSchema.LeaderWorkerInner.ExportMutationlog()).pipe(Effect.timeout(10_000), UnexpectedError.mapToUnexpectedError, Effect.withSpan('@livestore/adapter-web:client-session:getMutationLogData')),
233
+ getSyncState: runInWorker(new WorkerSchema.LeaderWorkerInner.GetLeaderSyncState()).pipe(UnexpectedError.mapToUnexpectedError, Effect.withSpan('@livestore/adapter-web:client-session:getLeaderSyncState')),
234
+ networkStatus,
235
+ sendDevtoolsMessage: (message) => runInWorker(new WorkerSchema.LeaderWorkerInner.ExtraDevtoolsMessage({ message })).pipe(UnexpectedError.mapToUnexpectedError, Effect.withSpan('@livestore/adapter-web:client-session:devtoolsMessageForLeader')),
236
+ },
237
+ shutdown,
238
+ };
239
+ if (devtoolsEnabled) {
240
+ // yield* bootDevtools({ client-session, waitForDevtoolsWebBridgePort, connectToDevtools, storeId })
241
+ yield* Effect.gen(function* () {
242
+ const sharedWorker = yield* Fiber.join(sharedWorkerFiber);
243
+ yield* bootDevtools({ clientSession, storeId });
244
+ // TODO re-enable browser extension as well
245
+ const storeDevtoolsChannel = yield* makeWebDevtoolsChannel({
246
+ nodeName: `client-session-${storeId}-${clientId}-${sessionId}`,
247
+ target: `devtools`,
248
+ schema: {
249
+ listen: Devtools.ClientSession.MessageToApp,
250
+ send: Devtools.ClientSession.MessageFromApp,
251
+ },
252
+ worker: sharedWorker,
253
+ workerTargetName: 'shared-worker',
254
+ });
255
+ yield* connectDevtoolsToStore(storeDevtoolsChannel);
256
+ }).pipe(Effect.withSpan('@livestore/adapter-web:client-session:devtools'), Effect.tapCauseLogPretty, Effect.forkScoped);
257
+ }
258
+ return clientSession;
259
+ }).pipe(UnexpectedError.mapToUnexpectedError);
260
+ // NOTE for `local` storage we could also use the mutationlog db to store the data
261
+ const getPersistedId = (key, storageType) => {
262
+ const makeId = () => nanoid(5);
263
+ const storage = typeof window === 'undefined'
264
+ ? undefined
265
+ : storageType === 'session'
266
+ ? sessionStorage
267
+ : storageType === 'local'
268
+ ? localStorage
269
+ : shouldNeverHappen(`[@livestore/adapter-web] Invalid storage type: ${storageType}`);
270
+ // in case of a worker, we need the id of the parent window, to keep the id consistent
271
+ // we also need to handle the case where there are multiple workers being spawned by the same window
272
+ if (storage === undefined) {
273
+ return makeId();
274
+ }
275
+ const fullKey = `livestore:${key}`;
276
+ const storedKey = storage.getItem(fullKey);
277
+ if (storedKey)
278
+ return storedKey;
279
+ const newKey = makeId();
280
+ storage.setItem(fullKey, newKey);
281
+ return newKey;
282
+ };
283
+ const ensureBrowserRequirements = Effect.gen(function* () {
284
+ const validate = (condition, label) => Effect.gen(function* () {
285
+ if (condition) {
286
+ yield* UnexpectedError.make({
287
+ cause: `[@livestore/adapter-web] Browser not supported. The LiveStore web adapter needs '${label}' to work properly`,
288
+ });
289
+ }
290
+ });
291
+ yield* Effect.all([
292
+ validate(typeof navigator === 'undefined', 'navigator'),
293
+ validate(navigator.locks === undefined, 'navigator.locks'),
294
+ validate(navigator.storage === undefined, 'navigator.storage'),
295
+ validate(typeof window === 'undefined', 'window'),
296
+ validate(typeof sessionStorage === 'undefined', 'sessionStorage'),
297
+ ]);
298
+ });
299
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web-worker/client-session/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { MutationEvent } from '@livestore/common/schema';
2
+ /** [(0,1), (0,2), (1,0), (0,1), (0,2), (1,0), (1,1)] -> [(0,1), (0,2), (1,0), (1,1)] */
3
+ export declare const trimPushBatch: (batch: ReadonlyArray<MutationEvent.AnyEncoded>) => readonly MutationEvent.AnyEncoded[];
4
+ //# sourceMappingURL=trim-batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim-batch.d.ts","sourceRoot":"","sources":["../../../src/web-worker/client-session/trim-batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAG7D,wFAAwF;AACxF,eAAO,MAAM,aAAa,UAAW,aAAa,CAAC,aAAa,CAAC,UAAU,CAAC,wCAU3E,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { EventId } from '@livestore/common/schema';
2
+ /** [(0,1), (0,2), (1,0), (0,1), (0,2), (1,0), (1,1)] -> [(0,1), (0,2), (1,0), (1,1)] */
3
+ export const trimPushBatch = (batch) => {
4
+ // Iterate over batch from the end and stop once we encounter an event with a larger id than the previous event
5
+ // Then return the slice of the batch up to and including that event
6
+ for (let i = batch.length - 2; i >= 0; i--) {
7
+ if (EventId.isGreaterThanOrEqual(batch[i].id, batch[i + 1].id)) {
8
+ return batch.slice(i + 1);
9
+ }
10
+ }
11
+ return batch;
12
+ };
13
+ //# sourceMappingURL=trim-batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim-batch.js","sourceRoot":"","sources":["../../../src/web-worker/client-session/trim-batch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAElD,wFAAwF;AACxF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAA8C,EAAE,EAAE;IAC9E,+GAA+G;IAC/G,oEAAoE;IACpE,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,EAAE,CAAC,EAAE,CAAC;YACjE,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=trim-batch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim-batch.test.d.ts","sourceRoot":"","sources":["../../../src/web-worker/client-session/trim-batch.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,38 @@
1
+ import { EventId } from '@livestore/common/schema';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { trimPushBatch } from './trim-batch.js';
4
+ describe('trimPushBatch', () => {
5
+ it('should return same batch', () => {
6
+ const batch = [
7
+ { id: EventId.make({ global: 0, client: 1 }), parentId: EventId.make({ global: 0, client: 0 }) },
8
+ { id: EventId.make({ global: 0, client: 2 }), parentId: EventId.make({ global: 0, client: 1 }) },
9
+ { id: EventId.make({ global: 1, client: 0 }), parentId: EventId.make({ global: 0, client: 0 }) },
10
+ { id: EventId.make({ global: 1, client: 1 }), parentId: EventId.make({ global: 1, client: 0 }) },
11
+ ];
12
+ const trimmed = trimPushBatch(batch);
13
+ expect(trimmed).toEqual(batch);
14
+ });
15
+ it('should trim the batch', () => {
16
+ const batch = [
17
+ { id: EventId.make({ global: 0, client: 1 }), parentId: EventId.make({ global: 0, client: 0 }) },
18
+ { id: EventId.make({ global: 0, client: 2 }), parentId: EventId.make({ global: 0, client: 1 }) },
19
+ // should trim above
20
+ { id: EventId.make({ global: 0, client: 1 }), parentId: EventId.make({ global: 0, client: 0 }) },
21
+ { id: EventId.make({ global: 0, client: 2 }), parentId: EventId.make({ global: 0, client: 1 }) },
22
+ { id: EventId.make({ global: 1, client: 0 }), parentId: EventId.make({ global: 0, client: 0 }) },
23
+ { id: EventId.make({ global: 1, client: 1 }), parentId: EventId.make({ global: 1, client: 0 }) },
24
+ ];
25
+ const trimmed = trimPushBatch(batch);
26
+ expect(trimmed).toEqual(batch.slice(2));
27
+ });
28
+ it('should trim the batch', () => {
29
+ const batch = [
30
+ { id: EventId.make({ global: 0, client: 1 }), parentId: EventId.make({ global: 0, client: 0 }) },
31
+ // should trim above
32
+ { id: EventId.make({ global: 0, client: 1 }), parentId: EventId.make({ global: 0, client: 0 }) },
33
+ ];
34
+ const trimmed = trimPushBatch(batch);
35
+ expect(trimmed).toEqual(batch.slice(1));
36
+ });
37
+ });
38
+ //# sourceMappingURL=trim-batch.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim-batch.test.js","sourceRoot":"","sources":["../../../src/web-worker/client-session/trim-batch.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { LiveStoreSchema } from '@livestore/common/schema';
2
+ import { Effect, Schema } from '@livestore/utils/effect';
3
+ import type * as WorkerSchema from './worker-schema.js';
4
+ declare const PersistedSqliteError_base: Schema.TaggedErrorClass<PersistedSqliteError, "PersistedSqliteError", {
5
+ readonly _tag: Schema.tag<"PersistedSqliteError">;
6
+ } & {
7
+ cause: Schema.Defect;
8
+ }>;
9
+ export declare class PersistedSqliteError extends PersistedSqliteError_base {
10
+ }
11
+ export declare const readPersistedAppDbFromClientSession: ({ storageOptions, storeId, schema, }: {
12
+ storageOptions: WorkerSchema.StorageType;
13
+ storeId: string;
14
+ schema: LiveStoreSchema;
15
+ }) => Effect.Effect<Uint8Array<ArrayBuffer> | undefined, never, never>;
16
+ export declare const resetPersistedDataFromClientSession: ({ storageOptions, storeId, }: {
17
+ storageOptions: WorkerSchema.StorageType;
18
+ storeId: string;
19
+ }) => Effect.Effect<void, never, never>;
20
+ export declare const sanitizeOpfsDir: (directory: string | undefined, storeId: string) => string;
21
+ export declare const getAppDbFileName: (schema: LiveStoreSchema) => string;
22
+ export {};
23
+ //# sourceMappingURL=persisted-sqlite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persisted-sqlite.d.ts","sourceRoot":"","sources":["../../../src/web-worker/common/persisted-sqlite.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAE/D,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAGxD,OAAO,KAAK,KAAK,YAAY,MAAM,oBAAoB,CAAA;;;;;;AAEvD,qBAAa,oBAAqB,SAAQ,yBAExC;CAAG;AAEL,eAAO,MAAM,mCAAmC,yCAI7C;IACD,cAAc,EAAE,YAAY,CAAC,WAAW,CAAA;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,eAAe,CAAA;CACxB,qEAyDE,CAAA;AAEH,eAAO,MAAM,mCAAmC,iCAG7C;IACD,cAAc,EAAE,YAAY,CAAC,WAAW,CAAA;IACxC,OAAO,EAAE,MAAM,CAAA;CAChB,sCAIuF,CAAA;AA6BxF,eAAO,MAAM,eAAe,cAAe,MAAM,GAAG,SAAS,WAAW,MAAM,WAY7E,CAAA;AAED,eAAO,MAAM,gBAAgB,WAAY,eAAe,WAGvD,CAAA"}
@@ -0,0 +1,92 @@
1
+ import { liveStoreStorageFormatVersion } from '@livestore/common';
2
+ import { decodeSAHPoolFilename, HEADER_OFFSET_DATA } from '@livestore/sqlite-wasm/browser';
3
+ import { Effect, Schema } from '@livestore/utils/effect';
4
+ import * as OpfsUtils from '../../opfs-utils.js';
5
+ export class PersistedSqliteError extends Schema.TaggedError()('PersistedSqliteError', {
6
+ cause: Schema.Defect,
7
+ }) {
8
+ }
9
+ export const readPersistedAppDbFromClientSession = ({ storageOptions, storeId, schema, }) => Effect.gen(function* () {
10
+ return yield* Effect.promise(async () => {
11
+ const directory = sanitizeOpfsDir(storageOptions.directory, storeId);
12
+ const sahPoolOpaqueDir = await OpfsUtils.getDirHandle(directory).catch(() => undefined);
13
+ if (sahPoolOpaqueDir === undefined) {
14
+ return undefined;
15
+ }
16
+ const tryGetDbFile = async (fileHandle) => {
17
+ const file = await fileHandle.getFile();
18
+ const fileName = await decodeSAHPoolFilename(file);
19
+ return fileName ? { fileName, file } : undefined;
20
+ };
21
+ const getAllFiles = async (asyncIterator) => {
22
+ const results = [];
23
+ for await (const value of asyncIterator) {
24
+ if (value.kind === 'file') {
25
+ results.push(value);
26
+ }
27
+ }
28
+ return results;
29
+ };
30
+ const files = await getAllFiles(sahPoolOpaqueDir.values());
31
+ const fileResults = await Promise.all(files.map(tryGetDbFile));
32
+ const appDbFileName = '/' + getAppDbFileName(schema);
33
+ const dbFileRes = fileResults.find((_) => _?.fileName === appDbFileName);
34
+ // console.debug('fileResults', fileResults, 'dbFileRes', dbFileRes)
35
+ if (dbFileRes !== undefined) {
36
+ const data = await dbFileRes.file.slice(HEADER_OFFSET_DATA).arrayBuffer();
37
+ // console.debug('readPersistedAppDbFromClientSession', data.byteLength, data)
38
+ // Given the SAH pool always eagerly creates files with empty non-header data,
39
+ // we want to return undefined if the file exists but is empty
40
+ if (data.byteLength === 0) {
41
+ return undefined;
42
+ }
43
+ return new Uint8Array(data);
44
+ }
45
+ return undefined;
46
+ });
47
+ }).pipe(Effect.logWarnIfTakesLongerThan({
48
+ duration: 1000,
49
+ label: '@livestore/adapter-web:readPersistedAppDbFromClientSession',
50
+ }), Effect.withPerformanceMeasure('@livestore/adapter-web:readPersistedAppDbFromClientSession'), Effect.withSpan('@livestore/adapter-web:readPersistedAppDbFromClientSession'));
51
+ export const resetPersistedDataFromClientSession = ({ storageOptions, storeId, }) => Effect.gen(function* () {
52
+ const directory = sanitizeOpfsDir(storageOptions.directory, storeId);
53
+ yield* opfsDeleteAbs(directory);
54
+ }).pipe(Effect.withSpan('@livestore/adapter-web:resetPersistedDataFromClientSession'));
55
+ const opfsDeleteAbs = (absPath) => Effect.promise(async () => {
56
+ // Get the root directory handle
57
+ const root = await OpfsUtils.rootHandlePromise;
58
+ // Split the absolute path to traverse directories
59
+ const pathParts = absPath.split('/').filter((part) => part.length);
60
+ try {
61
+ // Traverse to the target file handle
62
+ let currentDir = root;
63
+ for (let i = 0; i < pathParts.length - 1; i++) {
64
+ currentDir = await currentDir.getDirectoryHandle(pathParts[i]);
65
+ }
66
+ // Delete the file
67
+ await currentDir.removeEntry(pathParts.at(-1), { recursive: true });
68
+ }
69
+ catch (error) {
70
+ if (error instanceof DOMException && error.name === 'NotFoundError') {
71
+ // Can ignore as it's already been deleted or not there in the first place
72
+ return;
73
+ }
74
+ else {
75
+ throw error;
76
+ }
77
+ }
78
+ }).pipe(Effect.withSpan('@livestore/adapter-web:worker:opfsDeleteFile', { attributes: { absFilePath: absPath } }));
79
+ export const sanitizeOpfsDir = (directory, storeId) => {
80
+ // Root dir should be `''` not `/`
81
+ if (directory === undefined || directory === '' || directory === '/')
82
+ return `livestore-${storeId}@${liveStoreStorageFormatVersion}`;
83
+ if (directory.includes('/')) {
84
+ throw new Error(`@livestore/adapter-web:worker:sanitizeOpfsDir: Nested directories are not yet supported ('${directory}')`);
85
+ }
86
+ return `${directory}@${liveStoreStorageFormatVersion}`;
87
+ };
88
+ export const getAppDbFileName = (schema) => {
89
+ const schemaHashSuffix = schema.migrationOptions.strategy === 'manual' ? 'fixed' : schema.hash.toString();
90
+ return `app${schemaHashSuffix}.db`;
91
+ };
92
+ //# sourceMappingURL=persisted-sqlite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persisted-sqlite.js","sourceRoot":"","sources":["../../../src/web-worker/common/persisted-sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,MAAM,mBAAmB,CAAA;AAEjE,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAC1F,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAExD,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAA;AAGhD,MAAM,OAAO,oBAAqB,SAAQ,MAAM,CAAC,WAAW,EAAwB,CAAC,sBAAsB,EAAE;IAC3G,KAAK,EAAE,MAAM,CAAC,MAAM;CACrB,CAAC;CAAG;AAEL,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,EAClD,cAAc,EACd,OAAO,EACP,MAAM,GAKP,EAAE,EAAE,CACH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;QACtC,MAAM,SAAS,GAAG,eAAe,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QACpE,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;QAEvF,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;YACnC,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,MAAM,YAAY,GAAG,KAAK,EAAE,UAAgC,EAAE,EAAE;YAC9D,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,CAAA;YACvC,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAA;YAClD,OAAO,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAClD,CAAC,CAAA;QAED,MAAM,WAAW,GAAG,KAAK,EAAE,aAA8C,EAAmC,EAAE;YAC5G,MAAM,OAAO,GAA2B,EAAE,CAAA;YAC1C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBACxC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC1B,OAAO,CAAC,IAAI,CAAC,KAA6B,CAAC,CAAA;gBAC7C,CAAC;YACH,CAAC;YACD,OAAO,OAAO,CAAA;QAChB,CAAC,CAAA;QAED,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAA;QAE1D,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAA;QAE9D,MAAM,aAAa,GAAG,GAAG,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAA;QAEpD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,aAAa,CAAC,CAAA;QACxE,oEAAoE;QAEpE,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC,WAAW,EAAE,CAAA;YACzE,8EAA8E;YAE9E,8EAA8E;YAC9E,8DAA8D;YAC9D,IAAI,IAAI,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,SAAS,CAAA;YAClB,CAAC;YAED,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAA;QAC7B,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,wBAAwB,CAAC;IAC9B,QAAQ,EAAE,IAAI;IACd,KAAK,EAAE,4DAA4D;CACpE,CAAC,EACF,MAAM,CAAC,sBAAsB,CAAC,4DAA4D,CAAC,EAC3F,MAAM,CAAC,QAAQ,CAAC,4DAA4D,CAAC,CAC9E,CAAA;AAEH,MAAM,CAAC,MAAM,mCAAmC,GAAG,CAAC,EAClD,cAAc,EACd,OAAO,GAIR,EAAE,EAAE,CACH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,SAAS,GAAG,eAAe,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACpE,KAAK,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,CAAA;AACjC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,4DAA4D,CAAC,CAAC,CAAA;AAExF,MAAM,aAAa,GAAG,CAAC,OAAe,EAAE,EAAE,CACxC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;IACxB,gCAAgC;IAChC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,iBAAiB,CAAA;IAE9C,kDAAkD;IAClD,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAElE,IAAI,CAAC;QACH,qCAAqC;QACrC,IAAI,UAAU,GAAG,IAAI,CAAA;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,UAAU,GAAG,MAAM,UAAU,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAA;QACjE,CAAC;QAED,kBAAkB;QAClB,MAAM,UAAU,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACpE,0EAA0E;YAC1E,OAAM;QACR,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,CAAA;QACb,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,8CAA8C,EAAE,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AAEpH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,SAA6B,EAAE,OAAe,EAAE,EAAE;IAChF,kCAAkC;IAClC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,EAAE,IAAI,SAAS,KAAK,GAAG;QAClE,OAAO,aAAa,OAAO,IAAI,6BAA6B,EAAE,CAAA;IAEhE,IAAI,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,6FAA6F,SAAS,IAAI,CAC3G,CAAA;IACH,CAAC;IAED,OAAO,GAAG,SAAS,IAAI,6BAA6B,EAAE,CAAA;AACxD,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAuB,EAAE,EAAE;IAC1D,MAAM,gBAAgB,GAAG,MAAM,CAAC,gBAAgB,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAA;IACzG,OAAO,MAAM,gBAAgB,KAAK,CAAA;AACpC,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { WebChannel } from '@livestore/utils/effect';
2
+ export declare const makeShutdownChannel: (storeId: string) => import("effect/Effect").Effect<WebChannel.WebChannel<import("@livestore/common/dist/adapter-types.js").IntentionalShutdownCause | {
3
+ readonly _tag: "DedicatedWorkerDisconnectBroadcast";
4
+ }, import("@livestore/common/dist/adapter-types.js").IntentionalShutdownCause | {
5
+ readonly _tag: "DedicatedWorkerDisconnectBroadcast";
6
+ }, never>, never, import("effect/Scope").Scope>;
7
+ //# sourceMappingURL=shutdown-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-channel.d.ts","sourceRoot":"","sources":["../../../src/web-worker/common/shutdown-channel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEpD,eAAO,MAAM,mBAAmB,YAAa,MAAM;;;;+CAI/C,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { ShutdownChannel } from '@livestore/common/leader-thread';
2
+ import { WebChannel } from '@livestore/utils/effect';
3
+ export const makeShutdownChannel = (storeId) => WebChannel.broadcastChannel({
4
+ channelName: `livestore.shutdown.${storeId}`,
5
+ schema: ShutdownChannel.All,
6
+ });
7
+ //# sourceMappingURL=shutdown-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown-channel.js","sourceRoot":"","sources":["../../../src/web-worker/common/shutdown-channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEpD,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,OAAe,EAAE,EAAE,CACrD,UAAU,CAAC,gBAAgB,CAAC;IAC1B,WAAW,EAAE,sBAAsB,OAAO,EAAE;IAC5C,MAAM,EAAE,eAAe,CAAC,GAAG;CAC5B,CAAC,CAAA"}