@livestore/adapter-node 0.4.0-dev.20 → 0.4.0-dev.22
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 +67 -2
- package/dist/client-session/adapter.d.ts.map +1 -1
- package/dist/client-session/adapter.js +80 -4
- 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 +9 -1
- package/dist/devtools/devtools-server.js.map +1 -1
- package/dist/make-leader-worker.d.ts.map +1 -1
- package/dist/make-leader-worker.js +10 -1
- package/dist/make-leader-worker.js.map +1 -1
- package/dist/worker-schema.d.ts +54 -4
- package/dist/worker-schema.d.ts.map +1 -1
- package/dist/worker-schema.js +8 -1
- package/dist/worker-schema.js.map +1 -1
- package/package.json +6 -6
- package/src/client-session/adapter.ts +85 -4
- package/src/devtools/devtools-server.ts +11 -1
- package/src/make-leader-worker.ts +16 -1
- package/src/worker-schema.ts +11 -0
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
type SyncOptions,
|
|
14
14
|
UnknownError,
|
|
15
15
|
} from '@livestore/common'
|
|
16
|
-
import { Eventlog, LeaderThreadCtx } from '@livestore/common/leader-thread'
|
|
16
|
+
import { Eventlog, LeaderThreadCtx, streamEventsWithSyncState } from '@livestore/common/leader-thread'
|
|
17
17
|
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
18
18
|
import { LiveStoreEvent } from '@livestore/common/schema'
|
|
19
19
|
import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm'
|
|
@@ -88,7 +88,43 @@ export interface NodeAdapterOptions {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Creates a single-threaded LiveStore adapter for Node.js applications.
|
|
93
|
+
*
|
|
94
|
+
* This adapter runs the leader thread (persistence and sync) in the same thread as
|
|
95
|
+
* your application. Suitable for CLI tools, scripts, and applications where simplicity
|
|
96
|
+
* is preferred over maximum performance.
|
|
97
|
+
*
|
|
98
|
+
* For production servers or performance-critical applications, consider `makeWorkerAdapter`
|
|
99
|
+
* which runs persistence/sync in a separate worker thread.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { makeAdapter } from '@livestore/adapter-node'
|
|
104
|
+
* import { makeWsSync } from '@livestore/sync-cf/client'
|
|
105
|
+
*
|
|
106
|
+
* const adapter = makeAdapter({
|
|
107
|
+
* storage: { type: 'fs', baseDirectory: './data' },
|
|
108
|
+
* sync: {
|
|
109
|
+
* backend: makeWsSync({ url: 'wss://api.example.com/sync' }),
|
|
110
|
+
* },
|
|
111
|
+
* })
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```ts
|
|
116
|
+
* // With DevTools support
|
|
117
|
+
* const adapter = makeAdapter({
|
|
118
|
+
* storage: { type: 'fs', baseDirectory: './data' },
|
|
119
|
+
* devtools: {
|
|
120
|
+
* schemaPath: new URL('./schema.ts', import.meta.url),
|
|
121
|
+
* port: 4242,
|
|
122
|
+
* },
|
|
123
|
+
* })
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
* @see https://livestore.dev/docs/reference/adapters/node for setup guide
|
|
127
|
+
*/
|
|
92
128
|
export const makeAdapter = ({
|
|
93
129
|
sync,
|
|
94
130
|
...options
|
|
@@ -97,7 +133,36 @@ export const makeAdapter = ({
|
|
|
97
133
|
}): Adapter => makeAdapterImpl({ ...options, leaderThread: { _tag: 'single-threaded', sync } })
|
|
98
134
|
|
|
99
135
|
/**
|
|
100
|
-
*
|
|
136
|
+
* Creates a multi-threaded LiveStore adapter for Node.js applications.
|
|
137
|
+
*
|
|
138
|
+
* This adapter runs the leader thread (persistence, sync, and heavy SQLite operations)
|
|
139
|
+
* in a separate worker thread, keeping your main thread responsive. Recommended for
|
|
140
|
+
* production servers and performance-critical applications.
|
|
141
|
+
*
|
|
142
|
+
* You must create a worker file that calls `makeLeaderWorker()` and pass its URL
|
|
143
|
+
* to this function.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* // In your main file:
|
|
148
|
+
* import { makeWorkerAdapter } from '@livestore/adapter-node'
|
|
149
|
+
*
|
|
150
|
+
* const adapter = makeWorkerAdapter({
|
|
151
|
+
* storage: { type: 'fs', baseDirectory: './data' },
|
|
152
|
+
* workerUrl: new URL('./livestore.worker.ts', import.meta.url),
|
|
153
|
+
* })
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* // In livestore.worker.ts:
|
|
159
|
+
* import { makeLeaderWorker } from '@livestore/adapter-node/worker'
|
|
160
|
+
* import { schema } from './schema'
|
|
161
|
+
*
|
|
162
|
+
* makeLeaderWorker({ schema })
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* @see https://livestore.dev/docs/reference/adapters/node for setup guide
|
|
101
166
|
*/
|
|
102
167
|
export const makeWorkerAdapter = ({
|
|
103
168
|
workerUrl,
|
|
@@ -341,8 +406,18 @@ const makeLocalLeaderThread = ({
|
|
|
341
406
|
batch.map((item) => new LiveStoreEvent.Client.EncodedWithMeta(item)),
|
|
342
407
|
{ waitForProcessing: true },
|
|
343
408
|
),
|
|
409
|
+
stream: (options) =>
|
|
410
|
+
streamEventsWithSyncState({
|
|
411
|
+
dbEventlog,
|
|
412
|
+
syncState: syncProcessor.syncState,
|
|
413
|
+
options,
|
|
414
|
+
}),
|
|
415
|
+
},
|
|
416
|
+
initialState: {
|
|
417
|
+
leaderHead: initialLeaderHead,
|
|
418
|
+
migrationsReport: initialState.migrationsReport,
|
|
419
|
+
storageMode: 'persisted',
|
|
344
420
|
},
|
|
345
|
-
initialState: { leaderHead: initialLeaderHead, migrationsReport: initialState.migrationsReport },
|
|
346
421
|
export: Effect.sync(() => dbState.export()),
|
|
347
422
|
getEventlogData: Effect.sync(() => dbEventlog.export()),
|
|
348
423
|
syncState: syncProcessor.syncState,
|
|
@@ -481,10 +556,16 @@ const makeWorkerLeaderThread = ({
|
|
|
481
556
|
attributes: { batchSize: batch.length },
|
|
482
557
|
}),
|
|
483
558
|
),
|
|
559
|
+
stream: (options) =>
|
|
560
|
+
runInWorkerStream(new WorkerSchema.LeaderWorkerInnerStreamEvents(options)).pipe(
|
|
561
|
+
Stream.withSpan('@livestore/adapter-node:client-session:streamEvents'),
|
|
562
|
+
Stream.orDie,
|
|
563
|
+
),
|
|
484
564
|
},
|
|
485
565
|
initialState: {
|
|
486
566
|
leaderHead: initialLeaderHead,
|
|
487
567
|
migrationsReport: bootResult.migrationsReport,
|
|
568
|
+
storageMode: 'persisted',
|
|
488
569
|
},
|
|
489
570
|
export: runInWorker(new WorkerSchema.LeaderWorkerInnerExport()).pipe(
|
|
490
571
|
Effect.timeout(10_000),
|
|
@@ -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
|
|
@@ -96,7 +106,7 @@ export const startDevtoolsServer = ({
|
|
|
96
106
|
} else {
|
|
97
107
|
if (req.url === '/' || req.url === '') {
|
|
98
108
|
return HttpServerResponse.redirect('/_livestore/node')
|
|
99
|
-
} else if (req.url
|
|
109
|
+
} else if (shouldRouteToVite(req.url)) {
|
|
100
110
|
// Here we're delegating to the Vite middleware
|
|
101
111
|
|
|
102
112
|
// TODO replace this once @effect/platform-node supports Node HTTP middlewares
|
|
@@ -9,7 +9,8 @@ if (process.execArgv.includes('--inspect')) {
|
|
|
9
9
|
|
|
10
10
|
import type { SyncOptions } from '@livestore/common'
|
|
11
11
|
import { LogConfig, UnknownError } from '@livestore/common'
|
|
12
|
-
import {
|
|
12
|
+
import type { StreamEventsOptions } from '@livestore/common/leader-thread'
|
|
13
|
+
import { Eventlog, LeaderThreadCtx, streamEventsWithSyncState } from '@livestore/common/leader-thread'
|
|
13
14
|
import type { LiveStoreSchema } from '@livestore/common/schema'
|
|
14
15
|
import { LiveStoreEvent } from '@livestore/common/schema'
|
|
15
16
|
import { loadSqlite3Wasm } from '@livestore/sqlite-wasm/load-wasm'
|
|
@@ -86,6 +87,20 @@ export const makeWorkerEffect = (options: WorkerOptions) => {
|
|
|
86
87
|
const { syncProcessor } = yield* LeaderThreadCtx
|
|
87
88
|
return syncProcessor.pull({ cursor })
|
|
88
89
|
}).pipe(Stream.unwrapScoped),
|
|
90
|
+
StreamEvents: (options: WorkerSchema.LeaderWorkerInnerStreamEvents) =>
|
|
91
|
+
LeaderThreadCtx.pipe(
|
|
92
|
+
Effect.map(({ dbEventlog, syncProcessor }) => {
|
|
93
|
+
const { _tag: _ignored, ...payload } = options
|
|
94
|
+
const streamOptions = payload as StreamEventsOptions
|
|
95
|
+
return streamEventsWithSyncState({
|
|
96
|
+
dbEventlog,
|
|
97
|
+
syncState: syncProcessor.syncState,
|
|
98
|
+
options: streamOptions,
|
|
99
|
+
})
|
|
100
|
+
}),
|
|
101
|
+
Stream.unwrapScoped,
|
|
102
|
+
Stream.withSpan('@livestore/adapter-node:worker:StreamEvents'),
|
|
103
|
+
),
|
|
89
104
|
Export: () =>
|
|
90
105
|
Effect.andThen(LeaderThreadCtx, (_) => _.dbState.export()).pipe(
|
|
91
106
|
UnknownError.mapToUnknownError,
|
package/src/worker-schema.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
SyncState,
|
|
8
8
|
UnknownError,
|
|
9
9
|
} from '@livestore/common'
|
|
10
|
+
import { StreamEventsOptionsFields } from '@livestore/common/leader-thread'
|
|
10
11
|
import { EventSequenceNumber, LiveStoreEvent } from '@livestore/common/schema'
|
|
11
12
|
import { Schema, Transferable } from '@livestore/utils/effect'
|
|
12
13
|
|
|
@@ -111,6 +112,15 @@ export class LeaderWorkerInnerPullStream extends Schema.TaggedRequest<LeaderWork
|
|
|
111
112
|
failure: UnknownError,
|
|
112
113
|
}) {}
|
|
113
114
|
|
|
115
|
+
export class LeaderWorkerInnerStreamEvents extends Schema.TaggedRequest<LeaderWorkerInnerStreamEvents>()(
|
|
116
|
+
'StreamEvents',
|
|
117
|
+
{
|
|
118
|
+
payload: StreamEventsOptionsFields,
|
|
119
|
+
success: LiveStoreEvent.Client.Encoded,
|
|
120
|
+
failure: UnknownError,
|
|
121
|
+
},
|
|
122
|
+
) {}
|
|
123
|
+
|
|
114
124
|
export class LeaderWorkerInnerPushToLeader extends Schema.TaggedRequest<LeaderWorkerInnerPushToLeader>()(
|
|
115
125
|
'PushToLeader',
|
|
116
126
|
{
|
|
@@ -215,6 +225,7 @@ export const LeaderWorkerInnerRequest = Schema.Union(
|
|
|
215
225
|
LeaderWorkerInnerInitialMessage,
|
|
216
226
|
LeaderWorkerInnerBootStatusStream,
|
|
217
227
|
LeaderWorkerInnerPullStream,
|
|
228
|
+
LeaderWorkerInnerStreamEvents,
|
|
218
229
|
LeaderWorkerInnerPushToLeader,
|
|
219
230
|
LeaderWorkerInnerExport,
|
|
220
231
|
LeaderWorkerInnerGetRecreateSnapshot,
|