@livestore/adapter-node 0.4.0-dev.21 → 0.4.0-dev.23
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/client-session/adapter.d.ts +1 -0
- package/dist/client-session/adapter.d.ts.map +1 -1
- package/dist/client-session/adapter.js +21 -24
- package/dist/client-session/adapter.js.map +1 -1
- package/dist/devtools/devtools-server.d.ts.map +1 -1
- package/dist/devtools/devtools-server.js +14 -6
- package/dist/devtools/devtools-server.js.map +1 -1
- package/dist/devtools/mod.d.ts +1 -1
- package/dist/devtools/mod.d.ts.map +1 -1
- package/dist/devtools/mod.js +1 -1
- package/dist/devtools/mod.js.map +1 -1
- package/dist/devtools/vite-dev-server.d.ts +25 -3
- package/dist/devtools/vite-dev-server.d.ts.map +1 -1
- package/dist/devtools/vite-dev-server.js +40 -5
- package/dist/devtools/vite-dev-server.js.map +1 -1
- package/dist/leader-thread-shared.js +2 -2
- package/dist/leader-thread-shared.js.map +1 -1
- package/dist/make-leader-worker.d.ts +1 -1
- package/dist/make-leader-worker.d.ts.map +1 -1
- package/dist/make-leader-worker.js +15 -17
- package/dist/make-leader-worker.js.map +1 -1
- package/dist/shutdown-channel.d.ts.map +1 -1
- package/dist/shutdown-channel.js.map +1 -1
- package/dist/worker-schema.d.ts +31 -27
- package/dist/worker-schema.d.ts.map +1 -1
- package/dist/worker-schema.js +16 -16
- package/dist/worker-schema.js.map +1 -1
- package/package.json +59 -19
- package/src/client-session/adapter.ts +32 -47
- package/src/devtools/devtools-server.ts +22 -10
- package/src/devtools/mod.ts +1 -1
- package/src/devtools/vite-dev-server.ts +60 -6
- package/src/leader-thread-shared.ts +4 -4
- package/src/make-leader-worker.ts +38 -47
- package/src/shutdown-channel.ts +1 -0
- package/src/worker-schema.ts +16 -16
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { hostname } from 'node:os'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
+
import type { URL } from 'node:url'
|
|
3
4
|
import * as WT from 'node:worker_threads'
|
|
5
|
+
|
|
4
6
|
import {
|
|
5
7
|
type Adapter,
|
|
6
8
|
type BootStatus,
|
|
7
9
|
ClientSessionLeaderThreadProxy,
|
|
8
10
|
IntentionalShutdownCause,
|
|
11
|
+
isWorkerTransportError,
|
|
9
12
|
type LockStatus,
|
|
10
13
|
type MakeSqliteDb,
|
|
11
14
|
makeClientSession,
|
|
12
|
-
type SyncError,
|
|
13
15
|
type SyncOptions,
|
|
14
16
|
UnknownError,
|
|
15
17
|
} from '@livestore/common'
|
|
@@ -27,7 +29,7 @@ import {
|
|
|
27
29
|
Fiber,
|
|
28
30
|
FileSystem,
|
|
29
31
|
Layer,
|
|
30
|
-
|
|
32
|
+
Option,
|
|
31
33
|
Queue,
|
|
32
34
|
Schedule,
|
|
33
35
|
Schema,
|
|
@@ -35,7 +37,6 @@ import {
|
|
|
35
37
|
Subscribable,
|
|
36
38
|
SubscriptionRef,
|
|
37
39
|
Worker,
|
|
38
|
-
WorkerError,
|
|
39
40
|
} from '@livestore/utils/effect'
|
|
40
41
|
import { PlatformNode } from '@livestore/utils/node'
|
|
41
42
|
import * as Webmesh from '@livestore/webmesh'
|
|
@@ -232,7 +233,7 @@ const makeAdapterImpl = ({
|
|
|
232
233
|
yield* shutdownChannel.listen.pipe(
|
|
233
234
|
Stream.flatten(),
|
|
234
235
|
Stream.tap((cause) =>
|
|
235
|
-
shutdown(cause._tag === '
|
|
236
|
+
shutdown(cause._tag === 'IntentionalShutdownCause' ? Exit.succeed(cause) : Exit.fail(cause)),
|
|
236
237
|
),
|
|
237
238
|
Stream.runDrain,
|
|
238
239
|
Effect.interruptible,
|
|
@@ -246,7 +247,7 @@ const makeAdapterImpl = ({
|
|
|
246
247
|
const lockStatus = yield* SubscriptionRef.make<LockStatus>('has-lock')
|
|
247
248
|
|
|
248
249
|
const devtoolsOptions: WorkerSchema.LeaderWorkerInnerInitialMessage['devtools'] =
|
|
249
|
-
devtoolsEnabled && devtoolsOptionsInput !== undefined
|
|
250
|
+
devtoolsEnabled === true && devtoolsOptionsInput !== undefined
|
|
250
251
|
? {
|
|
251
252
|
enabled: true,
|
|
252
253
|
schemaPath:
|
|
@@ -297,7 +298,7 @@ const makeAdapterImpl = ({
|
|
|
297
298
|
sqliteDb: syncInMemoryDb,
|
|
298
299
|
webmeshMode: 'proxy',
|
|
299
300
|
connectWebmeshNode: Effect.fnUntraced(function* ({ webmeshNode }) {
|
|
300
|
-
if (devtoolsOptions.enabled) {
|
|
301
|
+
if (devtoolsOptions.enabled === true) {
|
|
301
302
|
yield* Webmesh.connectViaWebSocket({
|
|
302
303
|
node: webmeshNode,
|
|
303
304
|
url: `ws://${devtoolsOptions.host}:${devtoolsOptions.port}`,
|
|
@@ -413,7 +414,11 @@ const makeLocalLeaderThread = ({
|
|
|
413
414
|
options,
|
|
414
415
|
}),
|
|
415
416
|
},
|
|
416
|
-
initialState: {
|
|
417
|
+
initialState: {
|
|
418
|
+
leaderHead: initialLeaderHead,
|
|
419
|
+
migrationsReport: initialState.migrationsReport,
|
|
420
|
+
storageMode: 'persisted',
|
|
421
|
+
},
|
|
417
422
|
export: Effect.sync(() => dbState.export()),
|
|
418
423
|
getEventlogData: Effect.sync(() => dbEventlog.export()),
|
|
419
424
|
syncState: syncProcessor.syncState,
|
|
@@ -442,7 +447,7 @@ const makeWorkerLeaderThread = ({
|
|
|
442
447
|
syncPayloadEncoded,
|
|
443
448
|
testing,
|
|
444
449
|
}: {
|
|
445
|
-
shutdown: (cause: Exit.Exit<IntentionalShutdownCause, UnknownError
|
|
450
|
+
shutdown: (cause: Exit.Exit<IntentionalShutdownCause, UnknownError>) => Effect.Effect<void>
|
|
446
451
|
storeId: string
|
|
447
452
|
clientId: string
|
|
448
453
|
sessionId: string
|
|
@@ -458,8 +463,8 @@ const makeWorkerLeaderThread = ({
|
|
|
458
463
|
}) =>
|
|
459
464
|
Effect.gen(function* () {
|
|
460
465
|
const nodeWorker = new WT.Worker(workerUrl, {
|
|
461
|
-
execArgv: process.env.DEBUG_WORKER ? ['--inspect --enable-source-maps'] : ['--enable-source-maps'],
|
|
462
|
-
argv: [Schema.
|
|
466
|
+
execArgv: process.env.DEBUG_WORKER !== undefined ? ['--inspect --enable-source-maps'] : ['--enable-source-maps'],
|
|
467
|
+
argv: [yield* Schema.encode(WorkerSchema.WorkerArgv)({ storeId, clientId, sessionId, extraArgs: workerExtraArgs }).pipe(Effect.orDie)],
|
|
463
468
|
})
|
|
464
469
|
const nodeWorkerLayer = yield* Layer.build(PlatformNode.NodeWorker.layer(() => nodeWorker))
|
|
465
470
|
|
|
@@ -481,47 +486,30 @@ const makeWorkerLeaderThread = ({
|
|
|
481
486
|
Effect.withSpan('@livestore/adapter-node:adapter:setupLeaderThread'),
|
|
482
487
|
)
|
|
483
488
|
|
|
484
|
-
const runInWorker = <
|
|
485
|
-
req:
|
|
486
|
-
):
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
(worker.executeEffect(req) as any).pipe(
|
|
489
|
+
const runInWorker = <A, I, E, EI, R>(
|
|
490
|
+
req: WorkerSchema.LeaderWorkerInnerRequest & Schema.WithResult<A, I, E, EI, R>,
|
|
491
|
+
): Effect.Effect<A, E, R> =>
|
|
492
|
+
worker.executeEffect(req).pipe(
|
|
493
|
+
Effect.catchIf(isWorkerTransportError, (e) => Effect.die(e)),
|
|
490
494
|
Effect.logWarnIfTakesLongerThan({
|
|
491
495
|
label: `@livestore/adapter-node:client-session:runInWorker:${req._tag}`,
|
|
492
496
|
duration: 2000,
|
|
493
497
|
}),
|
|
494
498
|
Effect.withSpan(`@livestore/adapter-node:client-session:runInWorker:${req._tag}`),
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
),
|
|
502
|
-
Effect.catchAllDefect((cause) => new UnknownError({ cause })),
|
|
503
|
-
) as any
|
|
504
|
-
|
|
505
|
-
const runInWorkerStream = <TReq extends typeof WorkerSchema.LeaderWorkerInnerRequest.Type>(
|
|
506
|
-
req: TReq,
|
|
507
|
-
): TReq extends Schema.WithResult<infer A, infer _I, infer _E, infer _EI, infer R>
|
|
508
|
-
? Stream.Stream<A, UnknownError, R>
|
|
509
|
-
: never =>
|
|
510
|
-
worker.execute(req as any).pipe(
|
|
511
|
-
Stream.mapError((cause) =>
|
|
512
|
-
Schema.is(UnknownError)(cause)
|
|
513
|
-
? cause
|
|
514
|
-
: ParseResult.isParseError(cause) || Schema.is(WorkerError.WorkerError)(cause)
|
|
515
|
-
? new UnknownError({ cause })
|
|
516
|
-
: cause,
|
|
517
|
-
),
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
const runInWorkerStream = <A, I, E, EI, R>(
|
|
502
|
+
req: WorkerSchema.LeaderWorkerInnerRequest & Schema.WithResult<A, I, E, EI, R>,
|
|
503
|
+
): Stream.Stream<A, E, R> =>
|
|
504
|
+
worker.execute(req).pipe(
|
|
505
|
+
Stream.refineOrDie((e) => isWorkerTransportError(e) === true ? Option.none() : Option.some(e)),
|
|
518
506
|
Stream.withSpan(`@livestore/adapter-node:client-session:runInWorkerStream:${req._tag}`),
|
|
519
|
-
)
|
|
507
|
+
)
|
|
520
508
|
|
|
521
509
|
const bootStatusFiber = yield* runInWorkerStream(new WorkerSchema.LeaderWorkerInnerBootStatusStream()).pipe(
|
|
522
510
|
Stream.tap((bootStatus) => Queue.offer(bootStatusQueue, bootStatus)),
|
|
523
511
|
Stream.runDrain,
|
|
524
|
-
Effect.tapErrorCause((cause) => (Cause.isInterruptedOnly(cause) ? Effect.void : shutdown(Exit.failCause(cause)))),
|
|
512
|
+
Effect.tapErrorCause((cause) => (Cause.isInterruptedOnly(cause) === true ? Effect.void : shutdown(Exit.failCause(cause)))),
|
|
525
513
|
Effect.interruptible,
|
|
526
514
|
Effect.tapCauseLogPretty,
|
|
527
515
|
Effect.forkScoped,
|
|
@@ -536,8 +524,7 @@ const makeWorkerLeaderThread = ({
|
|
|
536
524
|
const initialLeaderHead = yield* runInWorker(new WorkerSchema.LeaderWorkerInnerGetLeaderHead())
|
|
537
525
|
|
|
538
526
|
const bootResult = yield* runInWorker(new WorkerSchema.LeaderWorkerInnerGetRecreateSnapshot()).pipe(
|
|
539
|
-
Effect.
|
|
540
|
-
UnknownError.mapToUnknownError,
|
|
527
|
+
Effect.timeoutOrDie(10_000),
|
|
541
528
|
Effect.withSpan('@livestore/adapter-node:client-session:export'),
|
|
542
529
|
)
|
|
543
530
|
|
|
@@ -561,23 +548,21 @@ const makeWorkerLeaderThread = ({
|
|
|
561
548
|
initialState: {
|
|
562
549
|
leaderHead: initialLeaderHead,
|
|
563
550
|
migrationsReport: bootResult.migrationsReport,
|
|
551
|
+
storageMode: 'persisted',
|
|
564
552
|
},
|
|
565
553
|
export: runInWorker(new WorkerSchema.LeaderWorkerInnerExport()).pipe(
|
|
566
|
-
Effect.
|
|
567
|
-
UnknownError.mapToUnknownError,
|
|
554
|
+
Effect.timeoutOrDie(10_000),
|
|
568
555
|
Effect.withSpan('@livestore/adapter-node:client-session:export'),
|
|
569
556
|
),
|
|
570
557
|
getEventlogData: Effect.dieMessage('Not implemented'),
|
|
571
558
|
syncState: Subscribable.make({
|
|
572
559
|
get: runInWorker(new WorkerSchema.LeaderWorkerInnerGetLeaderSyncState()).pipe(
|
|
573
|
-
UnknownError.mapToUnknownError,
|
|
574
560
|
Effect.withSpan('@livestore/adapter-node:client-session:getLeaderSyncState'),
|
|
575
561
|
),
|
|
576
562
|
changes: runInWorkerStream(new WorkerSchema.LeaderWorkerInnerSyncStateStream()).pipe(Stream.orDie),
|
|
577
563
|
}),
|
|
578
564
|
sendDevtoolsMessage: (message) =>
|
|
579
565
|
runInWorker(new WorkerSchema.LeaderWorkerInnerExtraDevtoolsMessage({ message })).pipe(
|
|
580
|
-
UnknownError.mapToUnknownError,
|
|
581
566
|
Effect.withSpan('@livestore/adapter-node:client-session:devtoolsMessageForLeader'),
|
|
582
567
|
),
|
|
583
568
|
networkStatus: Subscribable.make({
|
|
@@ -20,6 +20,16 @@ import { makeMeshNode, makeWebSocketEdge } from '@livestore/webmesh'
|
|
|
20
20
|
|
|
21
21
|
import { makeViteMiddleware } from './vite-dev-server.ts'
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Determines if a request URL should be routed to the Vite middleware.
|
|
25
|
+
* Includes LiveStore devtools paths and Vite internal paths like `/@fs/`, `/@vite/`, etc.
|
|
26
|
+
*/
|
|
27
|
+
const shouldRouteToVite = (url: string): boolean =>
|
|
28
|
+
url.startsWith('/_livestore') ||
|
|
29
|
+
url.startsWith('/@fs') ||
|
|
30
|
+
url.startsWith('/@vite') ||
|
|
31
|
+
url.startsWith('/@react-refresh')
|
|
32
|
+
|
|
23
33
|
/**
|
|
24
34
|
* Starts a devtools HTTP/WS server which serves ...
|
|
25
35
|
* - the Devtools UI via Vite
|
|
@@ -39,11 +49,12 @@ export const startDevtoolsServer = ({
|
|
|
39
49
|
Effect.gen(function* () {
|
|
40
50
|
const viteMiddleware = yield* makeViteMiddleware({
|
|
41
51
|
mode: { _tag: 'node', url: `http://${host}:${port}` },
|
|
42
|
-
schemaPath:
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
schemaPath:
|
|
53
|
+
isReadonlyArray(schemaPath) === true
|
|
54
|
+
? schemaPath.map((schemaPath) => path.resolve(process.cwd(), schemaPath))
|
|
55
|
+
: path.resolve(process.cwd(), schemaPath),
|
|
45
56
|
viteConfig: (viteConfig) => {
|
|
46
|
-
if (LS_DEV) {
|
|
57
|
+
if (LS_DEV === true) {
|
|
47
58
|
viteConfig.server ??= {}
|
|
48
59
|
viteConfig.server.fs ??= {}
|
|
49
60
|
viteConfig.server.fs.strict = false
|
|
@@ -63,7 +74,7 @@ export const startDevtoolsServer = ({
|
|
|
63
74
|
const handler = Effect.gen(function* () {
|
|
64
75
|
const req = yield* HttpServerRequest.HttpServerRequest
|
|
65
76
|
|
|
66
|
-
if (Headers.has(req.headers, 'upgrade')) {
|
|
77
|
+
if (Headers.has(req.headers, 'upgrade') === true) {
|
|
67
78
|
// yield* Effect.logDebug(`WS Relay ${relayNodeName}: WS upgrade request ${req.url}`)
|
|
68
79
|
|
|
69
80
|
const socket = yield* req.upgrade
|
|
@@ -81,7 +92,7 @@ export const startDevtoolsServer = ({
|
|
|
81
92
|
.addEdge({ target: from, edgeChannel: webChannel, replaceIfExists: true })
|
|
82
93
|
.pipe(Effect.acquireRelease(() => node.removeEdge(from).pipe(Effect.orDie)))
|
|
83
94
|
|
|
84
|
-
if (LS_DEV) {
|
|
95
|
+
if (LS_DEV === true) {
|
|
85
96
|
yield* Effect.log(`WS Relay ${relayNodeName}: added edge from '${from}'`)
|
|
86
97
|
yield* Effect.addFinalizerLog(`WS Relay ${relayNodeName}: removed edge from '${from}'`)
|
|
87
98
|
}
|
|
@@ -96,7 +107,7 @@ export const startDevtoolsServer = ({
|
|
|
96
107
|
} else {
|
|
97
108
|
if (req.url === '/' || req.url === '') {
|
|
98
109
|
return HttpServerResponse.redirect('/_livestore/node')
|
|
99
|
-
} else if (req.url
|
|
110
|
+
} else if (shouldRouteToVite(req.url) === true) {
|
|
100
111
|
// Here we're delegating to the Vite middleware
|
|
101
112
|
|
|
102
113
|
// TODO replace this once @effect/platform-node supports Node HTTP middlewares
|
|
@@ -114,9 +125,10 @@ export const startDevtoolsServer = ({
|
|
|
114
125
|
return HttpServerResponse.text('Not found')
|
|
115
126
|
}).pipe(Effect.tapCauseLogPretty, Effect.interruptible)
|
|
116
127
|
|
|
117
|
-
const sessionSuffix =
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
const sessionSuffix =
|
|
129
|
+
clientSessionInfo !== undefined
|
|
130
|
+
? `/${clientSessionInfo.storeId}/${clientSessionInfo.clientId}/${clientSessionInfo.sessionId}/${clientSessionInfo.schemaAlias}`
|
|
131
|
+
: '?autoconnect'
|
|
120
132
|
|
|
121
133
|
// Use `localhost` instead of `0.0.0.0` as it doesn't have the `navigator.locks` web adapter limitation (https://share.cleanshot.com/nHBnmk6S)
|
|
122
134
|
const maybeLocalhost = host === '0.0.0.0' ? 'localhost' : host
|
package/src/devtools/mod.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { startDevtoolsServer } from './devtools-server.ts'
|
|
2
2
|
export type { ViteDevtoolsOptions } from './vite-dev-server.ts'
|
|
3
|
-
export { makeViteMiddleware } from './vite-dev-server.ts'
|
|
3
|
+
export { DevtoolsViteNotInstalledError, makeViteMiddleware } from './vite-dev-server.ts'
|
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
|
|
3
|
+
import type * as Vite from 'vite'
|
|
4
|
+
|
|
3
5
|
import type { Devtools } from '@livestore/common'
|
|
4
6
|
import { UnknownError } from '@livestore/common'
|
|
5
|
-
import { livestoreDevtoolsPlugin } from '@livestore/devtools-vite'
|
|
6
7
|
import { isReadonlyArray } from '@livestore/utils'
|
|
7
|
-
import { Effect } from '@livestore/utils/effect'
|
|
8
|
+
import { Effect, Schema } from '@livestore/utils/effect'
|
|
8
9
|
import { getFreePort } from '@livestore/utils/node'
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when @livestore/devtools-vite is not installed.
|
|
13
|
+
* This is a peer dependency that must be installed separately.
|
|
14
|
+
*/
|
|
15
|
+
export class DevtoolsViteNotInstalledError extends Schema.TaggedError<DevtoolsViteNotInstalledError>(
|
|
16
|
+
'~@livestore/adapter-node/DevtoolsViteNotInstalledError',
|
|
17
|
+
)('DevtoolsViteNotInstalledError', {
|
|
18
|
+
cause: Schema.Defect,
|
|
19
|
+
}) {
|
|
20
|
+
override get message(): string {
|
|
21
|
+
return (
|
|
22
|
+
`@livestore/devtools-vite is required for devtools but not installed. ` +
|
|
23
|
+
`Install it with: pnpm add @livestore/devtools-vite@<version>. ` +
|
|
24
|
+
`Make sure to use the same version as @livestore/adapter-node.`
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Error thrown when vite is not installed for the devtools server path. */
|
|
30
|
+
export class ViteNotInstalledError extends Schema.TaggedError<ViteNotInstalledError>(
|
|
31
|
+
'~@livestore/adapter-node/ViteNotInstalledError',
|
|
32
|
+
)('ViteNotInstalledError', {
|
|
33
|
+
cause: Schema.Defect,
|
|
34
|
+
}) {
|
|
35
|
+
override get message(): string {
|
|
36
|
+
return (
|
|
37
|
+
`vite is required for @livestore/adapter-node/devtools but not installed. ` +
|
|
38
|
+
`Install it with: pnpm add -D vite@<version>.`
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
10
42
|
|
|
11
43
|
export type ViteDevtoolsOptions = {
|
|
12
44
|
viteConfig?: (config: Vite.UserConfig) => Vite.UserConfig
|
|
@@ -26,8 +58,13 @@ export type ViteDevtoolsOptions = {
|
|
|
26
58
|
}
|
|
27
59
|
|
|
28
60
|
// NOTE this is currently also used in @livestore/devtools-expo
|
|
29
|
-
export const makeViteMiddleware = (
|
|
61
|
+
export const makeViteMiddleware = (
|
|
62
|
+
options: ViteDevtoolsOptions,
|
|
63
|
+
): Effect.Effect<Vite.ViteDevServer, DevtoolsViteNotInstalledError | ViteNotInstalledError | UnknownError> =>
|
|
30
64
|
Effect.gen(function* () {
|
|
65
|
+
const { livestoreDevtoolsPlugin } = yield* importDevtoolsVite()
|
|
66
|
+
const Vite = yield* importVite()
|
|
67
|
+
|
|
31
68
|
const cwd = process.cwd()
|
|
32
69
|
|
|
33
70
|
const hmrPort = yield* getFreePort.pipe(UnknownError.mapToUnknownError)
|
|
@@ -39,13 +76,13 @@ export const makeViteMiddleware = (options: ViteDevtoolsOptions): Effect.Effect<
|
|
|
39
76
|
port: hmrPort,
|
|
40
77
|
},
|
|
41
78
|
// Relaxing fs access for monorepo setup
|
|
42
|
-
fs: { strict: process.env.LS_DEV ? false : true },
|
|
79
|
+
fs: { strict: process.env.LS_DEV !== undefined ? false : true },
|
|
43
80
|
},
|
|
44
81
|
appType: 'spa',
|
|
45
82
|
base: '/_livestore/',
|
|
46
83
|
plugins: [
|
|
47
84
|
livestoreDevtoolsPlugin({
|
|
48
|
-
schemaPath: isReadonlyArray(options.schemaPath)
|
|
85
|
+
schemaPath: isReadonlyArray(options.schemaPath) === true
|
|
49
86
|
? options.schemaPath.map((schemaPath) => path.resolve(cwd, schemaPath))
|
|
50
87
|
: path.resolve(cwd, options.schemaPath),
|
|
51
88
|
mode: options.mode,
|
|
@@ -62,3 +99,20 @@ export const makeViteMiddleware = (options: ViteDevtoolsOptions): Effect.Effect<
|
|
|
62
99
|
|
|
63
100
|
return viteServer
|
|
64
101
|
}).pipe(Effect.withSpan('@livestore/adapter-node:devtools:makeViteServer'))
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Dynamically imports @livestore/devtools-vite.
|
|
105
|
+
* This package is a peer dependency and may not be installed.
|
|
106
|
+
*/
|
|
107
|
+
const importDevtoolsVite = () =>
|
|
108
|
+
Effect.tryPromise({
|
|
109
|
+
try: () => import('@livestore/devtools-vite'),
|
|
110
|
+
catch: (cause) => new DevtoolsViteNotInstalledError({ cause }),
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
/** Dynamically imports vite for the devtools-only server path. */
|
|
114
|
+
const importVite = () =>
|
|
115
|
+
Effect.tryPromise({
|
|
116
|
+
try: () => import('vite'),
|
|
117
|
+
catch: (cause) => new ViteNotInstalledError({ cause }),
|
|
118
|
+
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import inspector from 'node:inspector'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
|
-
if (process.execArgv.includes('--inspect')) {
|
|
4
|
+
if (process.execArgv.includes('--inspect') === true) {
|
|
5
5
|
inspector.open()
|
|
6
6
|
inspector.waitForDebugger()
|
|
7
7
|
}
|
|
@@ -64,13 +64,13 @@ export const makeLeaderThread = ({
|
|
|
64
64
|
Scope.Scope
|
|
65
65
|
> =>
|
|
66
66
|
Effect.gen(function* () {
|
|
67
|
-
const runtime = yield* Effect.runtime
|
|
67
|
+
const runtime = yield* Effect.runtime()
|
|
68
68
|
|
|
69
69
|
const schemaHashSuffix =
|
|
70
70
|
schema.state.sqlite.migrations.strategy === 'manual' ? 'fixed' : schema.state.sqlite.hash.toString()
|
|
71
71
|
|
|
72
72
|
const makeDb = (kind: 'state' | 'eventlog') => {
|
|
73
|
-
if (testing?.makeLeaderThread) {
|
|
73
|
+
if (testing?.makeLeaderThread !== undefined) {
|
|
74
74
|
return testing
|
|
75
75
|
.makeLeaderThread(makeSqliteDb)
|
|
76
76
|
.pipe(Effect.map(({ dbEventlog, dbState }) => (kind === 'state' ? dbState : dbEventlog)))
|
|
@@ -184,7 +184,7 @@ const makeDevtoolsOptions = ({
|
|
|
184
184
|
eventlog: dbEventlog.metadata.persistenceInfo,
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
return { node, persistenceInfo, mode: 'proxy' }
|
|
187
|
+
return { node, persistenceInfo, mode: 'proxy' as const }
|
|
188
188
|
}),
|
|
189
189
|
}
|
|
190
190
|
})
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import './thread-polyfill.ts'
|
|
2
|
-
|
|
3
2
|
import inspector from 'node:inspector'
|
|
4
3
|
|
|
5
|
-
if (process.execArgv.includes('--inspect')) {
|
|
4
|
+
if (process.execArgv.includes('--inspect') === true) {
|
|
6
5
|
inspector.open()
|
|
7
6
|
inspector.waitForDebugger()
|
|
8
7
|
}
|
|
9
8
|
|
|
9
|
+
import type * as otel from '@opentelemetry/api'
|
|
10
|
+
|
|
10
11
|
import type { SyncOptions } from '@livestore/common'
|
|
11
12
|
import { LogConfig, UnknownError } from '@livestore/common'
|
|
12
13
|
import type { StreamEventsOptions } from '@livestore/common/leader-thread'
|
|
@@ -17,7 +18,6 @@ import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm'
|
|
|
17
18
|
import { sqliteDbFactory } from '@livestore/sqlite-wasm/node'
|
|
18
19
|
import { Effect, FetchHttpClient, Layer, OtelTracer, Schema, Stream, WorkerRunner } from '@livestore/utils/effect'
|
|
19
20
|
import { PlatformNode } from '@livestore/utils/node'
|
|
20
|
-
import type * as otel from '@opentelemetry/api'
|
|
21
21
|
|
|
22
22
|
import type { TestingOverrides } from './leader-thread-shared.ts'
|
|
23
23
|
import { makeLeaderThread } from './leader-thread-shared.ts'
|
|
@@ -42,7 +42,7 @@ export const makeWorker = (options: WorkerOptions) => {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export const makeWorkerEffect = (options: WorkerOptions) => {
|
|
45
|
-
const TracingLive = options.otelOptions?.tracer
|
|
45
|
+
const TracingLive = options.otelOptions?.tracer !== undefined
|
|
46
46
|
? Layer.unwrapEffect(Effect.map(OtelTracer.make, Layer.setTracer)).pipe(
|
|
47
47
|
Layer.provideMerge(Layer.succeed(OtelTracer.OtelTracer, options.otelOptions.tracer)),
|
|
48
48
|
)
|
|
@@ -103,69 +103,60 @@ export const makeWorkerEffect = (options: WorkerOptions) => {
|
|
|
103
103
|
),
|
|
104
104
|
Export: () =>
|
|
105
105
|
Effect.andThen(LeaderThreadCtx, (_) => _.dbState.export()).pipe(
|
|
106
|
-
UnknownError.mapToUnknownError,
|
|
107
106
|
Effect.withSpan('@livestore/adapter-node:worker:Export'),
|
|
108
107
|
),
|
|
109
108
|
ExportEventlog: () =>
|
|
110
109
|
Effect.andThen(LeaderThreadCtx, (_) => _.dbEventlog.export()).pipe(
|
|
111
|
-
UnknownError.mapToUnknownError,
|
|
112
110
|
Effect.withSpan('@livestore/adapter-node:worker:ExportEventlog'),
|
|
113
111
|
),
|
|
114
|
-
GetLeaderHead: ()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
return yield* workerCtx.syncProcessor.syncState
|
|
123
|
-
}).pipe(UnknownError.mapToUnknownError, Effect.withSpan('@livestore/adapter-node:worker:GetLeaderSyncState')),
|
|
112
|
+
GetLeaderHead: Effect.fn('@livestore/adapter-node:worker:GetLeaderHead')(function* () {
|
|
113
|
+
const workerCtx = yield* LeaderThreadCtx
|
|
114
|
+
return Eventlog.getClientHeadFromDb(workerCtx.dbEventlog)
|
|
115
|
+
}),
|
|
116
|
+
GetLeaderSyncState: Effect.fn('@livestore/adapter-node:worker:GetLeaderSyncState')(function* () {
|
|
117
|
+
const workerCtx = yield* LeaderThreadCtx
|
|
118
|
+
return yield* workerCtx.syncProcessor.syncState
|
|
119
|
+
}),
|
|
124
120
|
SyncStateStream: () =>
|
|
125
121
|
Effect.gen(function* () {
|
|
126
122
|
const workerCtx = yield* LeaderThreadCtx
|
|
127
123
|
return workerCtx.syncProcessor.syncState.changes
|
|
128
124
|
}).pipe(Stream.unwrapScoped),
|
|
129
|
-
GetNetworkStatus: ()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}).pipe(UnknownError.mapToUnknownError, Effect.withSpan('@livestore/adapter-node:worker:GetNetworkStatus')),
|
|
125
|
+
GetNetworkStatus: Effect.fn('@livestore/adapter-node:worker:GetNetworkStatus')(function* () {
|
|
126
|
+
const workerCtx = yield* LeaderThreadCtx
|
|
127
|
+
return yield* workerCtx.networkStatus
|
|
128
|
+
}),
|
|
134
129
|
NetworkStatusStream: () =>
|
|
135
130
|
Effect.gen(function* () {
|
|
136
131
|
const workerCtx = yield* LeaderThreadCtx
|
|
137
132
|
return workerCtx.networkStatus.changes
|
|
138
133
|
}).pipe(Stream.unwrapScoped),
|
|
139
|
-
GetRecreateSnapshot: ()
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
Effect.gen(function* () {
|
|
153
|
-
// const { db, dbEventlog } = yield* LeaderThreadCtx
|
|
154
|
-
yield* Effect.logDebug('[@livestore/adapter-node:worker] Shutdown')
|
|
134
|
+
GetRecreateSnapshot: Effect.fn('@livestore/adapter-node:worker:GetRecreateSnapshot')(function* () {
|
|
135
|
+
const workerCtx = yield* LeaderThreadCtx
|
|
136
|
+
// const result = yield* Deferred.await(workerCtx.initialSetupDeferred)
|
|
137
|
+
// NOTE we can only return the cached snapshot once as it's transferred (i.e. disposed), so we need to set it to undefined
|
|
138
|
+
// const cachedSnapshot =
|
|
139
|
+
// result._tag === 'Recreate' ? yield* Ref.getAndSet(result.snapshotRef, undefined) : undefined
|
|
140
|
+
// return cachedSnapshot ?? workerCtx.db.export()
|
|
141
|
+
const snapshot = workerCtx.dbState.export()
|
|
142
|
+
return { snapshot, migrationsReport: workerCtx.initialState.migrationsReport }
|
|
143
|
+
}),
|
|
144
|
+
Shutdown: Effect.fn('@livestore/adapter-node:worker:Shutdown')(function* () {
|
|
145
|
+
// const { db, dbEventlog } = yield* LeaderThreadCtx
|
|
146
|
+
yield* Effect.logDebug('[@livestore/adapter-node:worker] Shutdown')
|
|
155
147
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
148
|
+
// if (devtools.enabled) {
|
|
149
|
+
// yield* FiberSet.clear(devtools.connections)
|
|
150
|
+
// }
|
|
151
|
+
// db.close()
|
|
152
|
+
// dbEventlog.close()
|
|
161
153
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
154
|
+
// Buy some time for Otel to flush
|
|
155
|
+
// TODO find a cleaner way to do this
|
|
156
|
+
// yield* Effect.sleep(1000)
|
|
157
|
+
}),
|
|
166
158
|
ExtraDevtoolsMessage: ({ message }) =>
|
|
167
159
|
Effect.andThen(LeaderThreadCtx, (_) => _.extraIncomingMessagesQueue.offer(message)).pipe(
|
|
168
|
-
UnknownError.mapToUnknownError,
|
|
169
160
|
Effect.withSpan('@livestore/adapter-node:worker:ExtraDevtoolsMessage'),
|
|
170
161
|
),
|
|
171
162
|
}).pipe(
|