@livestore/sync-cf 0.4.0-dev.7 → 0.4.0-dev.8

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.
Files changed (35) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/cf-worker/do/pull.d.ts.map +1 -1
  3. package/dist/cf-worker/do/pull.js +14 -12
  4. package/dist/cf-worker/do/pull.js.map +1 -1
  5. package/dist/cf-worker/do/push.d.ts.map +1 -1
  6. package/dist/cf-worker/do/push.js +1 -1
  7. package/dist/cf-worker/do/push.js.map +1 -1
  8. package/dist/cf-worker/do/sync-storage.d.ts +8 -5
  9. package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
  10. package/dist/cf-worker/do/sync-storage.js +64 -19
  11. package/dist/cf-worker/do/sync-storage.js.map +1 -1
  12. package/package.json +4 -4
  13. package/src/cf-worker/do/pull.ts +17 -16
  14. package/src/cf-worker/do/push.ts +1 -0
  15. package/src/cf-worker/do/sync-storage.ts +106 -27
  16. package/dist/cf-worker/cf-types.d.ts +0 -2
  17. package/dist/cf-worker/cf-types.d.ts.map +0 -1
  18. package/dist/cf-worker/cf-types.js +0 -2
  19. package/dist/cf-worker/cf-types.js.map +0 -1
  20. package/dist/cf-worker/durable-object.d.ts +0 -189
  21. package/dist/cf-worker/durable-object.d.ts.map +0 -1
  22. package/dist/cf-worker/durable-object.js +0 -317
  23. package/dist/cf-worker/durable-object.js.map +0 -1
  24. package/dist/common/ws-message-types.d.ts +0 -270
  25. package/dist/common/ws-message-types.d.ts.map +0 -1
  26. package/dist/common/ws-message-types.js +0 -57
  27. package/dist/common/ws-message-types.js.map +0 -1
  28. package/dist/sync-impl/mod.d.ts +0 -2
  29. package/dist/sync-impl/mod.d.ts.map +0 -1
  30. package/dist/sync-impl/mod.js +0 -2
  31. package/dist/sync-impl/mod.js.map +0 -1
  32. package/dist/sync-impl/ws-impl.d.ts +0 -7
  33. package/dist/sync-impl/ws-impl.d.ts.map +0 -1
  34. package/dist/sync-impl/ws-impl.js +0 -175
  35. package/dist/sync-impl/ws-impl.js.map +0 -1
@@ -1,189 +0,0 @@
1
- import { State } from '@livestore/common/schema';
2
- import { Effect, Option, Schema } from '@livestore/utils/effect';
3
- import { WSMessage } from '../common/mod.ts';
4
- import type * as CfWorker from './cf-types.ts';
5
- export interface Env {
6
- DB: CfWorker.D1Database;
7
- ADMIN_SECRET: string;
8
- }
9
- export declare const eventlogTable: State.SQLite.TableDef<State.SQLite.SqliteTableDefForInput<"eventlog_$PERSISTENCE_FORMAT_VERSION_$storeId", {
10
- readonly seqNum: {
11
- columnType: "integer";
12
- schema: Schema.Schema<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never>;
13
- default: Option.None<never>;
14
- nullable: false;
15
- primaryKey: true;
16
- autoIncrement: false;
17
- };
18
- readonly parentSeqNum: {
19
- columnType: "integer";
20
- schema: Schema.Schema<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never>;
21
- default: Option.None<never>;
22
- nullable: false;
23
- primaryKey: false;
24
- autoIncrement: false;
25
- };
26
- readonly name: {
27
- columnType: "text";
28
- schema: Schema.Schema<string, string, never>;
29
- default: Option.None<never>;
30
- nullable: false;
31
- primaryKey: false;
32
- autoIncrement: false;
33
- };
34
- readonly args: {
35
- columnType: "text";
36
- schema: Schema.Schema<any, string | null, never>;
37
- default: Option.None<never>;
38
- nullable: true;
39
- primaryKey: false;
40
- autoIncrement: false;
41
- };
42
- /** ISO date format. Currently only used for debugging purposes. */
43
- readonly createdAt: {
44
- columnType: "text";
45
- schema: Schema.Schema<string, string, never>;
46
- default: Option.None<never>;
47
- nullable: false;
48
- primaryKey: false;
49
- autoIncrement: false;
50
- };
51
- readonly clientId: {
52
- columnType: "text";
53
- schema: Schema.Schema<string, string, never>;
54
- default: Option.None<never>;
55
- nullable: false;
56
- primaryKey: false;
57
- autoIncrement: false;
58
- };
59
- readonly sessionId: {
60
- columnType: "text";
61
- schema: Schema.Schema<string, string, never>;
62
- default: Option.None<never>;
63
- nullable: false;
64
- primaryKey: false;
65
- autoIncrement: false;
66
- };
67
- }>, State.SQLite.WithDefaults<{
68
- readonly seqNum: {
69
- columnType: "integer";
70
- schema: Schema.Schema<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never>;
71
- default: Option.None<never>;
72
- nullable: false;
73
- primaryKey: true;
74
- autoIncrement: false;
75
- };
76
- readonly parentSeqNum: {
77
- columnType: "integer";
78
- schema: Schema.Schema<number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">, number, never>;
79
- default: Option.None<never>;
80
- nullable: false;
81
- primaryKey: false;
82
- autoIncrement: false;
83
- };
84
- readonly name: {
85
- columnType: "text";
86
- schema: Schema.Schema<string, string, never>;
87
- default: Option.None<never>;
88
- nullable: false;
89
- primaryKey: false;
90
- autoIncrement: false;
91
- };
92
- readonly args: {
93
- columnType: "text";
94
- schema: Schema.Schema<any, string | null, never>;
95
- default: Option.None<never>;
96
- nullable: true;
97
- primaryKey: false;
98
- autoIncrement: false;
99
- };
100
- /** ISO date format. Currently only used for debugging purposes. */
101
- readonly createdAt: {
102
- columnType: "text";
103
- schema: Schema.Schema<string, string, never>;
104
- default: Option.None<never>;
105
- nullable: false;
106
- primaryKey: false;
107
- autoIncrement: false;
108
- };
109
- readonly clientId: {
110
- columnType: "text";
111
- schema: Schema.Schema<string, string, never>;
112
- default: Option.None<never>;
113
- nullable: false;
114
- primaryKey: false;
115
- autoIncrement: false;
116
- };
117
- readonly sessionId: {
118
- columnType: "text";
119
- schema: Schema.Schema<string, string, never>;
120
- default: Option.None<never>;
121
- nullable: false;
122
- primaryKey: false;
123
- autoIncrement: false;
124
- };
125
- }>, Schema.Schema<{
126
- readonly seqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
127
- readonly parentSeqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
128
- readonly name: string;
129
- readonly args: any;
130
- readonly createdAt: string;
131
- readonly clientId: string;
132
- readonly sessionId: string;
133
- }, {
134
- readonly seqNum: number;
135
- readonly parentSeqNum: number;
136
- readonly name: string;
137
- readonly args: string | null;
138
- readonly createdAt: string;
139
- readonly clientId: string;
140
- readonly sessionId: string;
141
- }, never>>;
142
- export declare const PULL_CHUNK_SIZE = 100;
143
- /**
144
- * Needs to be bumped when the storage format changes (e.g. eventlogTable schema changes)
145
- *
146
- * Changing this version number will lead to a "soft reset".
147
- */
148
- export declare const PERSISTENCE_FORMAT_VERSION = 7;
149
- export type MakeDurableObjectClassOptions = {
150
- onPush?: (message: WSMessage.PushReq, context: {
151
- storeId: string;
152
- payload?: Schema.JsonValue;
153
- }) => Effect.Effect<void> | Promise<void>;
154
- onPushRes?: (message: WSMessage.PushAck | WSMessage.Error) => Effect.Effect<void> | Promise<void>;
155
- onPull?: (message: WSMessage.PullReq, context: {
156
- storeId: string;
157
- payload?: Schema.JsonValue;
158
- }) => Effect.Effect<void> | Promise<void>;
159
- onPullRes?: (message: WSMessage.PullRes | WSMessage.Error) => Effect.Effect<void> | Promise<void>;
160
- };
161
- export type MakeDurableObjectClass = (options?: MakeDurableObjectClassOptions) => {
162
- new (ctx: CfWorker.DurableObjectState, env: Env): CfWorker.DurableObject;
163
- };
164
- /**
165
- * Creates a Durable Object class for handling WebSocket-based sync.
166
- *
167
- * Example:
168
- * ```ts
169
- * // In your Cloudflare Worker file
170
- * import { makeDurableObject } from '@livestore/sync-cf/cf-worker'
171
- *
172
- * export class WebSocketServer extends makeDurableObject({
173
- * onPush: async (message) => {
174
- * console.log('onPush', message.batch)
175
- * },
176
- * onPull: async (message) => {
177
- * console.log('onPull', message)
178
- * },
179
- * }) {}
180
- * ```
181
- *
182
- * ```toml
183
- * # wrangler.toml
184
- * [new_classes]
185
- * WebSocketServer = "src/websocket-server.ts"
186
- * ```
187
- */
188
- export declare const makeDurableObject: MakeDurableObjectClass;
189
- //# sourceMappingURL=durable-object.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"durable-object.d.ts","sourceRoot":"","sources":["../../src/cf-worker/durable-object.ts"],"names":[],"mappings":"AACA,OAAO,EAA4C,KAAK,EAAE,MAAM,0BAA0B,CAAA;AAE1F,OAAO,EAAE,MAAM,EAAoB,MAAM,EAAE,MAAM,EAAa,MAAM,yBAAyB,CAAA;AAC7F,OAAO,EAAsB,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEhE,OAAO,KAAK,KAAK,QAAQ,MAAM,eAAe,CAAA;AAO9C,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,QAAQ,CAAC,UAAU,CAAA;IACvB,YAAY,EAAE,MAAM,CAAA;CACrB;AAKD,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQtB,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAnE,mEAAmE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAKrE,CAAA;AASF,eAAO,MAAM,eAAe,MAAM,CAAA;AAElC;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,IAAI,CAAA;AAE3C,MAAM,MAAM,6BAA6B,GAAG;IAC1C,MAAM,CAAC,EAAE,CACP,OAAO,EAAE,SAAS,CAAC,OAAO,EAC1B,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,SAAS,CAAA;KAAE,KACrD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjG,MAAM,CAAC,EAAE,CACP,OAAO,EAAE,SAAS,CAAC,OAAO,EAC1B,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC,SAAS,CAAA;KAAE,KACrD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClG,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,CAAC,EAAE,6BAA6B,KAAK;IAChF,KAAK,GAAG,EAAE,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAA;CACzE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,iBAAiB,EAAE,sBA4Q/B,CAAA"}
@@ -1,317 +0,0 @@
1
- import { UnexpectedError } from '@livestore/common';
2
- import { EventSequenceNumber, State } from '@livestore/common/schema';
3
- import { shouldNeverHappen } from '@livestore/utils';
4
- import { Effect, Logger, LogLevel, Option, Schema, UrlParams } from '@livestore/utils/effect';
5
- import { SearchParamsSchema, WSMessage } from "../common/mod.js";
6
- const encodeOutgoingMessage = Schema.encodeSync(Schema.parseJson(WSMessage.BackendToClientMessage));
7
- const encodeIncomingMessage = Schema.encodeSync(Schema.parseJson(WSMessage.ClientToBackendMessage));
8
- export const eventlogTable = State.SQLite.table({
9
- // NOTE actual table name is determined at runtime
10
- name: 'eventlog_$PERSISTENCE_FORMAT_VERSION_$storeId',
11
- columns: {
12
- seqNum: State.SQLite.integer({ primaryKey: true, schema: EventSequenceNumber.GlobalEventSequenceNumber }),
13
- parentSeqNum: State.SQLite.integer({ schema: EventSequenceNumber.GlobalEventSequenceNumber }),
14
- name: State.SQLite.text({}),
15
- args: State.SQLite.text({ schema: Schema.parseJson(Schema.Any), nullable: true }),
16
- /** ISO date format. Currently only used for debugging purposes. */
17
- createdAt: State.SQLite.text({}),
18
- clientId: State.SQLite.text({}),
19
- sessionId: State.SQLite.text({}),
20
- },
21
- });
22
- const WebSocketAttachmentSchema = Schema.parseJson(Schema.Struct({
23
- storeId: Schema.String,
24
- payload: Schema.optional(Schema.JsonValue),
25
- }));
26
- export const PULL_CHUNK_SIZE = 100;
27
- /**
28
- * Needs to be bumped when the storage format changes (e.g. eventlogTable schema changes)
29
- *
30
- * Changing this version number will lead to a "soft reset".
31
- */
32
- export const PERSISTENCE_FORMAT_VERSION = 7;
33
- /**
34
- * Creates a Durable Object class for handling WebSocket-based sync.
35
- *
36
- * Example:
37
- * ```ts
38
- * // In your Cloudflare Worker file
39
- * import { makeDurableObject } from '@livestore/sync-cf/cf-worker'
40
- *
41
- * export class WebSocketServer extends makeDurableObject({
42
- * onPush: async (message) => {
43
- * console.log('onPush', message.batch)
44
- * },
45
- * onPull: async (message) => {
46
- * console.log('onPull', message)
47
- * },
48
- * }) {}
49
- * ```
50
- *
51
- * ```toml
52
- * # wrangler.toml
53
- * [new_classes]
54
- * WebSocketServer = "src/websocket-server.ts"
55
- * ```
56
- */
57
- export const makeDurableObject = (options) => {
58
- return class WebSocketServerBase {
59
- __DURABLE_OBJECT_BRAND = 'WebSocketServerBase';
60
- ctx;
61
- env;
62
- constructor(ctx, env) {
63
- this.ctx = ctx;
64
- this.env = env;
65
- }
66
- /** Needed to prevent concurrent pushes */
67
- pushSemaphore = Effect.makeSemaphore(1).pipe(Effect.runSync);
68
- currentHead = 'uninitialized';
69
- fetch = async (request) => Effect.sync(() => {
70
- const { storeId, payload } = getRequestSearchParams(request);
71
- const storage = makeStorage(this.ctx, this.env, storeId);
72
- const { 0: client, 1: server } = new WebSocketPair();
73
- // Since we're using websocket hibernation, we need to remember the storeId for subsequent `webSocketMessage` calls
74
- server.serializeAttachment(Schema.encodeSync(WebSocketAttachmentSchema)({ storeId, payload }));
75
- // See https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server
76
- this.ctx.acceptWebSocket(server);
77
- this.ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair(encodeIncomingMessage(WSMessage.Ping.make({ requestId: 'ping' })), encodeOutgoingMessage(WSMessage.Pong.make({ requestId: 'ping' }))));
78
- const colSpec = State.SQLite.makeColumnSpec(eventlogTable.sqliteDef.ast);
79
- this.env.DB.exec(`CREATE TABLE IF NOT EXISTS ${storage.dbName} (${colSpec}) strict`);
80
- return new Response(null, {
81
- status: 101,
82
- webSocket: client,
83
- });
84
- }).pipe(Effect.tapCauseLogPretty, Effect.runPromise);
85
- webSocketMessage = (ws, message) => {
86
- const decodedMessageRes = Schema.decodeUnknownEither(Schema.parseJson(WSMessage.ClientToBackendMessage))(message);
87
- if (decodedMessageRes._tag === 'Left') {
88
- Effect.logError('Invalid message received', { message }).pipe(Effect.provide(Logger.prettyWithThread('durable-object')), Effect.runSync);
89
- return;
90
- }
91
- const decodedMessage = decodedMessageRes.right;
92
- const requestId = decodedMessage.requestId;
93
- return Effect.gen(this, function* () {
94
- const { storeId, payload } = yield* Schema.decode(WebSocketAttachmentSchema)(ws.deserializeAttachment());
95
- const storage = makeStorage(this.ctx, this.env, storeId);
96
- switch (decodedMessage._tag) {
97
- // TODO allow pulling concurrently to not block incoming push requests
98
- case 'WSMessage.PullReq': {
99
- if (options?.onPull) {
100
- yield* Effect.tryAll(() => options.onPull(decodedMessage, { storeId, payload }));
101
- }
102
- const respond = (message) => Effect.gen(function* () {
103
- if (options?.onPullRes) {
104
- yield* Effect.tryAll(() => options.onPullRes(message));
105
- }
106
- if (ws.readyState !== WebSocket.OPEN) {
107
- yield* Effect.logWarning('WebSocket not open, skipping send', {
108
- readyState: ws.readyState,
109
- message,
110
- });
111
- return;
112
- }
113
- yield* Effect.try({
114
- try: () => ws.send(encodeOutgoingMessage(message)),
115
- catch: (cause) => new UnexpectedError({ cause, note: 'Failed to send pull response', payload: { message } }),
116
- });
117
- });
118
- const cursor = decodedMessage.cursor;
119
- // TODO use streaming
120
- const remainingEvents = yield* storage.getEvents(cursor);
121
- // Send at least one response, even if there are no events
122
- const batches = remainingEvents.length === 0
123
- ? [[]]
124
- : Array.from({ length: Math.ceil(remainingEvents.length / PULL_CHUNK_SIZE) }, (_, i) => remainingEvents.slice(i * PULL_CHUNK_SIZE, (i + 1) * PULL_CHUNK_SIZE));
125
- for (const [index, batch] of batches.entries()) {
126
- const remaining = Math.max(0, remainingEvents.length - (index + 1) * PULL_CHUNK_SIZE);
127
- yield* respond(WSMessage.PullRes.make({ batch, remaining, requestId: { context: 'pull', requestId } }));
128
- }
129
- break;
130
- }
131
- case 'WSMessage.PushReq': {
132
- const respond = (message) => Effect.gen(function* () {
133
- if (options?.onPushRes) {
134
- yield* Effect.tryAll(() => options.onPushRes(message));
135
- }
136
- ws.send(encodeOutgoingMessage(message));
137
- });
138
- if (decodedMessage.batch.length === 0) {
139
- yield* respond(WSMessage.PushAck.make({ requestId }));
140
- return;
141
- }
142
- yield* this.pushSemaphore.take(1);
143
- if (options?.onPush) {
144
- yield* Effect.tryAll(() => options.onPush(decodedMessage, { storeId, payload }));
145
- }
146
- // TODO check whether we could use the Durable Object storage for this to speed up the lookup
147
- // const expectedParentNum = yield* storage.getHead
148
- let currentHead;
149
- if (this.currentHead === 'uninitialized') {
150
- const currentHeadFromStorage = yield* Effect.promise(() => this.ctx.storage.get('currentHead'));
151
- // console.log('currentHeadFromStorage', currentHeadFromStorage)
152
- if (currentHeadFromStorage === undefined) {
153
- // console.log('currentHeadFromStorage is null, getting from D1')
154
- // currentHead = yield* storage.getHead
155
- // console.log('currentHeadFromStorage is null, using root')
156
- currentHead = EventSequenceNumber.ROOT.global;
157
- }
158
- else {
159
- currentHead = currentHeadFromStorage;
160
- }
161
- }
162
- else {
163
- // console.log('currentHead is already initialized', this.currentHead)
164
- currentHead = this.currentHead;
165
- }
166
- // TODO handle clientId unique conflict
167
- // Validate the batch
168
- const firstEvent = decodedMessage.batch[0];
169
- if (firstEvent.parentSeqNum !== currentHead) {
170
- const err = WSMessage.Error.make({
171
- message: `Invalid parent event number. Received e${firstEvent.parentSeqNum} but expected e${currentHead}`,
172
- requestId,
173
- });
174
- yield* Effect.logError(err);
175
- yield* respond(err);
176
- yield* this.pushSemaphore.release(1);
177
- return;
178
- }
179
- yield* respond(WSMessage.PushAck.make({ requestId }));
180
- const createdAt = new Date().toISOString();
181
- // NOTE we're not waiting for this to complete yet to allow the broadcast to happen right away
182
- // while letting the async storage write happen in the background
183
- const storeFiber = yield* storage.appendEvents(decodedMessage.batch, createdAt).pipe(Effect.fork);
184
- this.currentHead = decodedMessage.batch.at(-1).seqNum;
185
- yield* Effect.promise(() => this.ctx.storage.put('currentHead', this.currentHead));
186
- yield* this.pushSemaphore.release(1);
187
- const connectedClients = this.ctx.getWebSockets();
188
- // console.debug(`Broadcasting push batch to ${this.subscribedWebSockets.size} clients`)
189
- if (connectedClients.length > 0) {
190
- // TODO refactor to batch api
191
- const pullRes = WSMessage.PullRes.make({
192
- batch: decodedMessage.batch.map((eventEncoded) => ({
193
- eventEncoded,
194
- metadata: Option.some({ createdAt }),
195
- })),
196
- remaining: 0,
197
- requestId: { context: 'push', requestId },
198
- });
199
- const pullResEnc = encodeOutgoingMessage(pullRes);
200
- // Only calling once for now.
201
- if (options?.onPullRes) {
202
- yield* Effect.tryAll(() => options.onPullRes(pullRes));
203
- }
204
- // NOTE we're also sending the pullRes to the pushing ws client as a confirmation
205
- for (const conn of connectedClients) {
206
- conn.send(pullResEnc);
207
- }
208
- }
209
- // Wait for the storage write to complete before finishing this request
210
- yield* storeFiber;
211
- break;
212
- }
213
- case 'WSMessage.AdminResetRoomReq': {
214
- if (decodedMessage.adminSecret !== this.env.ADMIN_SECRET) {
215
- ws.send(encodeOutgoingMessage(WSMessage.Error.make({ message: 'Invalid admin secret', requestId })));
216
- return;
217
- }
218
- yield* storage.resetStore;
219
- ws.send(encodeOutgoingMessage(WSMessage.AdminResetRoomRes.make({ requestId })));
220
- break;
221
- }
222
- case 'WSMessage.AdminInfoReq': {
223
- if (decodedMessage.adminSecret !== this.env.ADMIN_SECRET) {
224
- ws.send(encodeOutgoingMessage(WSMessage.Error.make({ message: 'Invalid admin secret', requestId })));
225
- return;
226
- }
227
- ws.send(encodeOutgoingMessage(WSMessage.AdminInfoRes.make({ requestId, info: { durableObjectId: this.ctx.id.toString() } })));
228
- break;
229
- }
230
- default: {
231
- console.error('unsupported message', decodedMessage);
232
- return shouldNeverHappen();
233
- }
234
- }
235
- }).pipe(Effect.withSpan(`@livestore/sync-cf:durable-object:webSocketMessage:${decodedMessage._tag}`, {
236
- attributes: { requestId },
237
- }), Effect.tapCauseLogPretty, Effect.tapErrorCause((cause) => Effect.sync(() => ws.send(encodeOutgoingMessage(WSMessage.Error.make({ message: cause.toString(), requestId }))))), Logger.withMinimumLogLevel(LogLevel.Debug), Effect.provide(Logger.prettyWithThread('durable-object')), Effect.runPromise);
238
- };
239
- webSocketClose = async (ws, code, _reason, _wasClean) => {
240
- // If the client closes the connection, the runtime will invoke the webSocketClose() handler.
241
- ws.close(code, 'Durable Object is closing WebSocket');
242
- };
243
- };
244
- };
245
- const makeStorage = (ctx, env, storeId) => {
246
- const dbName = `eventlog_${PERSISTENCE_FORMAT_VERSION}_${toValidTableName(storeId)}`;
247
- const execDb = (cb) => Effect.tryPromise({
248
- try: () => cb(env.DB),
249
- catch: (error) => new UnexpectedError({ cause: error, payload: { dbName } }),
250
- }).pipe(Effect.map((_) => _.results), Effect.withSpan('@livestore/sync-cf:durable-object:execDb'));
251
- // const getHead: Effect.Effect<EventSequenceNumber.GlobalEventSequenceNumber, UnexpectedError> = Effect.gen(
252
- // function* () {
253
- // const result = yield* execDb<{ seqNum: EventSequenceNumber.GlobalEventSequenceNumber }>((db) =>
254
- // db.prepare(`SELECT seqNum FROM ${dbName} ORDER BY seqNum DESC LIMIT 1`).all(),
255
- // )
256
- // return result[0]?.seqNum ?? EventSequenceNumber.ROOT.global
257
- // },
258
- // ).pipe(UnexpectedError.mapToUnexpectedError)
259
- const getEvents = (cursor) => Effect.gen(function* () {
260
- const whereClause = cursor === undefined ? '' : `WHERE seqNum > ${cursor}`;
261
- const sql = `SELECT * FROM ${dbName} ${whereClause} ORDER BY seqNum ASC`;
262
- // TODO handle case where `cursor` was not found
263
- const rawEvents = yield* execDb((db) => db.prepare(sql).all());
264
- const events = Schema.decodeUnknownSync(Schema.Array(eventlogTable.rowSchema))(rawEvents).map(({ createdAt, ...eventEncoded }) => ({
265
- eventEncoded,
266
- metadata: Option.some({ createdAt }),
267
- }));
268
- return events;
269
- }).pipe(UnexpectedError.mapToUnexpectedError);
270
- const appendEvents = (batch, createdAt) => Effect.gen(function* () {
271
- // If there are no events, do nothing.
272
- if (batch.length === 0)
273
- return;
274
- // CF D1 limits:
275
- // Maximum bound parameters per query 100, Maximum arguments per SQL function 32
276
- // Thus we need to split the batch into chunks of max (100/7=)14 events each.
277
- const CHUNK_SIZE = 14;
278
- for (let i = 0; i < batch.length; i += CHUNK_SIZE) {
279
- const chunk = batch.slice(i, i + CHUNK_SIZE);
280
- // Create a list of placeholders ("(?, ?, ?, ?, ?, ?, ?)"), corresponding to each event.
281
- const valuesPlaceholders = chunk.map(() => '(?, ?, ?, ?, ?, ?, ?)').join(', ');
282
- const sql = `INSERT INTO ${dbName} (seqNum, parentSeqNum, args, name, createdAt, clientId, sessionId) VALUES ${valuesPlaceholders}`;
283
- // Flatten the event properties into a parameters array.
284
- const params = chunk.flatMap((event) => [
285
- event.seqNum,
286
- event.parentSeqNum,
287
- event.args === undefined ? null : JSON.stringify(event.args),
288
- event.name,
289
- createdAt,
290
- event.clientId,
291
- event.sessionId,
292
- ]);
293
- yield* execDb((db) => db
294
- .prepare(sql)
295
- .bind(...params)
296
- .run());
297
- }
298
- }).pipe(UnexpectedError.mapToUnexpectedError);
299
- const resetStore = Effect.gen(function* () {
300
- yield* Effect.promise(() => ctx.storage.deleteAll());
301
- }).pipe(UnexpectedError.mapToUnexpectedError);
302
- return {
303
- dbName,
304
- // getHead,
305
- getEvents,
306
- appendEvents,
307
- resetStore,
308
- };
309
- };
310
- const getRequestSearchParams = (request) => {
311
- const url = new URL(request.url);
312
- const urlParams = UrlParams.fromInput(url.searchParams);
313
- const paramsResult = UrlParams.schemaStruct(SearchParamsSchema)(urlParams).pipe(Effect.runSync);
314
- return paramsResult;
315
- };
316
- const toValidTableName = (str) => str.replaceAll(/[^a-zA-Z0-9]/g, '_');
317
- //# sourceMappingURL=durable-object.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"durable-object.js","sourceRoot":"","sources":["../../src/cf-worker/durable-object.ts"],"names":[],"mappings":"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"}