@livestore/adapter-web 0.0.0-snapshot-13a84f2057a5823fa045fade064685c25519837a → 0.0.0-snapshot-12fc9f248d56344bafb1f0bd9fc50c25c21fd3f7
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 +45 -3
- package/dist/in-memory/in-memory-adapter.d.ts.map +1 -1
- package/dist/in-memory/in-memory-adapter.js +139 -36
- package/dist/in-memory/in-memory-adapter.js.map +1 -1
- package/dist/web-worker/client-session/client-session-devtools.d.ts +11 -0
- package/dist/web-worker/client-session/client-session-devtools.d.ts.map +1 -1
- package/dist/web-worker/client-session/client-session-devtools.js +34 -1
- package/dist/web-worker/client-session/client-session-devtools.js.map +1 -1
- package/dist/web-worker/client-session/persisted-adapter.d.ts.map +1 -1
- package/dist/web-worker/client-session/persisted-adapter.js +5 -35
- package/dist/web-worker/client-session/persisted-adapter.js.map +1 -1
- package/dist/web-worker/common/worker-schema.d.ts +1 -1
- package/package.json +6 -6
- package/src/in-memory/in-memory-adapter.ts +250 -39
- package/src/web-worker/client-session/client-session-devtools.ts +62 -1
- package/src/web-worker/client-session/persisted-adapter.ts +5 -54
|
@@ -1,62 +1,273 @@
|
|
|
1
|
-
import type { Adapter,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { Adapter, ClientSessionLeaderThreadProxy, LockStatus, SyncOptions } from '@livestore/common'
|
|
2
|
+
import { Devtools, makeClientSession, UnexpectedError } from '@livestore/common'
|
|
3
|
+
import type { DevtoolsOptions, LeaderSqliteDb } from '@livestore/common/leader-thread'
|
|
4
|
+
import { configureConnection, Eventlog, LeaderThreadCtx, makeLeaderThreadLayer } from '@livestore/common/leader-thread'
|
|
5
|
+
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
6
|
+
import { LiveStoreEvent } from '@livestore/common/schema'
|
|
7
|
+
import * as DevtoolsWeb from '@livestore/devtools-web-common/web-channel'
|
|
8
|
+
import type * as WebmeshWorker from '@livestore/devtools-web-common/worker'
|
|
9
|
+
import type { MakeWebSqliteDb } from '@livestore/sqlite-wasm/browser'
|
|
5
10
|
import { sqliteDbFactory } from '@livestore/sqlite-wasm/browser'
|
|
6
11
|
import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm'
|
|
7
|
-
import {
|
|
12
|
+
import { tryAsFunctionAndNew } from '@livestore/utils'
|
|
13
|
+
import type { Schema, Scope } from '@livestore/utils/effect'
|
|
14
|
+
import { BrowserWorker, Effect, FetchHttpClient, Fiber, Layer, SubscriptionRef, Worker } from '@livestore/utils/effect'
|
|
8
15
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
16
|
+
import * as Webmesh from '@livestore/webmesh'
|
|
9
17
|
|
|
10
|
-
|
|
18
|
+
import { connectWebmeshNodeClientSession } from '../web-worker/client-session/client-session-devtools.js'
|
|
19
|
+
import { makeShutdownChannel } from '../web-worker/common/shutdown-channel.js'
|
|
11
20
|
|
|
12
21
|
// NOTE we're starting to initialize the sqlite wasm binary here to speed things up
|
|
13
22
|
const sqlite3Promise = loadSqlite3Wasm()
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
export interface InMemoryAdapterOptions {
|
|
25
|
+
importSnapshot?: Uint8Array
|
|
26
|
+
sync?: SyncOptions
|
|
27
|
+
/**
|
|
28
|
+
* The client ID to use for the adapter.
|
|
29
|
+
*
|
|
30
|
+
* @default a random nanoid
|
|
31
|
+
*/
|
|
32
|
+
clientId?: string
|
|
33
|
+
/**
|
|
34
|
+
* The session ID to use for the adapter.
|
|
35
|
+
*
|
|
36
|
+
* @default a random nanoid
|
|
37
|
+
*/
|
|
38
|
+
sessionId?: string
|
|
39
|
+
// TODO make the in-memory adapter work with the browser extension
|
|
40
|
+
/** In order to use the devtools with the in-memory adapter, you need to provide the shared worker. */
|
|
41
|
+
devtools?: {
|
|
42
|
+
sharedWorker:
|
|
43
|
+
| ((options: { name: string }) => globalThis.SharedWorker)
|
|
44
|
+
| (new (options: { name: string }) => globalThis.SharedWorker)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
16
48
|
export const makeInMemoryAdapter =
|
|
17
|
-
(
|
|
18
|
-
(
|
|
19
|
-
schema,
|
|
20
|
-
shutdown,
|
|
21
|
-
// devtoolsEnabled, bootStatusQueue, shutdown, connectDevtoolsToStore
|
|
22
|
-
}) =>
|
|
49
|
+
(options: InMemoryAdapterOptions = {}): Adapter =>
|
|
50
|
+
(adapterArgs) =>
|
|
23
51
|
Effect.gen(function* () {
|
|
52
|
+
const { schema, shutdown, syncPayload, storeId, devtoolsEnabled } = adapterArgs
|
|
24
53
|
const sqlite3 = yield* Effect.promise(() => sqlite3Promise)
|
|
25
54
|
|
|
26
55
|
const sqliteDb = yield* sqliteDbFactory({ sqlite3 })({ _tag: 'in-memory' })
|
|
27
|
-
let migrationsReport: MigrationsReport = { migrations: [] }
|
|
28
56
|
|
|
29
|
-
|
|
30
|
-
|
|
57
|
+
const clientId = options.clientId ?? nanoid(6)
|
|
58
|
+
const sessionId = options.sessionId ?? nanoid(6)
|
|
59
|
+
|
|
60
|
+
const sharedWebWorker = options.devtools?.sharedWorker
|
|
61
|
+
? tryAsFunctionAndNew(options.devtools.sharedWorker, {
|
|
62
|
+
name: `livestore-shared-worker-${storeId}`,
|
|
63
|
+
})
|
|
64
|
+
: undefined
|
|
31
65
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
66
|
+
const sharedWorkerFiber = sharedWebWorker
|
|
67
|
+
? yield* Worker.makePoolSerialized<typeof WebmeshWorker.Schema.Request.Type>({
|
|
68
|
+
size: 1,
|
|
69
|
+
concurrency: 100,
|
|
70
|
+
}).pipe(
|
|
71
|
+
Effect.provide(BrowserWorker.layer(() => sharedWebWorker)),
|
|
72
|
+
Effect.tapCauseLogPretty,
|
|
73
|
+
UnexpectedError.mapToUnexpectedError,
|
|
74
|
+
Effect.forkScoped,
|
|
75
|
+
)
|
|
76
|
+
: undefined
|
|
35
77
|
|
|
36
|
-
|
|
37
|
-
|
|
78
|
+
const { leaderThread, initialSnapshot } = yield* makeLeaderThread({
|
|
79
|
+
schema,
|
|
80
|
+
storeId,
|
|
81
|
+
clientId,
|
|
82
|
+
makeSqliteDb: sqliteDbFactory({ sqlite3 }),
|
|
83
|
+
syncOptions: options.sync,
|
|
84
|
+
syncPayload,
|
|
85
|
+
importSnapshot: options.importSnapshot,
|
|
86
|
+
devtoolsEnabled,
|
|
87
|
+
sharedWorkerFiber,
|
|
88
|
+
})
|
|
38
89
|
|
|
39
|
-
|
|
90
|
+
sqliteDb.import(initialSnapshot)
|
|
40
91
|
|
|
41
|
-
const
|
|
92
|
+
const lockStatus = yield* SubscriptionRef.make<LockStatus>('has-lock')
|
|
93
|
+
|
|
94
|
+
const clientSession = yield* makeClientSession({
|
|
95
|
+
...adapterArgs,
|
|
42
96
|
sqliteDb,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
leaderThread
|
|
47
|
-
events: {
|
|
48
|
-
pull: () => Stream.never,
|
|
49
|
-
push: () => Effect.void,
|
|
50
|
-
},
|
|
51
|
-
initialState: { leaderHead: EventSequenceNumber.ROOT, migrationsReport },
|
|
52
|
-
export: Effect.sync(() => sqliteDb.export()),
|
|
53
|
-
getEventlogData: Effect.succeed(new Uint8Array()),
|
|
54
|
-
getSyncState: Effect.dieMessage('Not implemented'),
|
|
55
|
-
sendDevtoolsMessage: () => Effect.dieMessage('Not implemented'),
|
|
56
|
-
},
|
|
97
|
+
clientId,
|
|
98
|
+
sessionId,
|
|
99
|
+
isLeader: true,
|
|
100
|
+
leaderThread,
|
|
57
101
|
lockStatus,
|
|
58
102
|
shutdown,
|
|
59
|
-
|
|
103
|
+
webmeshMode: 'direct',
|
|
104
|
+
connectWebmeshNode: ({ sessionInfo, webmeshNode }) =>
|
|
105
|
+
Effect.gen(function* () {
|
|
106
|
+
if (sharedWorkerFiber === undefined || devtoolsEnabled === false) {
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const sharedWorker = yield* sharedWorkerFiber.pipe(Fiber.join)
|
|
111
|
+
|
|
112
|
+
yield* connectWebmeshNodeClientSession({ webmeshNode, sessionInfo, sharedWorker, devtoolsEnabled, schema })
|
|
113
|
+
}),
|
|
114
|
+
registerBeforeUnload: (onBeforeUnload) => {
|
|
115
|
+
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
116
|
+
window.addEventListener('beforeunload', onBeforeUnload)
|
|
117
|
+
return () => window.removeEventListener('beforeunload', onBeforeUnload)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return () => {}
|
|
121
|
+
},
|
|
122
|
+
})
|
|
60
123
|
|
|
61
124
|
return clientSession
|
|
62
|
-
}).pipe(UnexpectedError.mapToUnexpectedError)
|
|
125
|
+
}).pipe(UnexpectedError.mapToUnexpectedError, Effect.provide(FetchHttpClient.layer))
|
|
126
|
+
|
|
127
|
+
export interface MakeLeaderThreadArgs {
|
|
128
|
+
schema: LiveStoreSchema
|
|
129
|
+
storeId: string
|
|
130
|
+
clientId: string
|
|
131
|
+
makeSqliteDb: MakeWebSqliteDb
|
|
132
|
+
syncOptions: SyncOptions | undefined
|
|
133
|
+
syncPayload: Schema.JsonValue | undefined
|
|
134
|
+
importSnapshot: Uint8Array | undefined
|
|
135
|
+
devtoolsEnabled: boolean
|
|
136
|
+
sharedWorkerFiber: SharedWorkerFiber | undefined
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const makeLeaderThread = ({
|
|
140
|
+
schema,
|
|
141
|
+
storeId,
|
|
142
|
+
clientId,
|
|
143
|
+
makeSqliteDb,
|
|
144
|
+
syncOptions,
|
|
145
|
+
syncPayload,
|
|
146
|
+
importSnapshot,
|
|
147
|
+
devtoolsEnabled,
|
|
148
|
+
sharedWorkerFiber,
|
|
149
|
+
}: MakeLeaderThreadArgs) =>
|
|
150
|
+
Effect.gen(function* () {
|
|
151
|
+
const runtime = yield* Effect.runtime<never>()
|
|
152
|
+
|
|
153
|
+
const makeDb = (_kind: 'state' | 'eventlog') => {
|
|
154
|
+
return makeSqliteDb({
|
|
155
|
+
_tag: 'in-memory',
|
|
156
|
+
configureDb: (db) =>
|
|
157
|
+
configureConnection(db, { foreignKeys: true }).pipe(Effect.provide(runtime), Effect.runSync),
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const shutdownChannel = yield* makeShutdownChannel(storeId)
|
|
162
|
+
|
|
163
|
+
// Might involve some async work, so we're running them concurrently
|
|
164
|
+
const [dbState, dbEventlog] = yield* Effect.all([makeDb('state'), makeDb('eventlog')], { concurrency: 2 })
|
|
165
|
+
|
|
166
|
+
if (importSnapshot) {
|
|
167
|
+
dbState.import(importSnapshot)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const devtoolsOptions = yield* makeDevtoolsOptions({
|
|
171
|
+
devtoolsEnabled,
|
|
172
|
+
sharedWorkerFiber,
|
|
173
|
+
dbState,
|
|
174
|
+
dbEventlog,
|
|
175
|
+
storeId,
|
|
176
|
+
clientId,
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const layer = yield* Layer.build(
|
|
180
|
+
makeLeaderThreadLayer({
|
|
181
|
+
schema,
|
|
182
|
+
storeId,
|
|
183
|
+
clientId,
|
|
184
|
+
makeSqliteDb,
|
|
185
|
+
syncOptions,
|
|
186
|
+
dbState,
|
|
187
|
+
dbEventlog,
|
|
188
|
+
devtoolsOptions,
|
|
189
|
+
shutdownChannel,
|
|
190
|
+
syncPayload,
|
|
191
|
+
}),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return yield* Effect.gen(function* () {
|
|
195
|
+
const { dbState, dbEventlog, syncProcessor, extraIncomingMessagesQueue, initialState } = yield* LeaderThreadCtx
|
|
196
|
+
|
|
197
|
+
const initialLeaderHead = Eventlog.getClientHeadFromDb(dbEventlog)
|
|
198
|
+
|
|
199
|
+
const leaderThread = {
|
|
200
|
+
events: {
|
|
201
|
+
pull: ({ cursor }) => syncProcessor.pull({ cursor }),
|
|
202
|
+
push: (batch) =>
|
|
203
|
+
syncProcessor.push(
|
|
204
|
+
batch.map((item) => new LiveStoreEvent.EncodedWithMeta(item)),
|
|
205
|
+
{ waitForProcessing: true },
|
|
206
|
+
),
|
|
207
|
+
},
|
|
208
|
+
initialState: { leaderHead: initialLeaderHead, migrationsReport: initialState.migrationsReport },
|
|
209
|
+
export: Effect.sync(() => dbState.export()),
|
|
210
|
+
getEventlogData: Effect.sync(() => dbEventlog.export()),
|
|
211
|
+
getSyncState: syncProcessor.syncState,
|
|
212
|
+
sendDevtoolsMessage: (message) => extraIncomingMessagesQueue.offer(message),
|
|
213
|
+
} satisfies ClientSessionLeaderThreadProxy
|
|
214
|
+
|
|
215
|
+
const initialSnapshot = dbState.export()
|
|
216
|
+
|
|
217
|
+
return { leaderThread, initialSnapshot }
|
|
218
|
+
}).pipe(Effect.provide(layer))
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
type SharedWorkerFiber = Fiber.Fiber<
|
|
222
|
+
Worker.SerializedWorkerPool<typeof WebmeshWorker.Schema.Request.Type>,
|
|
223
|
+
UnexpectedError
|
|
224
|
+
>
|
|
225
|
+
|
|
226
|
+
const makeDevtoolsOptions = ({
|
|
227
|
+
devtoolsEnabled,
|
|
228
|
+
sharedWorkerFiber,
|
|
229
|
+
dbState,
|
|
230
|
+
dbEventlog,
|
|
231
|
+
storeId,
|
|
232
|
+
clientId,
|
|
233
|
+
}: {
|
|
234
|
+
devtoolsEnabled: boolean
|
|
235
|
+
sharedWorkerFiber: SharedWorkerFiber | undefined
|
|
236
|
+
dbState: LeaderSqliteDb
|
|
237
|
+
dbEventlog: LeaderSqliteDb
|
|
238
|
+
storeId: string
|
|
239
|
+
clientId: string
|
|
240
|
+
}): Effect.Effect<DevtoolsOptions, UnexpectedError, Scope.Scope> =>
|
|
241
|
+
Effect.gen(function* () {
|
|
242
|
+
if (devtoolsEnabled === false || sharedWorkerFiber === undefined) {
|
|
243
|
+
return { enabled: false }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
enabled: true,
|
|
248
|
+
boot: Effect.gen(function* () {
|
|
249
|
+
const persistenceInfo = {
|
|
250
|
+
state: dbState.metadata.persistenceInfo,
|
|
251
|
+
eventlog: dbEventlog.metadata.persistenceInfo,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const node = yield* Webmesh.makeMeshNode(Devtools.makeNodeName.client.leader({ storeId, clientId }))
|
|
255
|
+
// @ts-expect-error TODO type this
|
|
256
|
+
globalThis.__debugWebmeshNodeLeader = node
|
|
257
|
+
|
|
258
|
+
const sharedWorker = yield* sharedWorkerFiber.pipe(Fiber.join)
|
|
259
|
+
|
|
260
|
+
// TODO also make this work with the browser extension
|
|
261
|
+
// basic idea: instead of also connecting to the shared worker,
|
|
262
|
+
// connect to the client session node above which will already connect to the shared worker + browser extension
|
|
263
|
+
|
|
264
|
+
yield* DevtoolsWeb.connectViaWorker({
|
|
265
|
+
node,
|
|
266
|
+
worker: sharedWorker,
|
|
267
|
+
target: DevtoolsWeb.makeNodeName.sharedWorker({ storeId }),
|
|
268
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
|
|
269
|
+
|
|
270
|
+
return { node, persistenceInfo, mode: 'direct' }
|
|
271
|
+
}),
|
|
272
|
+
}
|
|
273
|
+
})
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { Devtools } from '@livestore/common'
|
|
1
2
|
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
3
|
+
import * as DevtoolsWeb from '@livestore/devtools-web-common/web-channel'
|
|
2
4
|
import { isDevEnv } from '@livestore/utils'
|
|
3
|
-
import {
|
|
5
|
+
import type { Worker } from '@livestore/utils/effect'
|
|
6
|
+
import { Effect, Stream, WebChannel } from '@livestore/utils/effect'
|
|
7
|
+
import * as Webmesh from '@livestore/webmesh'
|
|
4
8
|
|
|
5
9
|
export const logDevtoolsUrl = ({
|
|
6
10
|
schema,
|
|
@@ -29,3 +33,60 @@ export const logDevtoolsUrl = ({
|
|
|
29
33
|
}
|
|
30
34
|
}
|
|
31
35
|
}).pipe(Effect.withSpan('@livestore/adapter-web:client-session:devtools:logDevtoolsUrl'))
|
|
36
|
+
|
|
37
|
+
export const connectWebmeshNodeClientSession = Effect.fn(function* ({
|
|
38
|
+
webmeshNode,
|
|
39
|
+
sessionInfo,
|
|
40
|
+
sharedWorker,
|
|
41
|
+
devtoolsEnabled,
|
|
42
|
+
schema,
|
|
43
|
+
}: {
|
|
44
|
+
webmeshNode: Webmesh.MeshNode
|
|
45
|
+
sessionInfo: Devtools.SessionInfo.SessionInfo
|
|
46
|
+
sharedWorker: Worker.SerializedWorkerPool<typeof DevtoolsWeb.WorkerSchema.Request.Type>
|
|
47
|
+
devtoolsEnabled: boolean
|
|
48
|
+
schema: LiveStoreSchema
|
|
49
|
+
}) {
|
|
50
|
+
if (devtoolsEnabled) {
|
|
51
|
+
const { clientId, sessionId, storeId } = sessionInfo
|
|
52
|
+
yield* logDevtoolsUrl({ clientId, sessionId, schema, storeId })
|
|
53
|
+
|
|
54
|
+
// This additional sessioninfo broadcast channel is needed since we can't use the shared worker
|
|
55
|
+
// as it's currently storeId-specific
|
|
56
|
+
yield* Devtools.SessionInfo.provideSessionInfo({
|
|
57
|
+
webChannel: yield* DevtoolsWeb.makeSessionInfoBroadcastChannel,
|
|
58
|
+
sessionInfo,
|
|
59
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
|
|
60
|
+
|
|
61
|
+
yield* Effect.gen(function* () {
|
|
62
|
+
const clientSessionStaticChannel = yield* DevtoolsWeb.makeStaticClientSessionChannel.clientSession
|
|
63
|
+
|
|
64
|
+
yield* clientSessionStaticChannel.send(
|
|
65
|
+
DevtoolsWeb.ClientSessionContentscriptMainReq.make({ clientId, sessionId, storeId }),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
const { tabId } = yield* clientSessionStaticChannel.listen.pipe(Stream.flatten(), Stream.runHead, Effect.flatten)
|
|
69
|
+
|
|
70
|
+
const contentscriptMainNodeName = DevtoolsWeb.makeNodeName.browserExtension.contentscriptMain(tabId)
|
|
71
|
+
|
|
72
|
+
const contentscriptMainChannel = yield* WebChannel.windowChannel({
|
|
73
|
+
listenWindow: window,
|
|
74
|
+
sendWindow: window,
|
|
75
|
+
schema: Webmesh.WebmeshSchema.Packet,
|
|
76
|
+
ids: { own: webmeshNode.nodeName, other: contentscriptMainNodeName },
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
yield* webmeshNode.addEdge({ target: contentscriptMainNodeName, edgeChannel: contentscriptMainChannel })
|
|
80
|
+
}).pipe(
|
|
81
|
+
Effect.withSpan('@livestore/adapter-web:client-session:devtools:browser-extension'),
|
|
82
|
+
Effect.tapCauseLogPretty,
|
|
83
|
+
Effect.forkScoped,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
yield* DevtoolsWeb.connectViaWorker({
|
|
87
|
+
node: webmeshNode,
|
|
88
|
+
target: DevtoolsWeb.makeNodeName.sharedWorker({ storeId }),
|
|
89
|
+
worker: sharedWorker,
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
})
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Adapter, ClientSession, LockStatus } from '@livestore/common'
|
|
2
2
|
import {
|
|
3
|
-
Devtools,
|
|
4
3
|
IntentionalShutdownCause,
|
|
5
4
|
liveStoreVersion,
|
|
6
5
|
makeClientSession,
|
|
@@ -11,7 +10,6 @@ import {
|
|
|
11
10
|
// NOTE We're using a non-relative import here for Vite to properly resolve the import during app builds
|
|
12
11
|
// import LiveStoreSharedWorker from '@livestore/adapter-web/internal-shared-worker?sharedworker'
|
|
13
12
|
import { EventSequenceNumber, SystemTables } from '@livestore/common/schema'
|
|
14
|
-
import * as DevtoolsWeb from '@livestore/devtools-web-common/web-channel'
|
|
15
13
|
import { sqliteDbFactory } from '@livestore/sqlite-wasm/browser'
|
|
16
14
|
import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm'
|
|
17
15
|
import { isDevEnv, shouldNeverHappen, tryAsFunctionAndNew } from '@livestore/utils'
|
|
@@ -27,20 +25,18 @@ import {
|
|
|
27
25
|
Schema,
|
|
28
26
|
Stream,
|
|
29
27
|
SubscriptionRef,
|
|
30
|
-
WebChannel,
|
|
31
28
|
WebLock,
|
|
32
29
|
Worker,
|
|
33
30
|
WorkerError,
|
|
34
31
|
} from '@livestore/utils/effect'
|
|
35
32
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
36
|
-
import * as Webmesh from '@livestore/webmesh'
|
|
37
33
|
|
|
38
34
|
import * as OpfsUtils from '../../opfs-utils.js'
|
|
39
35
|
import { readPersistedAppDbFromClientSession, resetPersistedDataFromClientSession } from '../common/persisted-sqlite.js'
|
|
40
36
|
import { makeShutdownChannel } from '../common/shutdown-channel.js'
|
|
41
37
|
import { DedicatedWorkerDisconnectBroadcast, makeWorkerDisconnectChannel } from '../common/worker-disconnect-channel.js'
|
|
42
38
|
import * as WorkerSchema from '../common/worker-schema.js'
|
|
43
|
-
import {
|
|
39
|
+
import { connectWebmeshNodeClientSession } from './client-session-devtools.js'
|
|
44
40
|
|
|
45
41
|
// NOTE we're starting to initialize the sqlite wasm binary here to speed things up
|
|
46
42
|
const sqlite3Promise = loadSqlite3Wasm()
|
|
@@ -426,6 +422,8 @@ export const makePersistedAdapter =
|
|
|
426
422
|
),
|
|
427
423
|
}
|
|
428
424
|
|
|
425
|
+
const sharedWorker = yield* Fiber.join(sharedWorkerFiber)
|
|
426
|
+
|
|
429
427
|
const clientSession = yield* makeClientSession({
|
|
430
428
|
...adapterArgs,
|
|
431
429
|
sqliteDb,
|
|
@@ -436,55 +434,8 @@ export const makePersistedAdapter =
|
|
|
436
434
|
isLeader: true,
|
|
437
435
|
leaderThread,
|
|
438
436
|
webmeshMode: 'direct',
|
|
439
|
-
connectWebmeshNode:
|
|
440
|
-
|
|
441
|
-
yield* logDevtoolsUrl({ clientId, sessionId, schema, storeId })
|
|
442
|
-
|
|
443
|
-
// This additional sessioninfo broadcast channel is needed since we can't use the shared worker
|
|
444
|
-
// as it's currently storeId-specific
|
|
445
|
-
yield* Devtools.SessionInfo.provideSessionInfo({
|
|
446
|
-
webChannel: yield* DevtoolsWeb.makeSessionInfoBroadcastChannel,
|
|
447
|
-
sessionInfo,
|
|
448
|
-
}).pipe(Effect.tapCauseLogPretty, Effect.forkScoped)
|
|
449
|
-
|
|
450
|
-
yield* Effect.gen(function* () {
|
|
451
|
-
const clientSessionStaticChannel = yield* DevtoolsWeb.makeStaticClientSessionChannel.clientSession
|
|
452
|
-
|
|
453
|
-
yield* clientSessionStaticChannel.send(
|
|
454
|
-
DevtoolsWeb.ClientSessionContentscriptMainReq.make({ clientId, sessionId, storeId }),
|
|
455
|
-
)
|
|
456
|
-
|
|
457
|
-
const { tabId } = yield* clientSessionStaticChannel.listen.pipe(
|
|
458
|
-
Stream.flatten(),
|
|
459
|
-
Stream.runHead,
|
|
460
|
-
Effect.flatten,
|
|
461
|
-
)
|
|
462
|
-
|
|
463
|
-
const contentscriptMainNodeName = DevtoolsWeb.makeNodeName.browserExtension.contentscriptMain(tabId)
|
|
464
|
-
|
|
465
|
-
const contentscriptMainChannel = yield* WebChannel.windowChannel({
|
|
466
|
-
listenWindow: window,
|
|
467
|
-
sendWindow: window,
|
|
468
|
-
schema: Webmesh.WebmeshSchema.Packet,
|
|
469
|
-
ids: { own: webmeshNode.nodeName, other: contentscriptMainNodeName },
|
|
470
|
-
})
|
|
471
|
-
|
|
472
|
-
yield* webmeshNode.addEdge({ target: contentscriptMainNodeName, edgeChannel: contentscriptMainChannel })
|
|
473
|
-
}).pipe(
|
|
474
|
-
Effect.withSpan('@livestore/adapter-web:client-session:devtools:browser-extension'),
|
|
475
|
-
Effect.tapCauseLogPretty,
|
|
476
|
-
Effect.forkScoped,
|
|
477
|
-
)
|
|
478
|
-
|
|
479
|
-
const sharedWorker = yield* Fiber.join(sharedWorkerFiber)
|
|
480
|
-
|
|
481
|
-
yield* DevtoolsWeb.connectViaWorker({
|
|
482
|
-
node: webmeshNode,
|
|
483
|
-
target: DevtoolsWeb.makeNodeName.sharedWorker({ storeId }),
|
|
484
|
-
worker: sharedWorker,
|
|
485
|
-
})
|
|
486
|
-
}
|
|
487
|
-
}),
|
|
437
|
+
connectWebmeshNode: ({ sessionInfo, webmeshNode }) =>
|
|
438
|
+
connectWebmeshNodeClientSession({ webmeshNode, sessionInfo, sharedWorker, devtoolsEnabled, schema }),
|
|
488
439
|
registerBeforeUnload: (onBeforeUnload) => {
|
|
489
440
|
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
490
441
|
window.addEventListener('beforeunload', onBeforeUnload)
|