@livestore/adapter-node 0.0.0-snapshot-f5ece014485b5ab43795c218f7ba7cfa32c81707 → 0.0.0-snapshot-057a9e3a18ca69a310d4eb8cf35a34e94fa1841e

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.
@@ -1,16 +1,16 @@
1
1
  import { hostname } from 'node:os'
2
2
  import * as WT from 'node:worker_threads'
3
-
4
- import type {
5
- Adapter,
6
- BootStatus,
3
+ import {
4
+ type Adapter,
5
+ type BootStatus,
7
6
  ClientSessionLeaderThreadProxy,
8
- IntentionalShutdownCause,
9
- LockStatus,
10
- MakeSqliteDb,
11
- SyncOptions,
7
+ type IntentionalShutdownCause,
8
+ type LockStatus,
9
+ type MakeSqliteDb,
10
+ makeClientSession,
11
+ type SyncOptions,
12
+ UnexpectedError,
12
13
  } from '@livestore/common'
13
- import { makeClientSession, UnexpectedError } from '@livestore/common'
14
14
  import { Eventlog, LeaderThreadCtx } from '@livestore/common/leader-thread'
15
15
  import type { LiveStoreSchema } from '@livestore/common/schema'
16
16
  import { LiveStoreEvent } from '@livestore/common/schema'
@@ -188,6 +188,7 @@ const makeAdapterImpl = ({
188
188
  })
189
189
 
190
190
  syncInMemoryDb.import(initialSnapshot)
191
+ syncInMemoryDb.debug.head = leaderThread.initialState.leaderHead
191
192
 
192
193
  const clientSession = yield* makeClientSession({
193
194
  ...adapterArgs,
@@ -214,7 +215,6 @@ const makeAdapterImpl = ({
214
215
  return clientSession
215
216
  }).pipe(
216
217
  Effect.withSpan('@livestore/adapter-node:adapter'),
217
- Effect.parallelFinalizers,
218
218
  Effect.provide(PlatformNode.NodeFileSystem.layer),
219
219
  Effect.provide(FetchHttpClient.layer),
220
220
  )) satisfies Adapter
@@ -262,23 +262,24 @@ const makeLocalLeaderThread = ({
262
262
 
263
263
  const initialLeaderHead = Eventlog.getClientHeadFromDb(dbEventlog)
264
264
 
265
- const leaderThread = {
266
- events: {
267
- pull:
268
- testing?.overrides?.clientSession?.leaderThreadProxy?.events?.pull ??
269
- (({ cursor }) => syncProcessor.pull({ cursor })),
270
- push: (batch) =>
271
- syncProcessor.push(
272
- batch.map((item) => new LiveStoreEvent.EncodedWithMeta(item)),
273
- { waitForProcessing: true },
274
- ),
265
+ const leaderThread = ClientSessionLeaderThreadProxy.of(
266
+ {
267
+ events: {
268
+ pull: ({ cursor }) => syncProcessor.pull({ cursor }),
269
+ push: (batch) =>
270
+ syncProcessor.push(
271
+ batch.map((item) => new LiveStoreEvent.EncodedWithMeta(item)),
272
+ { waitForProcessing: true },
273
+ ),
274
+ },
275
+ initialState: { leaderHead: initialLeaderHead, migrationsReport: initialState.migrationsReport },
276
+ export: Effect.sync(() => dbState.export()),
277
+ getEventlogData: Effect.sync(() => dbEventlog.export()),
278
+ getSyncState: syncProcessor.syncState,
279
+ sendDevtoolsMessage: (message) => extraIncomingMessagesQueue.offer(message),
275
280
  },
276
- initialState: { leaderHead: initialLeaderHead, migrationsReport: initialState.migrationsReport },
277
- export: Effect.sync(() => dbState.export()),
278
- getEventlogData: Effect.sync(() => dbEventlog.export()),
279
- getSyncState: syncProcessor.syncState,
280
- sendDevtoolsMessage: (message) => extraIncomingMessagesQueue.offer(message),
281
- } satisfies ClientSessionLeaderThreadProxy
281
+ { overrides: testing?.overrides?.clientSession?.leaderThreadProxy },
282
+ )
282
283
 
283
284
  const initialSnapshot = dbState.export()
284
285
 
@@ -336,20 +337,6 @@ const makeWorkerLeaderThread = ({
336
337
  Effect.withSpan('@livestore/adapter-node:adapter:setupLeaderThread'),
337
338
  )
338
339
 
339
- yield* Effect.addFinalizer(() =>
340
- Effect.gen(function* () {
341
- // We first try to gracefully shutdown the leader worker and then forcefully terminate it
342
- yield* Effect.raceFirst(
343
- runInWorker(new WorkerSchema.LeaderWorkerInner.Shutdown()).pipe(Effect.andThen(() => nodeWorker.terminate())),
344
-
345
- Effect.sync(() => {
346
- console.warn('[@livestore/adapter-node:adapter] Worker did not gracefully shutdown in time, terminating it')
347
- nodeWorker.terminate()
348
- }).pipe(Effect.delay(1000)),
349
- ).pipe(Effect.exit) // The disconnect is to prevent the interrupt to bubble out
350
- }).pipe(Effect.withSpan('@livestore/adapter-node:adapter:shutdown'), Effect.tapCauseLogPretty, Effect.orDie),
351
- )
352
-
353
340
  const runInWorker = <TReq extends typeof WorkerSchema.LeaderWorkerInner.Request.Type>(
354
341
  req: TReq,
355
342
  ): TReq extends Schema.WithResult<infer A, infer _I, infer _E, infer _EI, infer R>
@@ -410,39 +397,42 @@ const makeWorkerLeaderThread = ({
410
397
  Effect.withSpan('@livestore/adapter-node:client-session:export'),
411
398
  )
412
399
 
413
- const leaderThread = {
414
- events: {
415
- pull:
416
- testing?.overrides?.clientSession?.leaderThreadProxy?.events?.pull ??
417
- (({ cursor }) =>
418
- runInWorkerStream(new WorkerSchema.LeaderWorkerInner.PullStream({ cursor })).pipe(Stream.orDie)),
419
- push: (batch) =>
420
- runInWorker(new WorkerSchema.LeaderWorkerInner.PushToLeader({ batch })).pipe(
421
- Effect.withSpan('@livestore/adapter-node:client-session:pushToLeader', {
422
- attributes: { batchSize: batch.length },
423
- }),
400
+ const leaderThread = ClientSessionLeaderThreadProxy.of(
401
+ {
402
+ events: {
403
+ pull: ({ cursor }) =>
404
+ runInWorkerStream(new WorkerSchema.LeaderWorkerInner.PullStream({ cursor })).pipe(Stream.orDie),
405
+ push: (batch) =>
406
+ runInWorker(new WorkerSchema.LeaderWorkerInner.PushToLeader({ batch })).pipe(
407
+ Effect.withSpan('@livestore/adapter-node:client-session:pushToLeader', {
408
+ attributes: { batchSize: batch.length },
409
+ }),
410
+ ),
411
+ },
412
+ initialState: {
413
+ leaderHead: initialLeaderHead,
414
+ migrationsReport: bootResult.migrationsReport,
415
+ },
416
+ export: runInWorker(new WorkerSchema.LeaderWorkerInner.Export()).pipe(
417
+ Effect.timeout(10_000),
418
+ UnexpectedError.mapToUnexpectedError,
419
+ Effect.withSpan('@livestore/adapter-node:client-session:export'),
420
+ ),
421
+ getEventlogData: Effect.dieMessage('Not implemented'),
422
+ getSyncState: runInWorker(new WorkerSchema.LeaderWorkerInner.GetLeaderSyncState()).pipe(
423
+ UnexpectedError.mapToUnexpectedError,
424
+ Effect.withSpan('@livestore/adapter-node:client-session:getLeaderSyncState'),
425
+ ),
426
+ sendDevtoolsMessage: (message) =>
427
+ runInWorker(new WorkerSchema.LeaderWorkerInner.ExtraDevtoolsMessage({ message })).pipe(
428
+ UnexpectedError.mapToUnexpectedError,
429
+ Effect.withSpan('@livestore/adapter-node:client-session:devtoolsMessageForLeader'),
424
430
  ),
425
431
  },
426
- initialState: {
427
- leaderHead: initialLeaderHead,
428
- migrationsReport: bootResult.migrationsReport,
432
+ {
433
+ overrides: testing?.overrides?.clientSession?.leaderThreadProxy,
429
434
  },
430
- export: runInWorker(new WorkerSchema.LeaderWorkerInner.Export()).pipe(
431
- Effect.timeout(10_000),
432
- UnexpectedError.mapToUnexpectedError,
433
- Effect.withSpan('@livestore/adapter-node:client-session:export'),
434
- ),
435
- getEventlogData: Effect.dieMessage('Not implemented'),
436
- getSyncState: runInWorker(new WorkerSchema.LeaderWorkerInner.GetLeaderSyncState()).pipe(
437
- UnexpectedError.mapToUnexpectedError,
438
- Effect.withSpan('@livestore/adapter-node:client-session:getLeaderSyncState'),
439
- ),
440
- sendDevtoolsMessage: (message) =>
441
- runInWorker(new WorkerSchema.LeaderWorkerInner.ExtraDevtoolsMessage({ message })).pipe(
442
- UnexpectedError.mapToUnexpectedError,
443
- Effect.withSpan('@livestore/adapter-node:client-session:devtoolsMessageForLeader'),
444
- ),
445
- } satisfies ClientSessionLeaderThreadProxy
435
+ )
446
436
 
447
437
  return { leaderThread, initialSnapshot: bootResult.snapshot }
448
438
  })
@@ -1,3 +1,3 @@
1
- export { makeViteMiddleware } from './vite-dev-server.js'
2
- export type { ViteDevtoolsOptions } from './vite-dev-server.js'
3
1
  export { startDevtoolsServer } from './devtools-server.js'
2
+ export type { ViteDevtoolsOptions } from './vite-dev-server.js'
3
+ export { makeViteMiddleware } from './vite-dev-server.js'
@@ -21,11 +21,17 @@ import type * as WorkerSchema from './worker-schema.js'
21
21
 
22
22
  export type TestingOverrides = {
23
23
  clientSession?: {
24
- leaderThreadProxy?: Partial<ClientSessionLeaderThreadProxy>
25
- }
26
- makeLeaderThread?: {
27
- dbEventlog?: (makeSqliteDb: MakeSqliteDb) => Effect.Effect<SqliteDb, UnexpectedError>
24
+ leaderThreadProxy?: (
25
+ original: ClientSessionLeaderThreadProxy.ClientSessionLeaderThreadProxy,
26
+ ) => Partial<ClientSessionLeaderThreadProxy.ClientSessionLeaderThreadProxy>
28
27
  }
28
+ makeLeaderThread?: (makeSqliteDb: MakeSqliteDb) => Effect.Effect<
29
+ {
30
+ dbEventlog: SqliteDb
31
+ dbState: SqliteDb
32
+ },
33
+ UnexpectedError
34
+ >
29
35
  }
30
36
 
31
37
  export interface MakeLeaderThreadArgs {
@@ -62,8 +68,10 @@ export const makeLeaderThread = ({
62
68
  schema.state.sqlite.migrations.strategy === 'manual' ? 'fixed' : schema.state.sqlite.hash.toString()
63
69
 
64
70
  const makeDb = (kind: 'state' | 'eventlog') => {
65
- if (testing?.makeLeaderThread?.dbEventlog && kind === 'eventlog') {
66
- return testing.makeLeaderThread.dbEventlog(makeSqliteDb)
71
+ if (testing?.makeLeaderThread) {
72
+ return testing
73
+ .makeLeaderThread(makeSqliteDb)
74
+ .pipe(Effect.map(({ dbEventlog, dbState }) => (kind === 'state' ? dbState : dbEventlog)))
67
75
  }
68
76
 
69
77
  return storage.type === 'in-memory'
@@ -47,7 +47,7 @@ export type WorkerOptions = {
47
47
  export const getWorkerArgs = () => Schema.decodeSync(WorkerSchema.WorkerArgv)(process.argv[2]!)
48
48
 
49
49
  export const makeWorker = (options: WorkerOptions) => {
50
- makeWorkerEffect(options).pipe(Effect.runFork)
50
+ makeWorkerEffect(options).pipe(PlatformNode.NodeRuntime.runMain)
51
51
  }
52
52
 
53
53
  export const makeWorkerEffect = (options: WorkerOptions) => {
package/src/webchannel.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type BroadcastChannel as NodeBroadcastChannel } from 'node:worker_threads'
1
+ import type { BroadcastChannel as NodeBroadcastChannel } from 'node:worker_threads'
2
2
 
3
3
  import type { Either, ParseResult } from '@livestore/utils/effect'
4
4
  import { Deferred, Effect, Exit, Schema, Scope, Stream, WebChannel } from '@livestore/utils/effect'
@@ -37,7 +37,6 @@ export const makeBroadcastChannel = <Msg, MsgEncoded>({
37
37
  const listen = Stream.asyncPush<Either.Either<Msg, ParseResult.ParseError>>((emit) =>
38
38
  Effect.acquireRelease(
39
39
  Effect.gen(function* () {
40
- // eslint-disable-next-line unicorn/prefer-add-event-listener
41
40
  channel.onmessage = (event: any) => {
42
41
  return emit.single(Schema.decodeEither(schema)(event.data))
43
42
  }
@@ -1,12 +1,4 @@
1
- import {
2
- BootStatus,
3
- Devtools,
4
- LeaderAheadError,
5
- LeaderPullCursor,
6
- MigrationsReport,
7
- SyncState,
8
- UnexpectedError,
9
- } from '@livestore/common'
1
+ import { BootStatus, Devtools, LeaderAheadError, MigrationsReport, SyncState, UnexpectedError } from '@livestore/common'
10
2
  import { EventSequenceNumber, LiveStoreEvent } from '@livestore/common/schema'
11
3
  import { Schema, Transferable } from '@livestore/utils/effect'
12
4
 
@@ -91,11 +83,10 @@ export namespace LeaderWorkerInner {
91
83
 
92
84
  export class PullStream extends Schema.TaggedRequest<PullStream>()('PullStream', {
93
85
  payload: {
94
- cursor: LeaderPullCursor,
86
+ cursor: EventSequenceNumber.EventSequenceNumber,
95
87
  },
96
88
  success: Schema.Struct({
97
89
  payload: SyncState.PayloadUpstream,
98
- mergeCounter: Schema.Number,
99
90
  }),
100
91
  failure: UnexpectedError,
101
92
  }) {}