@livestore/sync-cf 0.3.0-dev.15 → 0.3.0-dev.17

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 (36) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/cf-worker/durable-object.d.ts +3 -0
  3. package/dist/cf-worker/durable-object.d.ts.map +1 -1
  4. package/dist/cf-worker/durable-object.js +119 -93
  5. package/dist/cf-worker/durable-object.js.map +1 -1
  6. package/dist/common/ws-message-types.d.ts +13 -0
  7. package/dist/common/ws-message-types.d.ts.map +1 -1
  8. package/dist/common/ws-message-types.js +1 -0
  9. package/dist/common/ws-message-types.js.map +1 -1
  10. package/dist/sync-impl/ws-impl.d.ts.map +1 -1
  11. package/dist/sync-impl/ws-impl.js +50 -2
  12. package/dist/sync-impl/ws-impl.js.map +1 -1
  13. package/package.json +3 -3
  14. package/src/cf-worker/durable-object.ts +74 -38
  15. package/src/common/ws-message-types.ts +3 -0
  16. package/src/sync-impl/ws-impl.ts +56 -1
  17. package/dist/cf-worker/index.d.ts +0 -3
  18. package/dist/cf-worker/index.d.ts.map +0 -1
  19. package/dist/cf-worker/index.js +0 -33
  20. package/dist/cf-worker/index.js.map +0 -1
  21. package/dist/cf-worker/make-worker.d.ts +0 -6
  22. package/dist/cf-worker/make-worker.d.ts.map +0 -1
  23. package/dist/cf-worker/make-worker.js +0 -31
  24. package/dist/cf-worker/make-worker.js.map +0 -1
  25. package/dist/cf-worker/types.d.ts +0 -2
  26. package/dist/cf-worker/types.d.ts.map +0 -1
  27. package/dist/cf-worker/types.js +0 -2
  28. package/dist/cf-worker/types.js.map +0 -1
  29. package/dist/common/index.d.ts +0 -2
  30. package/dist/common/index.d.ts.map +0 -1
  31. package/dist/common/index.js +0 -2
  32. package/dist/common/index.js.map +0 -1
  33. package/dist/sync-impl/index.d.ts +0 -2
  34. package/dist/sync-impl/index.d.ts.map +0 -1
  35. package/dist/sync-impl/index.js +0 -2
  36. package/dist/sync-impl/index.js.map +0 -1
@@ -36,6 +36,8 @@ const WebSocketAttachmentSchema = Schema.parseJson(
36
36
  }),
37
37
  )
38
38
 
39
+ export const PULL_CHUNK_SIZE = 100
40
+
39
41
  /**
40
42
  * Needs to be bumped when the storage format changes (e.g. mutationLogTable schema changes)
41
43
  *
@@ -45,7 +47,9 @@ export const PERSISTENCE_FORMAT_VERSION = 3
45
47
 
46
48
  export type MakeDurableObjectClassOptions = {
47
49
  onPush?: (message: WSMessage.PushReq) => Effect.Effect<void> | Promise<void>
50
+ onPushRes?: (message: WSMessage.PushAck | WSMessage.Error) => Effect.Effect<void> | Promise<void>
48
51
  onPull?: (message: WSMessage.PullReq) => Effect.Effect<void> | Promise<void>
52
+ onPullRes?: (message: WSMessage.PullRes | WSMessage.Error) => Effect.Effect<void> | Promise<void>
49
53
  }
50
54
 
51
55
  export type MakeDurableObjectClass = (options?: MakeDurableObjectClassOptions) => {
@@ -54,6 +58,9 @@ export type MakeDurableObjectClass = (options?: MakeDurableObjectClassOptions) =
54
58
 
55
59
  export const makeDurableObject: MakeDurableObjectClass = (options) => {
56
60
  return class WebSocketServerBase extends DurableObject<Env> {
61
+ /** Needed to prevent concurrent pushes */
62
+ private pushSemaphore = Effect.makeSemaphore(1).pipe(Effect.runSync)
63
+
57
64
  constructor(ctx: DurableObjectState, env: Env) {
58
65
  super(ctx, env)
59
66
  }
@@ -88,21 +95,21 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
88
95
  })
89
96
  }).pipe(Effect.tapCauseLogPretty, Effect.runPromise)
90
97
 
91
- webSocketMessage = (ws: WebSocketClient, message: ArrayBuffer | string) =>
92
- Effect.gen(this, function* () {
93
- const decodedMessageRes = decodeIncomingMessage(message)
98
+ webSocketMessage = (ws: WebSocketClient, message: ArrayBuffer | string) => {
99
+ const decodedMessageRes = decodeIncomingMessage(message)
94
100
 
95
- if (decodedMessageRes._tag === 'Left') {
96
- console.error('Invalid message received', decodedMessageRes.left)
97
- return
98
- }
101
+ if (decodedMessageRes._tag === 'Left') {
102
+ console.error('Invalid message received', decodedMessageRes.left)
103
+ return
104
+ }
105
+
106
+ const decodedMessage = decodedMessageRes.right
107
+ const requestId = decodedMessage.requestId
99
108
 
109
+ return Effect.gen(this, function* () {
100
110
  const { storeId } = yield* Schema.decode(WebSocketAttachmentSchema)(ws.deserializeAttachment())
101
111
  const storage = makeStorage(this.ctx, this.env, storeId)
102
112
 
103
- const decodedMessage = decodedMessageRes.right
104
- const requestId = decodedMessage.requestId
105
-
106
113
  try {
107
114
  switch (decodedMessage._tag) {
108
115
  // TODO allow pulling concurrently to not block incoming push requests
@@ -111,8 +118,15 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
111
118
  yield* Effect.tryAll(() => options.onPull!(decodedMessage))
112
119
  }
113
120
 
121
+ const respond = (message: WSMessage.PullRes) =>
122
+ Effect.gen(function* () {
123
+ if (options?.onPullRes) {
124
+ yield* Effect.tryAll(() => options.onPullRes!(message))
125
+ }
126
+ ws.send(encodeOutgoingMessage(message))
127
+ })
128
+
114
129
  const cursor = decodedMessage.cursor
115
- const CHUNK_SIZE = 100
116
130
 
117
131
  // TODO use streaming
118
132
  const remainingEvents = yield* storage.getEvents(cursor)
@@ -121,32 +135,41 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
121
135
  const batches =
122
136
  remainingEvents.length === 0
123
137
  ? [[]]
124
- : Array.from({ length: Math.ceil(remainingEvents.length / CHUNK_SIZE) }, (_, i) =>
125
- remainingEvents.slice(i * CHUNK_SIZE, (i + 1) * CHUNK_SIZE),
138
+ : Array.from({ length: Math.ceil(remainingEvents.length / PULL_CHUNK_SIZE) }, (_, i) =>
139
+ remainingEvents.slice(i * PULL_CHUNK_SIZE, (i + 1) * PULL_CHUNK_SIZE),
126
140
  )
127
141
 
128
142
  for (const [index, batch] of batches.entries()) {
129
- const remaining = Math.max(0, remainingEvents.length - (index + 1) * CHUNK_SIZE)
130
- ws.send(encodeOutgoingMessage(WSMessage.PullRes.make({ batch, remaining })))
143
+ const remaining = Math.max(0, remainingEvents.length - (index + 1) * PULL_CHUNK_SIZE)
144
+ yield* respond(WSMessage.PullRes.make({ batch, remaining, requestId: { context: 'pull', requestId } }))
131
145
  }
132
146
 
133
147
  break
134
148
  }
135
149
  case 'WSMessage.PushReq': {
136
- if (options?.onPush) {
137
- yield* Effect.tryAll(() => options.onPush!(decodedMessage))
138
- }
150
+ const respond = (message: WSMessage.PushAck | WSMessage.Error) =>
151
+ Effect.gen(function* () {
152
+ if (options?.onPushRes) {
153
+ yield* Effect.tryAll(() => options.onPushRes!(message))
154
+ }
155
+ ws.send(encodeOutgoingMessage(message))
156
+ })
139
157
 
140
158
  if (decodedMessage.batch.length === 0) {
141
- ws.send(encodeOutgoingMessage(WSMessage.PushAck.make({ requestId })))
159
+ yield* respond(WSMessage.PushAck.make({ requestId }))
142
160
  return
143
161
  }
144
162
 
163
+ yield* this.pushSemaphore.take(1)
164
+
165
+ if (options?.onPush) {
166
+ yield* Effect.tryAll(() => options.onPush!(decodedMessage))
167
+ }
168
+
145
169
  // TODO check whether we could use the Durable Object storage for this to speed up the lookup
146
170
  const expectedParentId = yield* storage.getHead
147
171
 
148
172
  // TODO handle clientId unique conflict
149
-
150
173
  // Validate the batch
151
174
  const firstEvent = decodedMessage.batch[0]!
152
175
  if (firstEvent.parentId !== expectedParentId) {
@@ -157,11 +180,14 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
157
180
 
158
181
  yield* Effect.logError(err)
159
182
 
160
- ws.send(encodeOutgoingMessage(err))
183
+ yield* respond(err)
184
+ yield* this.pushSemaphore.release(1)
161
185
  return
162
186
  }
163
187
 
164
- ws.send(encodeOutgoingMessage(WSMessage.PushAck.make({ requestId })))
188
+ yield* respond(WSMessage.PushAck.make({ requestId }))
189
+
190
+ yield* this.pushSemaphore.release(1)
165
191
 
166
192
  const createdAt = new Date().toISOString()
167
193
 
@@ -172,22 +198,26 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
172
198
  const connectedClients = this.ctx.getWebSockets()
173
199
 
174
200
  // console.debug(`Broadcasting push batch to ${this.subscribedWebSockets.size} clients`)
175
-
176
201
  if (connectedClients.length > 0) {
177
- const pullRes = encodeOutgoingMessage(
178
- // TODO refactor to batch api
179
- WSMessage.PullRes.make({
180
- batch: decodedMessage.batch.map((mutationEventEncoded) => ({
181
- mutationEventEncoded,
182
- metadata: Option.some({ createdAt }),
183
- })),
184
- remaining: 0,
185
- }),
186
- )
202
+ // TODO refactor to batch api
203
+ const pullRes = WSMessage.PullRes.make({
204
+ batch: decodedMessage.batch.map((mutationEventEncoded) => ({
205
+ mutationEventEncoded,
206
+ metadata: Option.some({ createdAt }),
207
+ })),
208
+ remaining: 0,
209
+ requestId: { context: 'push', requestId },
210
+ })
211
+ const pullResEnc = encodeOutgoingMessage(pullRes)
212
+
213
+ // Only calling once for now.
214
+ if (options?.onPullRes) {
215
+ yield* Effect.tryAll(() => options.onPullRes!(pullRes))
216
+ }
187
217
 
188
218
  // NOTE we're also sending the pullRes to the pushing ws client as a confirmation
189
219
  for (const conn of connectedClients) {
190
- conn.send(pullRes)
220
+ conn.send(pullResEnc)
191
221
  }
192
222
  }
193
223
 
@@ -230,12 +260,15 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
230
260
  ws.send(encodeOutgoingMessage(WSMessage.Error.make({ message: error.message, requestId })))
231
261
  }
232
262
  }).pipe(
233
- Effect.withSpan('@livestore/sync-cf:durable-object:webSocketMessage'),
263
+ Effect.withSpan(`@livestore/sync-cf:durable-object:webSocketMessage:${decodedMessage._tag}`, {
264
+ attributes: { requestId },
265
+ }),
234
266
  Effect.tapCauseLogPretty,
235
267
  Logger.withMinimumLogLevel(LogLevel.Debug),
236
268
  Effect.provide(Logger.pretty),
237
269
  Effect.runPromise,
238
270
  )
271
+ }
239
272
 
240
273
  webSocketClose = async (ws: WebSocketClient, code: number, _reason: string, _wasClean: boolean) => {
241
274
  // If the client closes the connection, the runtime will invoke the webSocketClose() handler.
@@ -267,7 +300,10 @@ const makeStorage = (ctx: DurableObjectState, env: Env, storeId: string): SyncSt
267
300
  Effect.tryPromise({
268
301
  try: () => cb(env.DB),
269
302
  catch: (error) => new UnexpectedError({ cause: error, payload: { dbName } }),
270
- }).pipe(Effect.map((_) => _.results))
303
+ }).pipe(
304
+ Effect.map((_) => _.results),
305
+ Effect.withSpan('@livestore/sync-cf:durable-object:execDb'),
306
+ )
271
307
 
272
308
  const getHead: Effect.Effect<EventId.GlobalEventId, UnexpectedError> = Effect.gen(function* () {
273
309
  const result = yield* execDb<{ id: EventId.GlobalEventId }>((db) =>
@@ -295,7 +331,7 @@ const makeStorage = (ctx: DurableObjectState, env: Env, storeId: string): SyncSt
295
331
  }),
296
332
  )
297
333
  return events
298
- })
334
+ }).pipe(UnexpectedError.mapToUnexpectedError)
299
335
 
300
336
  const appendEvents: SyncStorage['appendEvents'] = (batch, createdAt) =>
301
337
  Effect.gen(function* () {
@@ -330,7 +366,7 @@ const makeStorage = (ctx: DurableObjectState, env: Env, storeId: string): SyncSt
330
366
  .run(),
331
367
  )
332
368
  }
333
- })
369
+ }).pipe(UnexpectedError.mapToUnexpectedError)
334
370
 
335
371
  const resetStore = Effect.gen(function* () {
336
372
  yield* Effect.promise(() => ctx.storage.deleteAll())
@@ -23,6 +23,7 @@ export const PullRes = Schema.TaggedStruct('WSMessage.PullRes', {
23
23
  metadata: Schema.Option(SyncMetadata),
24
24
  }),
25
25
  ),
26
+ requestId: Schema.Struct({ context: Schema.Literal('pull', 'push'), requestId: Schema.String }),
26
27
  remaining: Schema.Number,
27
28
  })
28
29
 
@@ -46,6 +47,8 @@ export const Error = Schema.TaggedStruct('WSMessage.Error', {
46
47
  message: Schema.String,
47
48
  })
48
49
 
50
+ export type Error = typeof Error.Type
51
+
49
52
  export const Ping = Schema.TaggedStruct('WSMessage.Ping', {
50
53
  requestId: Schema.Literal('ping'),
51
54
  })
@@ -2,7 +2,8 @@
2
2
 
3
3
  import type { SyncBackend } from '@livestore/common'
4
4
  import { InvalidPullError, InvalidPushError } from '@livestore/common'
5
- import { LS_DEV } from '@livestore/utils'
5
+ import { EventId } from '@livestore/common/schema'
6
+ import { LS_DEV, shouldNeverHappen } from '@livestore/utils'
6
7
  import type { Scope } from '@livestore/utils/effect'
7
8
  import {
8
9
  Deferred,
@@ -33,10 +34,29 @@ export const makeWsSync = (options: WsSyncOptions): Effect.Effect<SyncBackend<Sy
33
34
 
34
35
  const { isConnected, incomingMessages, send } = yield* connect(wsUrl)
35
36
 
37
+ /**
38
+ * We need to account for the scenario where push-caused PullRes message arrive before the pull-caused PullRes message.
39
+ * i.e. a scenario where the WS connection is created but before the server processed the initial pull, a push from
40
+ * another client triggers a PullRes message sent to this client which we need to stash until our pull-caused
41
+ * PullRes message arrives at which point we can combine the stashed events with the pull-caused events and continue.
42
+ */
43
+ const stashedPullBatch: WSMessage.PullRes['batch'][number][] = []
44
+
45
+ // We currently only support one pull stream for a sync backend.
46
+ let pullStarted = false
47
+
36
48
  const api = {
37
49
  isConnected,
38
50
  pull: (args) =>
39
51
  Effect.gen(function* () {
52
+ if (pullStarted) {
53
+ return shouldNeverHappen(`Pull already started for this sync backend.`)
54
+ }
55
+
56
+ pullStarted = true
57
+
58
+ let pullResponseReceived = false
59
+
40
60
  const requestId = nanoid()
41
61
  const cursor = Option.getOrUndefined(args)?.cursor.global
42
62
 
@@ -48,6 +68,41 @@ export const makeWsSync = (options: WsSyncOptions): Effect.Effect<SyncBackend<Sy
48
68
  ? new InvalidPullError({ message: _.message })
49
69
  : Effect.void,
50
70
  ),
71
+ Stream.filterMap((msg) => {
72
+ if (msg._tag === 'WSMessage.PullRes') {
73
+ if (msg.requestId.context === 'pull') {
74
+ if (msg.requestId.requestId === requestId) {
75
+ pullResponseReceived = true
76
+
77
+ if (stashedPullBatch.length > 0 && msg.remaining === 0) {
78
+ const pullResHead = msg.batch.at(-1)?.mutationEventEncoded.id ?? EventId.ROOT.global
79
+ // Index where stashed events are greater than pullResHead
80
+ const newPartialBatchIndex = stashedPullBatch.findIndex(
81
+ (batchItem) => batchItem.mutationEventEncoded.id > pullResHead,
82
+ )
83
+ const batchWithNewStashedEvents =
84
+ newPartialBatchIndex === -1 ? [] : stashedPullBatch.slice(newPartialBatchIndex)
85
+ const combinedBatch = [...msg.batch, ...batchWithNewStashedEvents]
86
+ return Option.some({ ...msg, batch: combinedBatch, remaining: 0 })
87
+ } else {
88
+ return Option.some(msg)
89
+ }
90
+ } else {
91
+ // Ignore
92
+ return Option.none()
93
+ }
94
+ } else {
95
+ if (pullResponseReceived) {
96
+ return Option.some(msg)
97
+ } else {
98
+ stashedPullBatch.push(...msg.batch)
99
+ return Option.none()
100
+ }
101
+ }
102
+ }
103
+
104
+ return Option.none()
105
+ }),
51
106
  // This call is mostly here to for type narrowing
52
107
  Stream.filter(Schema.is(WSMessage.PullRes)),
53
108
  )
@@ -1,3 +0,0 @@
1
- /// <reference no-default-lib="true"/>
2
- export {};
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cf-worker/index.ts"],"names":[],"mappings":""}
@@ -1,33 +0,0 @@
1
- /// <reference no-default-lib="true"/>
2
- /// <reference lib="esnext" />
3
- export {};
4
- // export * from './durable-object.js'
5
- // export default {
6
- // fetch: async (request: Request, env: Env, _ctx: ExecutionContext): Promise<Response> => {
7
- // const url = new URL(request.url)
8
- // const searchParams = url.searchParams
9
- // const roomId = searchParams.get('room')
10
- // if (roomId === null) {
11
- // return new Response('Room ID is required', { status: 400 })
12
- // }
13
- // // This example will refer to the same Durable Object instance,
14
- // // since the name "foo" is hardcoded.
15
- // const id = env.WEBSOCKET_SERVER.idFromName(roomId)
16
- // const durableObject = env.WEBSOCKET_SERVER.get(id)
17
- // if (url.pathname.endsWith('/websocket')) {
18
- // const upgradeHeader = request.headers.get('Upgrade')
19
- // if (!upgradeHeader || upgradeHeader !== 'websocket') {
20
- // return new Response('Durable Object expected Upgrade: websocket', { status: 426 })
21
- // }
22
- // return durableObject.fetch(request)
23
- // }
24
- // return new Response(null, {
25
- // status: 400,
26
- // statusText: 'Bad Request',
27
- // headers: {
28
- // 'Content-Type': 'text/plain',
29
- // },
30
- // })
31
- // },
32
- // }
33
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cf-worker/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,8BAA8B;;AAI9B,sCAAsC;AAEtC,mBAAmB;AACnB,8FAA8F;AAC9F,uCAAuC;AACvC,4CAA4C;AAC5C,8CAA8C;AAE9C,6BAA6B;AAC7B,oEAAoE;AACpE,QAAQ;AAER,sEAAsE;AACtE,4CAA4C;AAC5C,yDAAyD;AACzD,yDAAyD;AAEzD,iDAAiD;AACjD,6DAA6D;AAC7D,+DAA+D;AAC/D,6FAA6F;AAC7F,UAAU;AAEV,4CAA4C;AAC5C,QAAQ;AAER,kCAAkC;AAClC,qBAAqB;AACrB,mCAAmC;AACnC,mBAAmB;AACnB,wCAAwC;AACxC,WAAW;AACX,SAAS;AACT,OAAO;AACP,IAAI"}
@@ -1,6 +0,0 @@
1
- import type { Env } from './durable-object.js';
2
- export type CFWorker = {
3
- fetch: (request: Request, env: Env, ctx: ExecutionContext) => Promise<Response>;
4
- };
5
- export declare const makeWorker: () => CFWorker;
6
- //# sourceMappingURL=make-worker.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"make-worker.d.ts","sourceRoot":"","sources":["../../src/cf-worker/make-worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AAE9C,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CAChF,CAAA;AAED,eAAO,MAAM,UAAU,QAAO,QAkC7B,CAAA"}
@@ -1,31 +0,0 @@
1
- export const makeWorker = () => {
2
- return {
3
- fetch: async (request, env, _ctx) => {
4
- const url = new URL(request.url);
5
- const searchParams = url.searchParams;
6
- const roomId = searchParams.get('room');
7
- if (roomId === null) {
8
- return new Response('Room ID is required', { status: 400 });
9
- }
10
- // This example will refer to the same Durable Object instance,
11
- // since the name "foo" is hardcoded.
12
- const id = env.WEBSOCKET_SERVER.idFromName(roomId);
13
- const durableObject = env.WEBSOCKET_SERVER.get(id);
14
- if (url.pathname.endsWith('/websocket')) {
15
- const upgradeHeader = request.headers.get('Upgrade');
16
- if (!upgradeHeader || upgradeHeader !== 'websocket') {
17
- return new Response('Durable Object expected Upgrade: websocket', { status: 426 });
18
- }
19
- return durableObject.fetch(request);
20
- }
21
- return new Response(null, {
22
- status: 400,
23
- statusText: 'Bad Request',
24
- headers: {
25
- 'Content-Type': 'text/plain',
26
- },
27
- });
28
- },
29
- };
30
- };
31
- //# sourceMappingURL=make-worker.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"make-worker.js","sourceRoot":"","sources":["../../src/cf-worker/make-worker.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,UAAU,GAAG,GAAa,EAAE;IACvC,OAAO;QACL,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YAClC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAChC,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,CAAA;YACrC,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;YAEvC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,OAAO,IAAI,QAAQ,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;YAC7D,CAAC;YAED,+DAA+D;YAC/D,qCAAqC;YACrC,MAAM,EAAE,GAAG,GAAG,CAAC,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;YAClD,MAAM,aAAa,GAAG,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAElD,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBACxC,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;gBACpD,IAAI,CAAC,aAAa,IAAI,aAAa,KAAK,WAAW,EAAE,CAAC;oBACpD,OAAO,IAAI,QAAQ,CAAC,4CAA4C,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;gBACpF,CAAC;gBAED,OAAO,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACrC,CAAC;YAED,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,GAAG;gBACX,UAAU,EAAE,aAAa;gBACzB,OAAO,EAAE;oBACP,cAAc,EAAE,YAAY;iBAC7B;aACF,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC,CAAA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cf-worker/types.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cf-worker/types.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- export * as WSMessage from './ws-message-types.js';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAA"}
@@ -1,2 +0,0 @@
1
- export * as WSMessage from './ws-message-types.js';
2
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAA"}
@@ -1,2 +0,0 @@
1
- export * from './ws-impl.js';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync-impl/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}
@@ -1,2 +0,0 @@
1
- export * from './ws-impl.js';
2
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync-impl/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA"}