@livestore/sync-cf 0.3.0-dev.4 → 0.3.0-dev.6
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/durable-object.d.ts +12 -15
- package/dist/cf-worker/durable-object.d.ts.map +1 -1
- package/dist/cf-worker/durable-object.js +22 -26
- package/dist/cf-worker/durable-object.js.map +1 -1
- package/dist/common/ws-message-types.d.ts +54 -207
- package/dist/common/ws-message-types.d.ts.map +1 -1
- package/dist/common/ws-message-types.js +3 -3
- package/dist/common/ws-message-types.js.map +1 -1
- package/package.json +11 -10
- package/src/cf-worker/durable-object.ts +27 -33
- package/src/common/ws-message-types.ts +3 -3
|
@@ -21,17 +21,24 @@ const decodeIncomingMessage = Schema.decodeUnknownEither(Schema.parseJson(WSMess
|
|
|
21
21
|
|
|
22
22
|
// NOTE actual table name is determined at runtime by `WebSocketServer.dbName`
|
|
23
23
|
export const mutationLogTable = DbSchema.table('__unused', {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
id: DbSchema.integer({ primaryKey: true, schema: EventId.GlobalEventId }),
|
|
25
|
+
parentId: DbSchema.integer({ schema: EventId.GlobalEventId }),
|
|
26
26
|
mutation: DbSchema.text({}),
|
|
27
27
|
args: DbSchema.text({ schema: Schema.parseJson(Schema.Any) }),
|
|
28
|
-
/** ISO date format */
|
|
28
|
+
/** ISO date format. Currently only used for debugging purposes. */
|
|
29
29
|
createdAt: DbSchema.text({}),
|
|
30
30
|
})
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Needs to be bumped when the storage format changes (e.g. mutationLogTable schema changes)
|
|
34
|
+
*
|
|
35
|
+
* Changing this version number will lead to a "soft reset".
|
|
36
|
+
*/
|
|
37
|
+
const PERSISTENCE_FORMAT_VERSION = 2
|
|
38
|
+
|
|
32
39
|
// Durable Object
|
|
33
40
|
export class WebSocketServer extends DurableObject<Env> {
|
|
34
|
-
dbName = `mutation_log_${this.ctx.id.toString()}`
|
|
41
|
+
dbName = `mutation_log_${PERSISTENCE_FORMAT_VERSION}_${this.ctx.id.toString()}`
|
|
35
42
|
storage = makeStorage(this.ctx, this.env, this.dbName)
|
|
36
43
|
|
|
37
44
|
constructor(ctx: DurableObjectState, env: Env) {
|
|
@@ -101,13 +108,13 @@ export class WebSocketServer extends DurableObject<Env> {
|
|
|
101
108
|
case 'WSMessage.PushReq': {
|
|
102
109
|
// TODO check whether we could use the Durable Object storage for this to speed up the lookup
|
|
103
110
|
const latestEvent = yield* Effect.promise(() => this.storage.getLatestEvent())
|
|
104
|
-
const expectedParentId = latestEvent?.id ?? EventId.ROOT
|
|
111
|
+
const expectedParentId = latestEvent?.id ?? EventId.ROOT.global
|
|
105
112
|
|
|
106
113
|
let i = 0
|
|
107
114
|
for (const mutationEventEncoded of decodedMessage.batch) {
|
|
108
|
-
if (mutationEventEncoded.parentId
|
|
115
|
+
if (mutationEventEncoded.parentId !== expectedParentId + i) {
|
|
109
116
|
const err = WSMessage.Error.make({
|
|
110
|
-
message: `Invalid parent id. Received ${mutationEventEncoded.parentId
|
|
117
|
+
message: `Invalid parent id. Received ${mutationEventEncoded.parentId} but expected ${expectedParentId}`,
|
|
111
118
|
requestId,
|
|
112
119
|
})
|
|
113
120
|
|
|
@@ -124,11 +131,7 @@ export class WebSocketServer extends DurableObject<Env> {
|
|
|
124
131
|
// NOTE we're currently not blocking on this to allow broadcasting right away
|
|
125
132
|
const storePromise = this.storage.appendEvent(mutationEventEncoded, createdAt)
|
|
126
133
|
|
|
127
|
-
ws.send(
|
|
128
|
-
encodeOutgoingMessage(
|
|
129
|
-
WSMessage.PushAck.make({ mutationId: mutationEventEncoded.id.global, requestId }),
|
|
130
|
-
),
|
|
131
|
-
)
|
|
134
|
+
ws.send(encodeOutgoingMessage(WSMessage.PushAck.make({ mutationId: mutationEventEncoded.id, requestId })))
|
|
132
135
|
|
|
133
136
|
// console.debug(`Broadcasting mutation event to ${this.subscribedWebSockets.size} clients`)
|
|
134
137
|
|
|
@@ -206,50 +209,41 @@ export class WebSocketServer extends DurableObject<Env> {
|
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
const makeStorage = (ctx: DurableObjectState, env: Env, dbName: string) => {
|
|
209
|
-
const getLatestEvent = async (): Promise<MutationEvent.
|
|
210
|
-
const rawEvents = await env.DB.prepare(`SELECT * FROM ${dbName} ORDER BY
|
|
212
|
+
const getLatestEvent = async (): Promise<MutationEvent.AnyEncodedGlobal | undefined> => {
|
|
213
|
+
const rawEvents = await env.DB.prepare(`SELECT * FROM ${dbName} ORDER BY id DESC LIMIT 1`).all()
|
|
211
214
|
if (rawEvents.error) {
|
|
212
215
|
throw new Error(rawEvents.error)
|
|
213
216
|
}
|
|
214
|
-
const events = Schema.decodeUnknownSync(Schema.Array(mutationLogTable.schema))(rawEvents.results)
|
|
215
|
-
|
|
216
|
-
// TODO remove local ids
|
|
217
|
-
id: { global: e.idGlobal, local: 0 },
|
|
218
|
-
parentId: { global: e.parentIdGlobal, local: 0 },
|
|
219
|
-
}))
|
|
217
|
+
const events = Schema.decodeUnknownSync(Schema.Array(mutationLogTable.schema))(rawEvents.results)
|
|
218
|
+
|
|
220
219
|
return events[0]
|
|
221
220
|
}
|
|
222
221
|
|
|
223
222
|
const getEvents = async (
|
|
224
223
|
cursor: number | undefined,
|
|
225
224
|
): Promise<
|
|
226
|
-
ReadonlyArray<{ mutationEventEncoded: MutationEvent.
|
|
225
|
+
ReadonlyArray<{ mutationEventEncoded: MutationEvent.AnyEncodedGlobal; metadata: Option.Option<SyncMetadata> }>
|
|
227
226
|
> => {
|
|
228
|
-
const whereClause = cursor === undefined ? '' : `WHERE
|
|
229
|
-
const sql = `SELECT * FROM ${dbName} ${whereClause} ORDER BY
|
|
227
|
+
const whereClause = cursor === undefined ? '' : `WHERE id > ${cursor}`
|
|
228
|
+
const sql = `SELECT * FROM ${dbName} ${whereClause} ORDER BY id ASC`
|
|
230
229
|
// TODO handle case where `cursor` was not found
|
|
231
230
|
const rawEvents = await env.DB.prepare(sql).all()
|
|
232
231
|
if (rawEvents.error) {
|
|
233
232
|
throw new Error(rawEvents.error)
|
|
234
233
|
}
|
|
235
234
|
const events = Schema.decodeUnknownSync(Schema.Array(mutationLogTable.schema))(rawEvents.results).map(
|
|
236
|
-
({ createdAt, ...
|
|
237
|
-
mutationEventEncoded
|
|
238
|
-
...e,
|
|
239
|
-
// TODO remove local ids
|
|
240
|
-
id: { global: e.idGlobal, local: 0 },
|
|
241
|
-
parentId: { global: e.parentIdGlobal, local: 0 },
|
|
242
|
-
},
|
|
235
|
+
({ createdAt, ...mutationEventEncoded }) => ({
|
|
236
|
+
mutationEventEncoded,
|
|
243
237
|
metadata: Option.some({ createdAt }),
|
|
244
238
|
}),
|
|
245
239
|
)
|
|
246
240
|
return events
|
|
247
241
|
}
|
|
248
242
|
|
|
249
|
-
const appendEvent = async (event: MutationEvent.
|
|
250
|
-
const sql = `INSERT INTO ${dbName} (
|
|
243
|
+
const appendEvent = async (event: MutationEvent.AnyEncodedGlobal, createdAt: string) => {
|
|
244
|
+
const sql = `INSERT INTO ${dbName} (id, parentId, args, mutation, createdAt) VALUES (?, ?, ?, ?, ?)`
|
|
251
245
|
await env.DB.prepare(sql)
|
|
252
|
-
.bind(event.id
|
|
246
|
+
.bind(event.id, event.parentId, JSON.stringify(event.args), event.mutation, createdAt)
|
|
253
247
|
.run()
|
|
254
248
|
}
|
|
255
249
|
|
|
@@ -20,7 +20,7 @@ export const PullRes = Schema.TaggedStruct('WSMessage.PullRes', {
|
|
|
20
20
|
requestId: Schema.String,
|
|
21
21
|
events: Schema.Array(
|
|
22
22
|
Schema.Struct({
|
|
23
|
-
mutationEventEncoded: MutationEvent.
|
|
23
|
+
mutationEventEncoded: MutationEvent.AnyEncodedGlobal,
|
|
24
24
|
metadata: Schema.Option(SyncMetadata),
|
|
25
25
|
}),
|
|
26
26
|
),
|
|
@@ -30,7 +30,7 @@ export const PullRes = Schema.TaggedStruct('WSMessage.PullRes', {
|
|
|
30
30
|
export type PullRes = typeof PullRes.Type
|
|
31
31
|
|
|
32
32
|
export const PushBroadcast = Schema.TaggedStruct('WSMessage.PushBroadcast', {
|
|
33
|
-
mutationEventEncoded: MutationEvent.
|
|
33
|
+
mutationEventEncoded: MutationEvent.AnyEncodedGlobal,
|
|
34
34
|
metadata: Schema.Option(SyncMetadata),
|
|
35
35
|
})
|
|
36
36
|
|
|
@@ -38,7 +38,7 @@ export type PushBroadcast = typeof PushBroadcast.Type
|
|
|
38
38
|
|
|
39
39
|
export const PushReq = Schema.TaggedStruct('WSMessage.PushReq', {
|
|
40
40
|
requestId: Schema.String,
|
|
41
|
-
batch: Schema.Array(MutationEvent.
|
|
41
|
+
batch: Schema.Array(MutationEvent.AnyEncodedGlobal),
|
|
42
42
|
})
|
|
43
43
|
|
|
44
44
|
export type PushReq = typeof PushReq.Type
|