@livestore/adapter-web 0.4.0-dev.12 → 0.4.0-dev.13
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/web-worker/client-session/persisted-adapter.d.ts.map +1 -1
- package/dist/web-worker/client-session/persisted-adapter.js +15 -17
- package/dist/web-worker/client-session/persisted-adapter.js.map +1 -1
- package/dist/web-worker/common/worker-schema.d.ts +12 -17
- package/dist/web-worker/common/worker-schema.d.ts.map +1 -1
- package/dist/web-worker/common/worker-schema.js +10 -16
- package/dist/web-worker/common/worker-schema.js.map +1 -1
- package/dist/web-worker/shared-worker/make-shared-worker.d.ts.map +1 -1
- package/dist/web-worker/shared-worker/make-shared-worker.js +39 -37
- package/dist/web-worker/shared-worker/make-shared-worker.js.map +1 -1
- package/package.json +6 -6
- package/src/web-worker/client-session/persisted-adapter.ts +20 -21
- package/src/web-worker/common/worker-schema.ts +9 -16
- package/src/web-worker/shared-worker/make-shared-worker.ts +41 -48
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Devtools, UnexpectedError } from '@livestore/common'
|
|
1
|
+
import { Devtools, liveStoreVersion, UnexpectedError } from '@livestore/common'
|
|
2
2
|
import * as DevtoolsWeb from '@livestore/devtools-web-common/web-channel'
|
|
3
3
|
import * as WebmeshWorker from '@livestore/devtools-web-common/worker'
|
|
4
4
|
import { isDevEnv, isNotUndefined, LS_DEV } from '@livestore/utils'
|
|
@@ -60,10 +60,6 @@ const makeWorkerRunner = Effect.gen(function* () {
|
|
|
60
60
|
| undefined
|
|
61
61
|
>(undefined)
|
|
62
62
|
|
|
63
|
-
const initialMessagePayloadDeferredRef = yield* Deferred.make<
|
|
64
|
-
typeof WorkerSchema.SharedWorkerInitialMessagePayloadFromClientSession.Type
|
|
65
|
-
>().pipe(Effect.andThen(Ref.make))
|
|
66
|
-
|
|
67
63
|
const waitForWorker = SubscriptionRef.waitUntil(leaderWorkerContextSubRef, isNotUndefined).pipe(
|
|
68
64
|
Effect.map((_) => _.worker),
|
|
69
65
|
)
|
|
@@ -155,62 +151,59 @@ const makeWorkerRunner = Effect.gen(function* () {
|
|
|
155
151
|
}
|
|
156
152
|
}).pipe(Effect.withSpan('@livestore/adapter-web:shared-worker:resetCurrentWorkerCtx'))
|
|
157
153
|
|
|
158
|
-
// const devtoolsWebBridge = yield* makeDevtoolsWebBridge
|
|
159
|
-
|
|
160
154
|
const reset = Effect.gen(function* () {
|
|
161
155
|
yield* Effect.logDebug('reset')
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
yield* Ref.set(initialMessagePayloadDeferredRef, initialMessagePayloadDeferred)
|
|
166
|
-
|
|
156
|
+
// Clear cached invariants so a fresh configuration can be accepted after shutdown
|
|
157
|
+
yield* Ref.set(invariantsRef, undefined)
|
|
158
|
+
// Tear down current leader worker context
|
|
167
159
|
yield* resetCurrentWorkerCtx
|
|
168
|
-
// yield* devtoolsWebBridge.reset
|
|
169
160
|
})
|
|
170
161
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const messageSchema = WorkerSchema.LeaderWorkerInnerInitialMessage.pipe(
|
|
183
|
-
Schema.omit('devtoolsEnabled', 'debugInstanceId'),
|
|
184
|
-
)
|
|
185
|
-
const isEqual = Schema.equivalence(messageSchema)
|
|
186
|
-
if (isEqual(initialMessage, previousInitialMessage.initialMessage) === false) {
|
|
187
|
-
const diff = Schema.debugDiff(messageSchema)(previousInitialMessage.initialMessage, initialMessage)
|
|
162
|
+
// Cache first-applied invariants to enforce stability across leader transitions
|
|
163
|
+
const InvariantsSchema = Schema.Struct({
|
|
164
|
+
storeId: Schema.String,
|
|
165
|
+
storageOptions: WorkerSchema.StorageType,
|
|
166
|
+
syncPayload: Schema.UndefinedOr(Schema.JsonValue),
|
|
167
|
+
liveStoreVersion: Schema.Literal(liveStoreVersion),
|
|
168
|
+
devtoolsEnabled: Schema.Boolean,
|
|
169
|
+
})
|
|
170
|
+
type Invariants = typeof InvariantsSchema.Type
|
|
171
|
+
const invariantsRef = yield* Ref.make<Invariants | undefined>(undefined)
|
|
172
|
+
const sameInvariants = Schema.equivalence(InvariantsSchema)
|
|
188
173
|
|
|
189
|
-
|
|
190
|
-
cause: 'Initial message already sent and was different now',
|
|
191
|
-
payload: {
|
|
192
|
-
diff,
|
|
193
|
-
previousInitialMessage: previousInitialMessage.initialMessage,
|
|
194
|
-
newInitialMessage: initialMessage,
|
|
195
|
-
},
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
} else {
|
|
199
|
-
yield* Deferred.succeed(initialMessagePayloadDeferred, message.payload)
|
|
200
|
-
}
|
|
201
|
-
}),
|
|
174
|
+
return WorkerRunner.layerSerialized(WorkerSchema.SharedWorkerRequest, {
|
|
202
175
|
// Whenever the client session leader changes (and thus creates a new leader thread), the new client session leader
|
|
203
176
|
// sends a new MessagePort to the shared worker which proxies messages to the new leader thread.
|
|
204
|
-
UpdateMessagePort: ({ port }) =>
|
|
177
|
+
UpdateMessagePort: ({ port, initial, liveStoreVersion: clientLiveStoreVersion }) =>
|
|
205
178
|
Effect.gen(function* () {
|
|
206
|
-
|
|
179
|
+
// Enforce invariants: storeId, storageOptions, syncPayload, liveStoreVersion must remain stable
|
|
180
|
+
const invariants: Invariants = {
|
|
181
|
+
storeId: initial.storeId,
|
|
182
|
+
storageOptions: initial.storageOptions,
|
|
183
|
+
syncPayload: initial.syncPayload,
|
|
184
|
+
liveStoreVersion: clientLiveStoreVersion,
|
|
185
|
+
devtoolsEnabled: initial.devtoolsEnabled,
|
|
186
|
+
}
|
|
187
|
+
const prev = yield* Ref.get(invariantsRef)
|
|
188
|
+
// Early return on mismatch to keep happy path linear
|
|
189
|
+
if (prev !== undefined && !sameInvariants(prev, invariants)) {
|
|
190
|
+
const diff = Schema.debugDiff(InvariantsSchema)(prev, invariants)
|
|
191
|
+
return yield* new UnexpectedError({
|
|
192
|
+
cause: 'Store invariants changed across leader transitions',
|
|
193
|
+
payload: { diff, previous: prev, next: invariants },
|
|
194
|
+
})
|
|
195
|
+
}
|
|
196
|
+
// First writer records invariants
|
|
197
|
+
if (prev === undefined) {
|
|
198
|
+
yield* Ref.set(invariantsRef, invariants)
|
|
199
|
+
}
|
|
207
200
|
|
|
208
201
|
yield* resetCurrentWorkerCtx
|
|
209
202
|
|
|
210
203
|
const scope = yield* Scope.make()
|
|
211
204
|
|
|
212
205
|
yield* Effect.gen(function* () {
|
|
213
|
-
const shutdownChannel = yield* makeShutdownChannel(
|
|
206
|
+
const shutdownChannel = yield* makeShutdownChannel(initial.storeId)
|
|
214
207
|
|
|
215
208
|
yield* shutdownChannel.listen.pipe(
|
|
216
209
|
Stream.flatten(),
|
|
@@ -225,7 +218,7 @@ const makeWorkerRunner = Effect.gen(function* () {
|
|
|
225
218
|
const worker = yield* Worker.makePoolSerialized<WorkerSchema.LeaderWorkerInnerRequest>({
|
|
226
219
|
size: 1,
|
|
227
220
|
concurrency: 100,
|
|
228
|
-
initialMessage: () =>
|
|
221
|
+
initialMessage: () => initial,
|
|
229
222
|
}).pipe(
|
|
230
223
|
Effect.provide(workerLayer),
|
|
231
224
|
Effect.withSpan('@livestore/adapter-web:shared-worker:makeWorkerProxyFromPort'),
|
|
@@ -233,7 +226,7 @@ const makeWorkerRunner = Effect.gen(function* () {
|
|
|
233
226
|
|
|
234
227
|
// Prepare the web mesh connection for leader worker to be able to connect to the devtools
|
|
235
228
|
const { node } = yield* WebmeshWorker.CacheService
|
|
236
|
-
const { storeId, clientId } =
|
|
229
|
+
const { storeId, clientId } = initial
|
|
237
230
|
|
|
238
231
|
yield* DevtoolsWeb.connectViaWorker({
|
|
239
232
|
node,
|