@livestore/sync-cf 0.4.0 → 0.5.0-dev.0
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/cf-worker/do/durable-object.d.ts.map +1 -1
- package/dist/cf-worker/do/durable-object.js +24 -11
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +22 -18
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +43 -33
- package/dist/cf-worker/do/layer.js.map +1 -1
- package/dist/cf-worker/do/pull.d.ts +3 -3
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +17 -18
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +16 -3
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +69 -49
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/push.test.d.ts +2 -0
- package/dist/cf-worker/do/push.test.d.ts.map +1 -0
- package/dist/cf-worker/do/push.test.js +30 -0
- package/dist/cf-worker/do/push.test.js.map +1 -0
- package/dist/cf-worker/do/sqlite.d.ts +34 -46
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js +1 -1
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +7 -6
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +26 -14
- package/dist/cf-worker/do/sync-storage.js.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts +2 -2
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.js +21 -19
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +2 -2
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.js +7 -7
- package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +2 -2
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.js +9 -9
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +22 -19
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +13 -11
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +6 -6
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +16 -14
- package/dist/cf-worker/worker.js.map +1 -1
- package/dist/client/transport/do-rpc-client.d.ts +13 -4
- package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/do-rpc-client.js +55 -26
- package/dist/client/transport/do-rpc-client.js.map +1 -1
- package/dist/client/transport/http-rpc-client.d.ts +3 -3
- package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/http-rpc-client.js +30 -21
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts +3 -3
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +20 -16
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/do-rpc-schema.d.ts +38 -39
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +3 -3
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +36 -37
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +5 -5
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/mod.d.ts +4 -5
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +3 -4
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +116 -133
- package/dist/common/sync-message-types.d.ts.map +1 -1
- package/dist/common/sync-message-types.js +26 -14
- package/dist/common/sync-message-types.js.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +33 -34
- package/dist/common/ws-rpc-schema.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.js +4 -4
- package/dist/common/ws-rpc-schema.js.map +1 -1
- package/package.json +21 -37
- package/src/cf-worker/do/durable-object.ts +45 -36
- package/src/cf-worker/do/layer.ts +142 -99
- package/src/cf-worker/do/pull.ts +28 -28
- package/src/cf-worker/do/push.test.ts +40 -0
- package/src/cf-worker/do/push.ts +138 -115
- package/src/cf-worker/do/sqlite.ts +1 -1
- package/src/cf-worker/do/sync-storage.ts +34 -21
- package/src/cf-worker/do/transport/do-rpc-server.ts +23 -34
- package/src/cf-worker/do/transport/http-rpc-server.ts +7 -10
- package/src/cf-worker/do/transport/ws-rpc-server.ts +10 -10
- package/src/cf-worker/shared.ts +18 -13
- package/src/cf-worker/worker.ts +21 -22
- package/src/client/transport/do-rpc-client.ts +82 -40
- package/src/client/transport/http-rpc-client.ts +47 -37
- package/src/client/transport/ws-rpc-client.ts +29 -26
- package/src/common/do-rpc-schema.ts +3 -3
- package/src/common/http-rpc-schema.ts +5 -5
- package/src/common/mod.ts +3 -4
- package/src/common/sync-message-types.ts +16 -16
- package/src/common/ws-rpc-schema.ts +4 -4
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { BackendIdMismatchError, ServerAheadError, SyncBackend, UnknownError
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, SyncBackend, UnknownError } from '@livestore/common';
|
|
2
2
|
import { emitStreamResponse } from '@livestore/common-cf';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { splitArrayBySize } from '@livestore/common/sync';
|
|
4
|
+
import { Effect, Option, ReadonlyArray as EffectArray, Schema } from '@livestore/utils/effect';
|
|
5
5
|
import { MAX_PUSH_EVENTS_PER_REQUEST, MAX_WS_MESSAGE_BYTES } from "../../common/constants.js";
|
|
6
6
|
import { SyncMessage } from "../../common/mod.js";
|
|
7
|
-
import { WebSocketAttachmentSchema, } from "../shared.js";
|
|
8
|
-
import
|
|
9
|
-
const
|
|
10
|
-
const
|
|
7
|
+
import { rpcSubscriptionKeyPrefix, WebSocketAttachmentSchema, } from "../shared.js";
|
|
8
|
+
import * as DoCtx from "./layer.js";
|
|
9
|
+
const pullResponseJsonSchema = Schema.toCodecJson(SyncMessage.PullResponse);
|
|
10
|
+
const encodePullResponse = Schema.encodeSync(pullResponseJsonSchema);
|
|
11
|
+
const jsonStringify = Schema.encodeSync(Schema.fromJsonString(Schema.Unknown));
|
|
11
12
|
export const makePush = ({ payload, headers, options, storeId, ctx, env, }) => (pushRequest) => Effect.gen(function* () {
|
|
12
13
|
// yield* Effect.log(`Pushing ${decodedMessage.batch.length} events`, decodedMessage.batch)
|
|
13
|
-
const { backendId, storage, currentHeadRef, updateCurrentHead,
|
|
14
|
+
const { backendId, storage, currentHeadRef, updateCurrentHead, pushSemaphore } = yield* DoCtx.DoCtx;
|
|
14
15
|
if (pushRequest.batch.length === 0) {
|
|
15
16
|
return SyncMessage.PushAck.make({});
|
|
16
17
|
}
|
|
17
18
|
if (options?.onPush !== undefined) {
|
|
18
|
-
yield* Effect.
|
|
19
|
+
yield* Effect.trySyncOrPromiseOrEffect(() => options.onPush(pushRequest, {
|
|
19
20
|
storeId,
|
|
20
21
|
...(payload !== undefined ? { payload } : {}),
|
|
21
22
|
...(headers !== undefined ? { headers } : {}),
|
|
@@ -24,32 +25,32 @@ export const makePush = ({ payload, headers, options, storeId, ctx, env, }) => (
|
|
|
24
25
|
if (pushRequest.backendId._tag === 'Some' && pushRequest.backendId.value !== backendId) {
|
|
25
26
|
return yield* new BackendIdMismatchError({ expected: backendId, received: pushRequest.backendId.value });
|
|
26
27
|
}
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}).pipe(blockConcurrencyWhile(ctx));
|
|
48
|
-
// Run in background but already return the push ack to the client
|
|
49
|
-
yield* Effect.gen(function* () {
|
|
28
|
+
// A push is one ordered admit → persist → publish operation. `blockConcurrencyWhile` below protects
|
|
29
|
+
// the Durable Object state transition, while this semaphore keeps later pushes from overtaking this
|
|
30
|
+
// push during broadcasting without holding Cloudflare's concurrency gate across network I/O.
|
|
31
|
+
yield* runSerializedPushAdmission(pushSemaphore, Effect.gen(function* () {
|
|
32
|
+
// Keep the head check, durable append, and in-memory head update atomic with respect to other
|
|
33
|
+
// Durable Object requests. Broadcasting intentionally happens after this gate is released.
|
|
34
|
+
const { createdAt } = yield* Effect.gen(function* () {
|
|
35
|
+
const currentHead = currentHeadRef.current;
|
|
36
|
+
// TODO handle clientId unique conflict
|
|
37
|
+
// Validate the batch
|
|
38
|
+
const firstEventParent = pushRequest.batch[0].parentSeqNum;
|
|
39
|
+
if (firstEventParent !== currentHead) {
|
|
40
|
+
return yield* new ServerAheadError({ minimumExpectedNum: currentHead, providedNum: firstEventParent });
|
|
41
|
+
}
|
|
42
|
+
const createdAt = new Date().toISOString();
|
|
43
|
+
// TODO possibly model this as a queue in order to speed up subsequent pushes
|
|
44
|
+
yield* storage.appendEvents(pushRequest.batch, createdAt);
|
|
45
|
+
updateCurrentHead(pushRequest.batch.at(-1).seqNum);
|
|
46
|
+
return { createdAt };
|
|
47
|
+
}).pipe(blockConcurrencyWhile(ctx));
|
|
50
48
|
const connectedClients = ctx.getWebSockets();
|
|
51
49
|
// Preparing chunks of responses to make sure we don't exceed the WS message size limit.
|
|
52
|
-
|
|
50
|
+
if (EffectArray.isReadonlyArrayNonEmpty(pushRequest.batch) === false) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const responses = yield* splitArrayBySize({
|
|
53
54
|
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
54
55
|
maxBytes: MAX_WS_MESSAGE_BYTES,
|
|
55
56
|
encode: (items) => encodePullResponse(SyncMessage.PullResponse.make({
|
|
@@ -60,8 +61,8 @@ export const makePush = ({ payload, headers, options, storeId, ctx, env, }) => (
|
|
|
60
61
|
pageInfo: SyncBackend.pageInfoNoMore,
|
|
61
62
|
backendId,
|
|
62
63
|
})),
|
|
63
|
-
})
|
|
64
|
-
const batchWithMetadata =
|
|
64
|
+
})(pushRequest.batch).pipe(Effect.map((eventBatch) => eventBatch.map((events) => {
|
|
65
|
+
const batchWithMetadata = events.map((eventEncoded) => ({
|
|
65
66
|
eventEncoded,
|
|
66
67
|
metadata: Option.some(SyncMessage.SyncMetadata.make({ createdAt })),
|
|
67
68
|
}));
|
|
@@ -72,7 +73,7 @@ export const makePush = ({ payload, headers, options, storeId, ctx, env, }) => (
|
|
|
72
73
|
});
|
|
73
74
|
return {
|
|
74
75
|
response,
|
|
75
|
-
encoded:
|
|
76
|
+
encoded: encodePullResponse(response),
|
|
76
77
|
};
|
|
77
78
|
})));
|
|
78
79
|
// Dual broadcasting: WebSocket + RPC clients
|
|
@@ -81,11 +82,11 @@ export const makePush = ({ payload, headers, options, storeId, ctx, env, }) => (
|
|
|
81
82
|
for (const { response, encoded } of responses) {
|
|
82
83
|
// Only calling once for now.
|
|
83
84
|
if (options?.onPullRes !== undefined) {
|
|
84
|
-
yield* Effect.
|
|
85
|
+
yield* Effect.trySyncOrPromiseOrEffect(() => options.onPullRes(response)).pipe(UnknownError.mapToUnknownError);
|
|
85
86
|
}
|
|
86
87
|
// NOTE we're also sending the pullRes chunk to the pushing ws client as confirmation
|
|
87
88
|
for (const conn of connectedClients) {
|
|
88
|
-
const attachment = yield* Schema.
|
|
89
|
+
const attachment = yield* Schema.decodeEffect(WebSocketAttachmentSchema)(conn.deserializeAttachment());
|
|
89
90
|
// We're doing something a bit "advanced" here as we're directly emitting Effect RPC-compatible
|
|
90
91
|
// response messsages on the Effect RPC-managed websocket connection to the WS client.
|
|
91
92
|
// For this we need to get the RPC `requestId` from the WebSocket attachment.
|
|
@@ -101,38 +102,57 @@ export const makePush = ({ payload, headers, options, storeId, ctx, env, }) => (
|
|
|
101
102
|
}
|
|
102
103
|
yield* Effect.logDebug(`Broadcasted to ${connectedClients.length} WebSocket clients`);
|
|
103
104
|
}
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
// Subscribers live in the DO's KV storage (single source of truth), so fan-out survives reconstruction.
|
|
106
|
+
// emitStreamResponse reconstructs each client stub from its callerContext.
|
|
107
|
+
const rpcSubscriptions = Array.from(ctx.storage.kv.list({ prefix: rpcSubscriptionKeyPrefix }));
|
|
108
|
+
if (rpcSubscriptions.length > 0) {
|
|
109
|
+
for (const [, subscription] of rpcSubscriptions) {
|
|
107
110
|
for (const { encoded } of responses) {
|
|
108
111
|
yield* emitStreamResponse({
|
|
109
112
|
callerContext: subscription.callerContext,
|
|
110
113
|
env,
|
|
111
114
|
requestId: subscription.requestId,
|
|
115
|
+
storeId: subscription.storeId,
|
|
112
116
|
values: [encoded],
|
|
113
117
|
}).pipe(Effect.tapCauseLogPretty, Effect.exit);
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
|
-
yield* Effect.logDebug(`Broadcasted to ${rpcSubscriptions.
|
|
120
|
+
yield* Effect.logDebug(`Broadcasted to ${rpcSubscriptions.length} RPC clients`);
|
|
117
121
|
}
|
|
118
|
-
}).pipe(Effect.tapCauseLogPretty, Effect.withSpan('push-rpc-broadcast')
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
yield* Effect.yieldNow();
|
|
122
|
+
}).pipe(Effect.tapCauseLogPretty, Effect.withSpan('push-rpc-broadcast')));
|
|
123
|
+
// Acknowledge only after the committed batch has been published, so a client cannot observe an
|
|
124
|
+
// advanced server head while the corresponding pull response is still waiting in a detached fiber.
|
|
122
125
|
return SyncMessage.PushAck.make({});
|
|
123
126
|
}).pipe(Effect.tap(Effect.fn(function* (message) {
|
|
124
127
|
if (options?.onPushRes !== undefined) {
|
|
125
|
-
yield* Effect.
|
|
128
|
+
yield* Effect.trySyncOrPromiseOrEffect(() => options.onPushRes(message)).pipe(UnknownError.mapToUnknownError);
|
|
126
129
|
}
|
|
127
130
|
})), Effect.mapError((cause) => cause._tag === 'BackendIdMismatchError' || cause._tag === 'ServerAheadError' || cause._tag === 'UnknownError'
|
|
128
131
|
? cause
|
|
129
132
|
: new UnknownError({ cause })), Effect.withSpan('sync-cf:do:push', { attributes: { storeId, batchSize: pushRequest.batch.length } }));
|
|
130
133
|
/**
|
|
134
|
+
* Serializes the complete push admission lifecycle, including publication to pull subscribers.
|
|
135
|
+
*
|
|
136
|
+
* This complements `blockConcurrencyWhile`: that Cloudflare primitive makes the durable state transition
|
|
137
|
+
* atomic with respect to other Durable Object requests, whereas this semaphore preserves push order after
|
|
138
|
+
* the storage gate is released and broadcasting begins. Keeping broadcast outside `blockConcurrencyWhile`
|
|
139
|
+
* avoids holding Cloudflare's concurrency gate across network I/O.
|
|
140
|
+
*
|
|
141
|
+
* Once admitted, the effect is uninterruptible so cancellation cannot leave a committed head without its
|
|
142
|
+
* matching pull response. Such a gap would make later pushers receive `ServerAhead` while waiting for a
|
|
143
|
+
* response that was never published.
|
|
144
|
+
*/
|
|
145
|
+
export const runSerializedPushAdmission = (semaphore, admission) => semaphore.withPermits(1)(admission.pipe(Effect.uninterruptible));
|
|
146
|
+
/**
|
|
147
|
+
* Runs the storage-backed state transition behind Cloudflare's Durable Object concurrency gate.
|
|
148
|
+
* This scope should remain limited to local persistence and head mutation; ordered publication is handled
|
|
149
|
+
* separately by `runSerializedPushAdmission` so outbound work does not block unrelated Durable Object events.
|
|
150
|
+
*
|
|
131
151
|
* @see https://developers.cloudflare.com/durable-objects/api/state/#blockconcurrencywhile
|
|
132
152
|
*/
|
|
133
153
|
const blockConcurrencyWhile = (ctx) => (eff) => Effect.gen(function* () {
|
|
134
|
-
const
|
|
135
|
-
const exit = yield* Effect.promise(() => ctx.blockConcurrencyWhile(() => eff.pipe(Effect.
|
|
154
|
+
const services = yield* Effect.context();
|
|
155
|
+
const exit = yield* Effect.promise(() => ctx.blockConcurrencyWhile(() => eff.pipe(Effect.runPromiseExitWith(services))));
|
|
136
156
|
return yield* exit;
|
|
137
157
|
});
|
|
138
158
|
//# sourceMappingURL=push.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../../src/cf-worker/do/push.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../../../src/cf-worker/do/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.test.d.ts","sourceRoot":"","sources":["../../../src/cf-worker/do/push.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Vitest } from '@livestore/utils-dev/node-vitest';
|
|
2
|
+
import { Deferred, Duration, Effect, Fiber, Semaphore } from '@livestore/utils/effect';
|
|
3
|
+
import { runSerializedPushAdmission } from "./push.js";
|
|
4
|
+
Vitest.describe('sync-cf push admission', () => {
|
|
5
|
+
Vitest.live('publishes an admitted push before honoring interruption', () => Effect.gen(function* () {
|
|
6
|
+
const semaphore = yield* Semaphore.make(1);
|
|
7
|
+
const persisted = yield* Deferred.make();
|
|
8
|
+
const allowBroadcast = yield* Deferred.make();
|
|
9
|
+
const broadcasted = yield* Deferred.make();
|
|
10
|
+
const admissionFiber = yield* runSerializedPushAdmission(semaphore, Effect.gen(function* () {
|
|
11
|
+
yield* Deferred.succeed(persisted, undefined);
|
|
12
|
+
yield* Deferred.await(allowBroadcast);
|
|
13
|
+
yield* Deferred.succeed(broadcasted, undefined);
|
|
14
|
+
})).pipe(Effect.forkChild);
|
|
15
|
+
// Reproduce cancellation after persistence but before the pull broadcast handoff.
|
|
16
|
+
yield* Deferred.await(persisted);
|
|
17
|
+
const interruptStarted = yield* Deferred.make();
|
|
18
|
+
const interruptFiber = yield* Effect.gen(function* () {
|
|
19
|
+
yield* Deferred.succeed(interruptStarted, undefined);
|
|
20
|
+
yield* Fiber.interrupt(admissionFiber);
|
|
21
|
+
}).pipe(Effect.forkChild);
|
|
22
|
+
yield* Deferred.await(interruptStarted);
|
|
23
|
+
yield* Effect.yieldNow;
|
|
24
|
+
yield* Deferred.succeed(allowBroadcast, undefined);
|
|
25
|
+
yield* Deferred.await(broadcasted).pipe(Effect.timeout(Duration.seconds(1)));
|
|
26
|
+
yield* Fiber.join(interruptFiber);
|
|
27
|
+
Vitest.expect(yield* Deferred.isDone(broadcasted)).toBe(true);
|
|
28
|
+
}));
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=push.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.test.js","sourceRoot":"","sources":["../../../src/cf-worker/do/push.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAA;AACzD,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAEtF,OAAO,EAAE,0BAA0B,EAAE,MAAM,WAAW,CAAA;AAEtD,MAAM,CAAC,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IAC7C,MAAM,CAAC,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE,CAC1E,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAA;QAC9C,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAA;QACnD,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAA;QAEhD,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,0BAA0B,CACtD,SAAS,EACT,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;YAC7C,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;YACrC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;QACjD,CAAC,CAAC,CACH,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QAExB,kFAAkF;QAClF,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAChC,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAQ,CAAA;QACrD,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAChD,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAA;YACpD,KAAK,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAA;QACxC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACzB,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;QACvC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAA;QAEtB,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,SAAS,CAAC,CAAA;QAClD,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5E,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;QAEjC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC/D,CAAC,CAAC,CACH,CAAA;AACH,CAAC,CAAC,CAAA"}
|
|
@@ -8,7 +8,7 @@ import { Schema } from '@livestore/utils/effect';
|
|
|
8
8
|
export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"eventlog_7_$storeId", {
|
|
9
9
|
readonly seqNum: {
|
|
10
10
|
columnType: "integer";
|
|
11
|
-
schema: Schema.
|
|
11
|
+
schema: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
12
12
|
default: import("effect/Option").None<never>;
|
|
13
13
|
nullable: false;
|
|
14
14
|
primaryKey: true;
|
|
@@ -16,7 +16,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
16
16
|
};
|
|
17
17
|
readonly parentSeqNum: {
|
|
18
18
|
columnType: "integer";
|
|
19
|
-
schema: Schema.
|
|
19
|
+
schema: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
20
20
|
default: import("effect/Option").None<never>;
|
|
21
21
|
nullable: false;
|
|
22
22
|
primaryKey: false;
|
|
@@ -24,7 +24,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
24
24
|
};
|
|
25
25
|
readonly name: {
|
|
26
26
|
columnType: "text";
|
|
27
|
-
schema: Schema.
|
|
27
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
28
28
|
default: import("effect/Option").None<never>;
|
|
29
29
|
nullable: false;
|
|
30
30
|
primaryKey: false;
|
|
@@ -32,7 +32,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
32
32
|
};
|
|
33
33
|
readonly args: {
|
|
34
34
|
columnType: "text";
|
|
35
|
-
schema: Schema.
|
|
35
|
+
schema: Schema.Codec<any, string | null, never, never>;
|
|
36
36
|
default: import("effect/Option").None<never>;
|
|
37
37
|
nullable: true;
|
|
38
38
|
primaryKey: false;
|
|
@@ -41,7 +41,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
41
41
|
/** ISO date format. Currently only used for debugging purposes. */
|
|
42
42
|
readonly createdAt: {
|
|
43
43
|
columnType: "text";
|
|
44
|
-
schema: Schema.
|
|
44
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
45
45
|
default: import("effect/Option").None<never>;
|
|
46
46
|
nullable: false;
|
|
47
47
|
primaryKey: false;
|
|
@@ -49,7 +49,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
49
49
|
};
|
|
50
50
|
readonly clientId: {
|
|
51
51
|
columnType: "text";
|
|
52
|
-
schema: Schema.
|
|
52
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
53
53
|
default: import("effect/Option").None<never>;
|
|
54
54
|
nullable: false;
|
|
55
55
|
primaryKey: false;
|
|
@@ -57,7 +57,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
57
57
|
};
|
|
58
58
|
readonly sessionId: {
|
|
59
59
|
columnType: "text";
|
|
60
|
-
schema: Schema.
|
|
60
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
61
61
|
default: import("effect/Option").None<never>;
|
|
62
62
|
nullable: false;
|
|
63
63
|
primaryKey: false;
|
|
@@ -66,7 +66,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
66
66
|
}>, State.SQLite.WithDefaults<{
|
|
67
67
|
readonly seqNum: {
|
|
68
68
|
columnType: "integer";
|
|
69
|
-
schema: Schema.
|
|
69
|
+
schema: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
70
70
|
default: import("effect/Option").None<never>;
|
|
71
71
|
nullable: false;
|
|
72
72
|
primaryKey: true;
|
|
@@ -74,7 +74,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
74
74
|
};
|
|
75
75
|
readonly parentSeqNum: {
|
|
76
76
|
columnType: "integer";
|
|
77
|
-
schema: Schema.
|
|
77
|
+
schema: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
78
78
|
default: import("effect/Option").None<never>;
|
|
79
79
|
nullable: false;
|
|
80
80
|
primaryKey: false;
|
|
@@ -82,7 +82,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
82
82
|
};
|
|
83
83
|
readonly name: {
|
|
84
84
|
columnType: "text";
|
|
85
|
-
schema: Schema.
|
|
85
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
86
86
|
default: import("effect/Option").None<never>;
|
|
87
87
|
nullable: false;
|
|
88
88
|
primaryKey: false;
|
|
@@ -90,7 +90,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
90
90
|
};
|
|
91
91
|
readonly args: {
|
|
92
92
|
columnType: "text";
|
|
93
|
-
schema: Schema.
|
|
93
|
+
schema: Schema.Codec<any, string | null, never, never>;
|
|
94
94
|
default: import("effect/Option").None<never>;
|
|
95
95
|
nullable: true;
|
|
96
96
|
primaryKey: false;
|
|
@@ -99,7 +99,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
99
99
|
/** ISO date format. Currently only used for debugging purposes. */
|
|
100
100
|
readonly createdAt: {
|
|
101
101
|
columnType: "text";
|
|
102
|
-
schema: Schema.
|
|
102
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
103
103
|
default: import("effect/Option").None<never>;
|
|
104
104
|
nullable: false;
|
|
105
105
|
primaryKey: false;
|
|
@@ -107,7 +107,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
107
107
|
};
|
|
108
108
|
readonly clientId: {
|
|
109
109
|
columnType: "text";
|
|
110
|
-
schema: Schema.
|
|
110
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
111
111
|
default: import("effect/Option").None<never>;
|
|
112
112
|
nullable: false;
|
|
113
113
|
primaryKey: false;
|
|
@@ -115,29 +115,21 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
115
115
|
};
|
|
116
116
|
readonly sessionId: {
|
|
117
117
|
columnType: "text";
|
|
118
|
-
schema: Schema.
|
|
118
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
119
119
|
default: import("effect/Option").None<never>;
|
|
120
120
|
nullable: false;
|
|
121
121
|
primaryKey: false;
|
|
122
122
|
autoIncrement: false;
|
|
123
123
|
};
|
|
124
|
-
}>, Schema.
|
|
125
|
-
readonly seqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
|
|
126
|
-
readonly parentSeqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
|
|
127
|
-
readonly name: string
|
|
128
|
-
readonly args: any
|
|
129
|
-
readonly createdAt: string
|
|
130
|
-
readonly clientId: string
|
|
131
|
-
readonly sessionId: string
|
|
132
|
-
}
|
|
133
|
-
readonly seqNum: number;
|
|
134
|
-
readonly parentSeqNum: number;
|
|
135
|
-
readonly name: string;
|
|
136
|
-
readonly args: string | null;
|
|
137
|
-
readonly createdAt: string;
|
|
138
|
-
readonly clientId: string;
|
|
139
|
-
readonly sessionId: string;
|
|
140
|
-
}, never>>;
|
|
124
|
+
}>, Schema.Struct<{
|
|
125
|
+
readonly seqNum: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
126
|
+
readonly parentSeqNum: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
127
|
+
readonly name: Schema.Codec<string, string, never, never>;
|
|
128
|
+
readonly args: Schema.Codec<any, string | null, never, never>;
|
|
129
|
+
readonly createdAt: Schema.Codec<string, string, never, never>;
|
|
130
|
+
readonly clientId: Schema.Codec<string, string, never, never>;
|
|
131
|
+
readonly sessionId: Schema.Codec<string, string, never, never>;
|
|
132
|
+
}>>;
|
|
141
133
|
/**
|
|
142
134
|
* Context metadata table - one row per Durable Object.
|
|
143
135
|
*
|
|
@@ -146,7 +138,7 @@ export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTab
|
|
|
146
138
|
export declare const contextTable: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"context_7", {
|
|
147
139
|
readonly storeId: {
|
|
148
140
|
columnType: "text";
|
|
149
|
-
schema: Schema.
|
|
141
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
150
142
|
default: import("effect/Option").None<never>;
|
|
151
143
|
nullable: false;
|
|
152
144
|
primaryKey: true;
|
|
@@ -154,7 +146,7 @@ export declare const contextTable: State.SQLite.TableDef<State.SQLite.SqliteTabl
|
|
|
154
146
|
};
|
|
155
147
|
readonly currentHead: {
|
|
156
148
|
columnType: "integer";
|
|
157
|
-
schema: Schema.
|
|
149
|
+
schema: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
158
150
|
default: import("effect/Option").None<never>;
|
|
159
151
|
nullable: false;
|
|
160
152
|
primaryKey: false;
|
|
@@ -162,7 +154,7 @@ export declare const contextTable: State.SQLite.TableDef<State.SQLite.SqliteTabl
|
|
|
162
154
|
};
|
|
163
155
|
readonly backendId: {
|
|
164
156
|
columnType: "text";
|
|
165
|
-
schema: Schema.
|
|
157
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
166
158
|
default: import("effect/Option").None<never>;
|
|
167
159
|
nullable: false;
|
|
168
160
|
primaryKey: false;
|
|
@@ -171,7 +163,7 @@ export declare const contextTable: State.SQLite.TableDef<State.SQLite.SqliteTabl
|
|
|
171
163
|
}>, State.SQLite.WithDefaults<{
|
|
172
164
|
readonly storeId: {
|
|
173
165
|
columnType: "text";
|
|
174
|
-
schema: Schema.
|
|
166
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
175
167
|
default: import("effect/Option").None<never>;
|
|
176
168
|
nullable: false;
|
|
177
169
|
primaryKey: true;
|
|
@@ -179,7 +171,7 @@ export declare const contextTable: State.SQLite.TableDef<State.SQLite.SqliteTabl
|
|
|
179
171
|
};
|
|
180
172
|
readonly currentHead: {
|
|
181
173
|
columnType: "integer";
|
|
182
|
-
schema: Schema.
|
|
174
|
+
schema: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
183
175
|
default: import("effect/Option").None<never>;
|
|
184
176
|
nullable: false;
|
|
185
177
|
primaryKey: false;
|
|
@@ -187,19 +179,15 @@ export declare const contextTable: State.SQLite.TableDef<State.SQLite.SqliteTabl
|
|
|
187
179
|
};
|
|
188
180
|
readonly backendId: {
|
|
189
181
|
columnType: "text";
|
|
190
|
-
schema: Schema.
|
|
182
|
+
schema: Schema.Codec<string, string, never, never>;
|
|
191
183
|
default: import("effect/Option").None<never>;
|
|
192
184
|
nullable: false;
|
|
193
185
|
primaryKey: false;
|
|
194
186
|
autoIncrement: false;
|
|
195
187
|
};
|
|
196
|
-
}>, Schema.
|
|
197
|
-
readonly storeId: string
|
|
198
|
-
readonly currentHead: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
|
|
199
|
-
readonly backendId: string
|
|
200
|
-
}
|
|
201
|
-
readonly storeId: string;
|
|
202
|
-
readonly currentHead: number;
|
|
203
|
-
readonly backendId: string;
|
|
204
|
-
}, never>>;
|
|
188
|
+
}>, Schema.Struct<{
|
|
189
|
+
readonly storeId: Schema.Codec<string, string, never, never>;
|
|
190
|
+
readonly currentHead: Schema.Codec<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never, never>;
|
|
191
|
+
readonly backendId: Schema.Codec<string, string, never, never>;
|
|
192
|
+
}>>;
|
|
205
193
|
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/cf-worker/do/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAIhD;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQtB,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAnE,mEAAmE
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../../src/cf-worker/do/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAIhD;;;;GAIG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQtB,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAnE,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKrE,CAAA;AAEF;;;;GAIG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAOvB,CAAA"}
|
|
@@ -13,7 +13,7 @@ export const eventlogTable = State.SQLite.table({
|
|
|
13
13
|
seqNum: State.SQLite.integer({ primaryKey: true, schema: EventSequenceNumber.Global.Schema }),
|
|
14
14
|
parentSeqNum: State.SQLite.integer({ schema: EventSequenceNumber.Global.Schema }),
|
|
15
15
|
name: State.SQLite.text({}),
|
|
16
|
-
args: State.SQLite.text({ schema: Schema.
|
|
16
|
+
args: State.SQLite.text({ schema: Schema.fromJsonString(Schema.Any), nullable: true }),
|
|
17
17
|
/** ISO date format. Currently only used for debugging purposes. */
|
|
18
18
|
createdAt: State.SQLite.text({}),
|
|
19
19
|
clientId: State.SQLite.text({}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../src/cf-worker/do/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;IAC9C,wEAAwE;IACxE,IAAI,EAAE,YAAY,0BAA0B,WAAW;IACvD,OAAO,EAAE;QACP,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7F,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACjF,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../../src/cf-worker/do/sqlite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAA;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AAEzD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;IAC9C,wEAAwE;IACxE,IAAI,EAAE,YAAY,0BAA0B,WAAW;IACvD,OAAO,EAAE;QACP,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAC7F,YAAY,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACjF,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACtF,mEAAmE;QACnE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;KACjC;CACF,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;IAC7C,IAAI,EAAE,WAAW,0BAA0B,EAAE;IAC7C,OAAO,EAAE;QACP,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QAChD,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,mBAAmB,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QAChF,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;KACjC;CACF,CAAC,CAAA"}
|
|
@@ -4,6 +4,12 @@ import type { LiveStoreEvent } from '@livestore/common/schema';
|
|
|
4
4
|
import { Effect, Option, Stream } from '@livestore/utils/effect';
|
|
5
5
|
import { SyncMetadata } from '../../common/sync-message-types.ts';
|
|
6
6
|
import { type StoreId } from '../shared.ts';
|
|
7
|
+
export type StorageEngine = {
|
|
8
|
+
_tag: 'd1';
|
|
9
|
+
db: CfTypes.D1Database;
|
|
10
|
+
} | {
|
|
11
|
+
_tag: 'do-sqlite';
|
|
12
|
+
};
|
|
7
13
|
export type SyncStorage = {
|
|
8
14
|
dbName: string;
|
|
9
15
|
getEvents: (cursor: number | undefined) => Effect.Effect<{
|
|
@@ -16,10 +22,5 @@ export type SyncStorage = {
|
|
|
16
22
|
appendEvents: (batch: ReadonlyArray<LiveStoreEvent.Global.Encoded>, createdAt: string) => Effect.Effect<void, UnknownError>;
|
|
17
23
|
resetStore: Effect.Effect<void, UnknownError>;
|
|
18
24
|
};
|
|
19
|
-
export declare const makeStorage: (ctx: CfTypes.DurableObjectState, storeId: StoreId, engine:
|
|
20
|
-
_tag: "d1";
|
|
21
|
-
db: CfTypes.D1Database;
|
|
22
|
-
} | {
|
|
23
|
-
_tag: "do-sqlite";
|
|
24
|
-
}) => SyncStorage;
|
|
25
|
+
export declare const makeStorage: (ctx: CfTypes.DurableObjectState, storeId: StoreId, engine: StorageEngine) => SyncStorage;
|
|
25
26
|
//# sourceMappingURL=sync-storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-storage.d.ts","sourceRoot":"","sources":["../../../src/cf-worker/do/sync-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,
|
|
1
|
+
{"version":3,"file":"sync-storage.d.ts","sourceRoot":"","sources":["../../../src/cf-worker/do/sync-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,EAAwC,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEtG,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AACjE,OAAO,EAA8B,KAAK,OAAO,EAAE,MAAM,cAAc,CAAA;AAGvE,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC,UAAU,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAA;AAE1F,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,CAAC,MAAM,CACtD;QACE,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,CACnB;YAAE,YAAY,EAAE,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;SAAE,EACtF,YAAY,CACb,CAAA;KACF,EACD,YAAY,CACb,CAAA;IACD,YAAY,EAAE,CACZ,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,EACnD,SAAS,EAAE,MAAM,KACd,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;IACtC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;CAC9C,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,KAAK,OAAO,CAAC,kBAAkB,EAAE,SAAS,OAAO,EAAE,QAAQ,aAAa,KAAG,WAiTtG,CAAA"}
|