@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.
Files changed (101) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
  3. package/dist/cf-worker/do/durable-object.js +24 -11
  4. package/dist/cf-worker/do/durable-object.js.map +1 -1
  5. package/dist/cf-worker/do/layer.d.ts +22 -18
  6. package/dist/cf-worker/do/layer.d.ts.map +1 -1
  7. package/dist/cf-worker/do/layer.js +43 -33
  8. package/dist/cf-worker/do/layer.js.map +1 -1
  9. package/dist/cf-worker/do/pull.d.ts +3 -3
  10. package/dist/cf-worker/do/pull.d.ts.map +1 -1
  11. package/dist/cf-worker/do/pull.js +17 -18
  12. package/dist/cf-worker/do/pull.js.map +1 -1
  13. package/dist/cf-worker/do/push.d.ts +16 -3
  14. package/dist/cf-worker/do/push.d.ts.map +1 -1
  15. package/dist/cf-worker/do/push.js +69 -49
  16. package/dist/cf-worker/do/push.js.map +1 -1
  17. package/dist/cf-worker/do/push.test.d.ts +2 -0
  18. package/dist/cf-worker/do/push.test.d.ts.map +1 -0
  19. package/dist/cf-worker/do/push.test.js +30 -0
  20. package/dist/cf-worker/do/push.test.js.map +1 -0
  21. package/dist/cf-worker/do/sqlite.d.ts +34 -46
  22. package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
  23. package/dist/cf-worker/do/sqlite.js +1 -1
  24. package/dist/cf-worker/do/sqlite.js.map +1 -1
  25. package/dist/cf-worker/do/sync-storage.d.ts +7 -6
  26. package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
  27. package/dist/cf-worker/do/sync-storage.js +26 -14
  28. package/dist/cf-worker/do/sync-storage.js.map +1 -1
  29. package/dist/cf-worker/do/transport/do-rpc-server.d.ts +2 -2
  30. package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
  31. package/dist/cf-worker/do/transport/do-rpc-server.js +21 -19
  32. package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
  33. package/dist/cf-worker/do/transport/http-rpc-server.d.ts +2 -2
  34. package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
  35. package/dist/cf-worker/do/transport/http-rpc-server.js +7 -7
  36. package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
  37. package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +2 -2
  38. package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
  39. package/dist/cf-worker/do/transport/ws-rpc-server.js +9 -9
  40. package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
  41. package/dist/cf-worker/shared.d.ts +22 -19
  42. package/dist/cf-worker/shared.d.ts.map +1 -1
  43. package/dist/cf-worker/shared.js +13 -11
  44. package/dist/cf-worker/shared.js.map +1 -1
  45. package/dist/cf-worker/worker.d.ts +6 -6
  46. package/dist/cf-worker/worker.d.ts.map +1 -1
  47. package/dist/cf-worker/worker.js +16 -14
  48. package/dist/cf-worker/worker.js.map +1 -1
  49. package/dist/client/transport/do-rpc-client.d.ts +13 -4
  50. package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
  51. package/dist/client/transport/do-rpc-client.js +55 -26
  52. package/dist/client/transport/do-rpc-client.js.map +1 -1
  53. package/dist/client/transport/http-rpc-client.d.ts +3 -3
  54. package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
  55. package/dist/client/transport/http-rpc-client.js +30 -21
  56. package/dist/client/transport/http-rpc-client.js.map +1 -1
  57. package/dist/client/transport/ws-rpc-client.d.ts +3 -3
  58. package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
  59. package/dist/client/transport/ws-rpc-client.js +20 -16
  60. package/dist/client/transport/ws-rpc-client.js.map +1 -1
  61. package/dist/common/do-rpc-schema.d.ts +38 -39
  62. package/dist/common/do-rpc-schema.d.ts.map +1 -1
  63. package/dist/common/do-rpc-schema.js +3 -3
  64. package/dist/common/do-rpc-schema.js.map +1 -1
  65. package/dist/common/http-rpc-schema.d.ts +36 -37
  66. package/dist/common/http-rpc-schema.d.ts.map +1 -1
  67. package/dist/common/http-rpc-schema.js +5 -5
  68. package/dist/common/http-rpc-schema.js.map +1 -1
  69. package/dist/common/mod.d.ts +4 -5
  70. package/dist/common/mod.d.ts.map +1 -1
  71. package/dist/common/mod.js +3 -4
  72. package/dist/common/mod.js.map +1 -1
  73. package/dist/common/sync-message-types.d.ts +116 -133
  74. package/dist/common/sync-message-types.d.ts.map +1 -1
  75. package/dist/common/sync-message-types.js +26 -14
  76. package/dist/common/sync-message-types.js.map +1 -1
  77. package/dist/common/ws-rpc-schema.d.ts +33 -34
  78. package/dist/common/ws-rpc-schema.d.ts.map +1 -1
  79. package/dist/common/ws-rpc-schema.js +4 -4
  80. package/dist/common/ws-rpc-schema.js.map +1 -1
  81. package/package.json +21 -37
  82. package/src/cf-worker/do/durable-object.ts +45 -36
  83. package/src/cf-worker/do/layer.ts +142 -99
  84. package/src/cf-worker/do/pull.ts +28 -28
  85. package/src/cf-worker/do/push.test.ts +40 -0
  86. package/src/cf-worker/do/push.ts +138 -115
  87. package/src/cf-worker/do/sqlite.ts +1 -1
  88. package/src/cf-worker/do/sync-storage.ts +34 -21
  89. package/src/cf-worker/do/transport/do-rpc-server.ts +23 -34
  90. package/src/cf-worker/do/transport/http-rpc-server.ts +7 -10
  91. package/src/cf-worker/do/transport/ws-rpc-server.ts +10 -10
  92. package/src/cf-worker/shared.ts +18 -13
  93. package/src/cf-worker/worker.ts +21 -22
  94. package/src/client/transport/do-rpc-client.ts +82 -40
  95. package/src/client/transport/http-rpc-client.ts +47 -37
  96. package/src/client/transport/ws-rpc-client.ts +29 -26
  97. package/src/common/do-rpc-schema.ts +3 -3
  98. package/src/common/http-rpc-schema.ts +5 -5
  99. package/src/common/mod.ts +3 -4
  100. package/src/common/sync-message-types.ts +16 -16
  101. package/src/common/ws-rpc-schema.ts +4 -4
@@ -1,9 +1,7 @@
1
1
  import { SyncBackend, UnknownError } from '@livestore/common'
2
- import type { EventSequenceNumber } from '@livestore/common/schema'
3
- import { splitChunkBySize } from '@livestore/common/sync'
4
- import { omit } from '@livestore/utils'
2
+ import type { EventSequenceNumber, LiveStoreEvent } from '@livestore/common/schema'
3
+ import { splitArrayBySize } from '@livestore/common/sync'
5
4
  import {
6
- Chunk,
7
5
  type Duration,
8
6
  Effect,
9
7
  HttpClient,
@@ -11,11 +9,14 @@ import {
11
9
  identity,
12
10
  Layer,
13
11
  Option,
12
+ ReadonlyArray as EffectArray,
14
13
  RpcClient,
15
14
  RpcSerialization,
16
15
  Schedule,
17
16
  Schema,
17
+ Semaphore,
18
18
  Stream,
19
+ Struct,
19
20
  SubscriptionRef,
20
21
  UrlParams,
21
22
  } from '@livestore/utils/effect'
@@ -25,6 +26,8 @@ import { SyncHttpRpc } from '../../common/http-rpc-schema.ts'
25
26
  import { SearchParamsSchema } from '../../common/mod.ts'
26
27
  import type { SyncMetadata } from '../../common/sync-message-types.ts'
27
28
 
29
+ type PushBatchItem = LiveStoreEvent.Global.Encoded
30
+
28
31
  export interface HttpSyncOptions {
29
32
  /**
30
33
  * URL of the sync backend
@@ -41,7 +44,7 @@ export interface HttpSyncOptions {
41
44
  * How often to poll for new events
42
45
  * @default 5 seconds
43
46
  */
44
- pollInterval?: Duration.DurationInput
47
+ pollInterval?: Duration.Input
45
48
  }
46
49
  ping?: {
47
50
  /**
@@ -52,12 +55,12 @@ export interface HttpSyncOptions {
52
55
  * How long to wait for a ping response before timing out
53
56
  * @default 10 seconds
54
57
  */
55
- requestTimeout?: Duration.DurationInput
58
+ requestTimeout?: Duration.Input
56
59
  /**
57
60
  * How often to send ping requests
58
61
  * @default 10 seconds
59
62
  */
60
- requestInterval?: Duration.DurationInput
63
+ requestInterval?: Duration.Input
61
64
  }
62
65
  }
63
66
 
@@ -73,7 +76,7 @@ export const makeHttpSync =
73
76
 
74
77
  const livePullInterval = options.livePull?.pollInterval ?? 5_000
75
78
 
76
- const urlParamsData = yield* Schema.encode(SearchParamsSchema)({
79
+ const urlParamsData = yield* Schema.encodeEffect(SearchParamsSchema)({
77
80
  storeId,
78
81
  payload,
79
82
  transport: 'http',
@@ -83,9 +86,10 @@ export const makeHttpSync =
83
86
 
84
87
  // Setup HTTP RPC Protocol
85
88
  const HttpProtocolLive = RpcClient.layerProtocolHttp({
86
- url: `${options.url}?${UrlParams.toString(urlParams)}`,
89
+ url: options.url,
87
90
  transformClient: HttpClient.mapRequest((request) =>
88
91
  request.pipe(
92
+ HttpClientRequest.appendUrlParams(urlParams),
89
93
  HttpClientRequest.setHeaders({
90
94
  ...options.headers,
91
95
  // Used in CF Worker to identify the store (additionally to storeId embedded in the RPC requests)
@@ -100,13 +104,13 @@ export const makeHttpSync =
100
104
  const pingTimeout = options.ping?.requestTimeout ?? 10_000
101
105
 
102
106
  const ping: SyncBackend.SyncBackend<SyncMetadata>['ping'] = Effect.gen(function* () {
103
- yield* rpcClient.SyncHttpRpc.Ping({ storeId, payload })
107
+ yield* rpcClient['SyncHttpRpc.Ping']({ storeId, payload })
104
108
 
105
109
  yield* SubscriptionRef.set(isConnected, true)
106
110
  }).pipe(
107
111
  UnknownError.mapToUnknownError,
108
112
  Effect.timeout(pingTimeout),
109
- Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)),
113
+ Effect.catchTag('TimeoutError', () => SubscriptionRef.set(isConnected, false)),
110
114
  )
111
115
 
112
116
  const pingInterval = options.ping?.requestInterval ?? 10_000
@@ -130,7 +134,7 @@ export const makeHttpSync =
130
134
  )
131
135
 
132
136
  const pull: SyncBackend.SyncBackend<SyncMetadata>['pull'] = (cursor, options) =>
133
- rpcClient.SyncHttpRpc.Pull({
137
+ rpcClient['SyncHttpRpc.Pull']({
134
138
  storeId,
135
139
  payload,
136
140
  cursor: mapCursor(cursor),
@@ -139,34 +143,40 @@ export const makeHttpSync =
139
143
  ? // Phase 2: Simulate `live` pull by polling for new events
140
144
  Stream.concatWithLastElement((lastElement) => {
141
145
  const initialPhase2Cursor = lastElement.pipe(
142
- Option.flatMap((_) => Option.fromNullable(_.batch.at(-1)?.eventEncoded.seqNum)),
146
+ Option.flatMap((_) => Option.fromNullishOr(_.batch.at(-1)?.eventEncoded.seqNum)),
143
147
  Option.map((eventSequenceNumber) => ({ eventSequenceNumber })),
144
148
  Option.orElse(() => cursor),
145
149
  mapCursor,
146
150
  )
147
151
 
148
- return Stream.unfoldChunkEffect(initialPhase2Cursor, (currentCursor) =>
152
+ return Stream.paginate(initialPhase2Cursor, (currentCursor) =>
149
153
  Effect.gen(function* () {
150
154
  yield* Effect.sleep(livePullInterval)
151
155
 
152
- const items = yield* rpcClient.SyncHttpRpc.Pull({ storeId, payload, cursor: currentCursor }).pipe(
153
- Stream.runCollect,
154
- )
156
+ const items = yield* rpcClient['SyncHttpRpc.Pull']({
157
+ storeId,
158
+ payload,
159
+ cursor: currentCursor,
160
+ }).pipe(Stream.runCollect)
155
161
 
156
- const nextCursor = Chunk.last(items).pipe(
157
- Option.flatMap((item) => Option.fromNullable(item.batch.at(-1)?.eventEncoded.seqNum)),
162
+ const nextCursor = EffectArray.last(items).pipe(
163
+ Option.flatMap((item) => Option.fromNullishOr(item.batch.at(-1)?.eventEncoded.seqNum)),
158
164
  Option.map((eventSequenceNumber) => ({ eventSequenceNumber })),
159
165
  Option.orElse(() => currentCursor),
160
166
  mapCursor,
161
167
  )
162
168
 
163
- return Option.some([items, nextCursor])
169
+ const page: readonly [typeof items, Option.Option<typeof currentCursor>] = [
170
+ items,
171
+ Option.some(nextCursor),
172
+ ]
173
+ return page
164
174
  }),
165
175
  )
166
176
  })
167
177
  : identity,
168
178
  Stream.tap((res) => backendIdHelper.lazySet(res.backendId)),
169
- Stream.map((res) => omit(res, ['backendId'])),
179
+ Stream.map((res) => Struct.omit(res, ['backendId'])),
170
180
  Stream.mapError((cause) =>
171
181
  cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
172
182
  ? cause
@@ -175,7 +185,7 @@ export const makeHttpSync =
175
185
  Stream.withSpan('http-sync-client:pull'),
176
186
  )
177
187
 
178
- const pushSemaphore = yield* Effect.makeSemaphore(1)
188
+ const pushSemaphore = yield* Semaphore.make(1)
179
189
 
180
190
  const push: SyncBackend.SyncBackend<SyncMetadata>['push'] = Effect.fn('http-sync-client:push')(
181
191
  function* (batch) {
@@ -184,23 +194,23 @@ export const makeHttpSync =
184
194
  }
185
195
 
186
196
  const backendId = backendIdHelper.get()
187
- const batchChunks = yield* Chunk.fromIterable(batch).pipe(
188
- splitChunkBySize({
189
- maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
190
- maxBytes: MAX_HTTP_REQUEST_BYTES,
191
- encode: (items) => ({
192
- batch: items,
193
- storeId,
194
- payload,
195
- backendId,
196
- }),
197
+ if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
198
+ return
199
+ }
200
+
201
+ const batchChunks = yield* splitArrayBySize({
202
+ maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
203
+ maxBytes: MAX_HTTP_REQUEST_BYTES,
204
+ encode: (items: ReadonlyArray<PushBatchItem>) => ({
205
+ batch: items,
206
+ storeId,
207
+ payload,
208
+ backendId,
197
209
  }),
198
- Effect.mapError((cause) => new UnknownError({ cause })),
199
- )
210
+ })(batch).pipe(Effect.mapError((cause) => new UnknownError({ cause })))
200
211
 
201
- for (const chunk of Chunk.toReadonlyArray(batchChunks)) {
202
- const chunkArray = Chunk.toReadonlyArray(chunk)
203
- yield* rpcClient.SyncHttpRpc.Push({ storeId, payload, batch: chunkArray, backendId })
212
+ for (const batchChunk of batchChunks) {
213
+ yield* rpcClient['SyncHttpRpc.Push']({ storeId, payload, batch: batchChunk, backendId })
204
214
  }
205
215
  },
206
216
  pushSemaphore.withPermits(1),
@@ -1,13 +1,12 @@
1
1
  import { IsOfflineError, SyncBackend, UnknownError } from '@livestore/common'
2
2
  import type { LiveStoreEvent } from '@livestore/common/schema'
3
- import { splitChunkBySize } from '@livestore/common/sync'
4
- import { omit } from '@livestore/utils'
3
+ import { splitArrayBySize } from '@livestore/common/sync'
5
4
  import {
6
- Chunk,
7
- type Duration,
5
+ Duration,
8
6
  Effect,
9
7
  Layer,
10
8
  Option,
9
+ ReadonlyArray as EffectArray,
11
10
  RpcClient,
12
11
  RpcSerialization,
13
12
  Schedule,
@@ -15,6 +14,7 @@ import {
15
14
  type Scope,
16
15
  Socket,
17
16
  Stream,
17
+ Struct,
18
18
  SubscriptionRef,
19
19
  UrlParams,
20
20
  } from '@livestore/utils/effect'
@@ -48,12 +48,12 @@ export interface WsSyncOptions {
48
48
  * How long to wait for a ping response before timing out
49
49
  * @default 10 seconds
50
50
  */
51
- requestTimeout?: Duration.DurationInput
51
+ requestTimeout?: Duration.Input
52
52
  /**
53
53
  * How often to send ping requests
54
54
  * @default 10 seconds
55
55
  */
56
- requestInterval?: Duration.DurationInput
56
+ requestInterval?: Duration.Input
57
57
  }
58
58
  }
59
59
 
@@ -70,7 +70,7 @@ export const makeWsSync =
70
70
  (options: WsSyncOptions): SyncBackend.SyncBackendConstructor<SyncMetadata> =>
71
71
  ({ storeId, payload }) =>
72
72
  Effect.gen(function* () {
73
- const urlParamsData = yield* Schema.encode(SearchParamsSchema)({
73
+ const urlParamsData = yield* Schema.encodeEffect(SearchParamsSchema)({
74
74
  storeId,
75
75
  payload,
76
76
  transport: 'ws',
@@ -89,7 +89,7 @@ export const makeWsSync =
89
89
  // }
90
90
  // TODO bring this back in a cross-platform way
91
91
  // if (navigator.onLine === false) {
92
- // yield* Effect.async((cb) => self.addEventListener('online', () => cb(Effect.void)))
92
+ // yield* Effect.callback((cb) => self.addEventListener('online', () => cb(Effect.void)))
93
93
  // }
94
94
 
95
95
  const pingInterval = options.ping?.requestInterval ?? 10_000
@@ -97,10 +97,10 @@ export const makeWsSync =
97
97
  const ProtocolLive = RpcClient.layerProtocolSocketWithIsConnected({
98
98
  isConnected,
99
99
  retryTransientErrors: Schedule.exponential('1 seconds').pipe(
100
- Schedule.union(Schedule.fixed('30 seconds')),
100
+ Schedule.modifyDelay(({ duration }) => Effect.succeed(Duration.min(duration, Duration.seconds(30)))),
101
101
  Schedule.jittered,
102
102
  ),
103
- pingSchedule: Schedule.once.pipe(Schedule.andThen(Schedule.fixed(pingInterval))),
103
+ pingSchedule: Schedule.recurs(1).pipe(Schedule.concat(Schedule.fixed(pingInterval))),
104
104
  url: wsUrl,
105
105
  }).pipe(
106
106
  Layer.provide(Socket.layerWebSocket(wsUrl)),
@@ -122,7 +122,7 @@ export const makeWsSync =
122
122
  yield* SubscriptionRef.set(isConnected, true)
123
123
  }).pipe(
124
124
  Effect.timeout(pingTimeout),
125
- Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)),
125
+ Effect.catchTag('TimeoutError', () => SubscriptionRef.set(isConnected, false)),
126
126
  UnknownError.mapToUnknownError,
127
127
  Effect.withSpan('ping'),
128
128
  )
@@ -133,7 +133,7 @@ export const makeWsSync =
133
133
  isConnected,
134
134
  connect: ping,
135
135
  pull: (cursor, options) =>
136
- rpcClient.SyncWsRpc.Pull({
136
+ rpcClient['SyncWsRpc.Pull']({
137
137
  storeId,
138
138
  payload,
139
139
  cursor: cursor.pipe(
@@ -145,7 +145,7 @@ export const makeWsSync =
145
145
  live: options?.live === true,
146
146
  }).pipe(
147
147
  Stream.tap((res) => backendIdHelper.lazySet(res.backendId)),
148
- Stream.map((res) => omit(res, ['backendId'])),
148
+ Stream.map((res) => Struct.omit(res, ['backendId'])),
149
149
  Stream.mapError((cause) =>
150
150
  cause._tag === 'RpcClientError' && Socket.isSocketError(cause.cause) === true
151
151
  ? new IsOfflineError({ cause: cause.cause })
@@ -166,24 +166,27 @@ export const makeWsSync =
166
166
  backendId: backendIdHelper.get(),
167
167
  })
168
168
 
169
- const chunksChunk = yield* Chunk.fromIterable(batch).pipe(
170
- splitChunkBySize({
171
- maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
172
- maxBytes: MAX_WS_MESSAGE_BYTES,
173
- encode: encodePayload,
174
- }),
175
- Effect.mapError((cause) => new UnknownError({ cause })),
176
- )
177
-
178
- for (const sub of chunksChunk) {
179
- yield* rpcClient.SyncWsRpc.Push({
169
+ if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
170
+ return
171
+ }
172
+
173
+ const batchChunks = yield* splitArrayBySize({
174
+ maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
175
+ maxBytes: MAX_WS_MESSAGE_BYTES,
176
+ encode: encodePayload,
177
+ })(batch).pipe(Effect.mapError((cause) => new UnknownError({ cause })))
178
+
179
+ for (const batchChunk of batchChunks) {
180
+ yield* rpcClient['SyncWsRpc.Push']({
180
181
  storeId,
181
182
  payload,
182
- batch: Chunk.toReadonlyArray(sub),
183
+ batch: batchChunk,
183
184
  backendId: backendIdHelper.get(),
184
185
  }).pipe(
185
186
  Effect.mapError((cause) =>
186
- cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
187
+ cause._tag === 'UnknownError' ||
188
+ cause._tag === 'ServerAheadError' ||
189
+ cause._tag === 'BackendIdMismatchError'
187
190
  ? cause
188
191
  : new UnknownError({ cause }),
189
192
  ),
@@ -11,7 +11,7 @@ const commonPayloadFields = {
11
11
  */
12
12
  storeId: Schema.String,
13
13
  /** Needed for various reasons (e.g. auth) */
14
- payload: Schema.optional(Schema.JsonValue),
14
+ payload: Schema.optional(Schema.Json),
15
15
  }
16
16
 
17
17
  export class SyncDoRpc extends RpcGroup.make(
@@ -35,7 +35,7 @@ export class SyncDoRpc extends RpcGroup.make(
35
35
  rpcRequestId: Schema.String,
36
36
  ...SyncMessage.PullResponse.fields,
37
37
  }),
38
- error: Schema.Union(UnknownError, BackendIdMismatchError),
38
+ error: Schema.Union([UnknownError, BackendIdMismatchError]),
39
39
  stream: true,
40
40
  }),
41
41
  Rpc.make('SyncDoRpc.Push', {
@@ -44,7 +44,7 @@ export class SyncDoRpc extends RpcGroup.make(
44
44
  ...commonPayloadFields,
45
45
  },
46
46
  success: SyncMessage.PushAck,
47
- error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
47
+ error: Schema.Union([UnknownError, ServerAheadError, BackendIdMismatchError]),
48
48
  }),
49
49
  Rpc.make('SyncDoRpc.Ping', {
50
50
  payload: {
@@ -14,26 +14,26 @@ export class SyncHttpRpc extends RpcGroup.make(
14
14
  Rpc.make('SyncHttpRpc.Pull', {
15
15
  payload: Schema.Struct({
16
16
  storeId: Schema.String,
17
- payload: Schema.optional(Schema.JsonValue),
17
+ payload: Schema.optional(Schema.Json),
18
18
  ...SyncMessage.PullRequest.fields,
19
19
  }),
20
20
  success: SyncMessage.PullResponse,
21
- error: Schema.Union(UnknownError, BackendIdMismatchError),
21
+ error: Schema.Union([UnknownError, BackendIdMismatchError]),
22
22
  stream: true,
23
23
  }),
24
24
  Rpc.make('SyncHttpRpc.Push', {
25
25
  payload: Schema.Struct({
26
26
  storeId: Schema.String,
27
- payload: Schema.optional(Schema.JsonValue),
27
+ payload: Schema.optional(Schema.Json),
28
28
  ...SyncMessage.PushRequest.fields,
29
29
  }),
30
30
  success: SyncMessage.PushAck,
31
- error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
31
+ error: Schema.Union([UnknownError, ServerAheadError, BackendIdMismatchError]),
32
32
  }),
33
33
  Rpc.make('SyncHttpRpc.Ping', {
34
34
  payload: Schema.Struct({
35
35
  storeId: Schema.String,
36
- payload: Schema.optional(Schema.JsonValue),
36
+ payload: Schema.optional(Schema.Json),
37
37
  }),
38
38
  success: SyncMessage.Pong,
39
39
  error: UnknownError,
package/src/common/mod.ts CHANGED
@@ -1,17 +1,16 @@
1
- import { OversizeChunkItemError, splitChunkBySize } from '@livestore/common/sync'
1
+ export { OversizeChunkItemError, splitArrayBySize } from '@livestore/common/sync'
2
2
  import { Schema } from '@livestore/utils/effect'
3
3
 
4
4
  export type { CfTypes } from '@livestore/common-cf'
5
5
  export * from './constants.ts'
6
6
  export { SyncHttpRpc } from './http-rpc-schema.ts'
7
7
  export * as SyncMessage from './sync-message-types.ts'
8
- export { OversizeChunkItemError, splitChunkBySize }
9
8
 
10
9
  export const SearchParamsSchema = Schema.Struct({
11
10
  storeId: Schema.String,
12
- payload: Schema.compose(Schema.StringFromUriComponent, Schema.parseJson(Schema.JsonValue)).pipe(Schema.UndefinedOr),
11
+ payload: Schema.optional(Schema.StringFromUriComponent.pipe(Schema.decodeTo(Schema.fromJsonString(Schema.Json)))),
13
12
  // NOTE `do-rpc` is handled differently
14
- transport: Schema.Literal('http', 'ws'),
13
+ transport: Schema.Literals(['http', 'ws']),
15
14
  })
16
15
 
17
16
  export type SearchParams = typeof SearchParamsSchema.Type
@@ -11,7 +11,7 @@ import { Schema } from '@livestore/utils/effect'
11
11
  export const SyncMetadata = Schema.TaggedStruct('SyncMessage.SyncMetadata', {
12
12
  /** ISO date format */
13
13
  createdAt: Schema.String,
14
- }).annotations({ title: '@livestore/sync-cf:SyncMetadata' })
14
+ }).annotate({ title: '@livestore/sync-cf:SyncMetadata' })
15
15
 
16
16
  export type SyncMetadata = typeof SyncMetadata.Type
17
17
 
@@ -23,7 +23,7 @@ export const PullRequest = Schema.Struct({
23
23
  eventSequenceNumber: EventSequenceNumber.Global.Schema,
24
24
  }),
25
25
  ),
26
- }).annotations({ title: '@livestore/sync-cf:PullRequest' })
26
+ }).annotate({ title: '@livestore/sync-cf:PullRequest' })
27
27
 
28
28
  export type PullRequest = typeof PullRequest.Type
29
29
 
@@ -36,7 +36,7 @@ export const PullResponse = Schema.Struct({
36
36
  ),
37
37
  pageInfo: SyncBackend.PullResPageInfo,
38
38
  backendId: BackendId,
39
- }).annotations({ title: '@livestore/sync-cf:PullResponse' })
39
+ }).annotate({ title: '@livestore/sync-cf:PullResponse' })
40
40
 
41
41
  export const emptyPullResponse = (backendId: string) =>
42
42
  PullResponse.make({
@@ -50,32 +50,32 @@ export type PullResponse = typeof PullResponse.Type
50
50
  export const PushRequest = Schema.Struct({
51
51
  batch: Schema.Array(LiveStoreEvent.Global.Encoded),
52
52
  backendId: Schema.Option(BackendId),
53
- }).annotations({ title: '@livestore/sync-cf:PushRequest' })
53
+ }).annotate({ title: '@livestore/sync-cf:PushRequest' })
54
54
 
55
55
  export type PushRequest = typeof PushRequest.Type
56
56
 
57
- export const PushAck = Schema.Struct({}).annotations({
57
+ export const PushAck = Schema.Struct({}).annotate({
58
58
  title: '@livestore/sync-cf:PushAck',
59
59
  })
60
60
 
61
61
  export type PushAck = typeof PushAck.Type
62
62
 
63
- export const Ping = Schema.TaggedStruct('SyncMessage.Ping', {}).annotations({ title: '@livestore/sync-cf:Ping' })
63
+ export const Ping = Schema.TaggedStruct('SyncMessage.Ping', {}).annotate({ title: '@livestore/sync-cf:Ping' })
64
64
 
65
65
  export type Ping = typeof Ping.Type
66
66
 
67
- export const Pong = Schema.TaggedStruct('SyncMessage.Pong', {}).annotations({ title: '@livestore/sync-cf:Pong' })
67
+ export const Pong = Schema.TaggedStruct('SyncMessage.Pong', {}).annotate({ title: '@livestore/sync-cf:Pong' })
68
68
 
69
69
  export type Pong = typeof Pong.Type
70
70
 
71
71
  // Admin operations
72
72
  export const AdminResetRoomRequest = Schema.TaggedStruct('SyncMessage.AdminResetRoomRequest', {
73
73
  adminSecret: Schema.String,
74
- }).annotations({ title: '@livestore/sync-cf:AdminResetRoomRequest' })
74
+ }).annotate({ title: '@livestore/sync-cf:AdminResetRoomRequest' })
75
75
 
76
76
  export type AdminResetRoomRequest = typeof AdminResetRoomRequest.Type
77
77
 
78
- export const AdminResetRoomResponse = Schema.TaggedStruct('SyncMessage.AdminResetRoomResponse', {}).annotations({
78
+ export const AdminResetRoomResponse = Schema.TaggedStruct('SyncMessage.AdminResetRoomResponse', {}).annotate({
79
79
  title: '@livestore/sync-cf:AdminResetRoomResponse',
80
80
  })
81
81
 
@@ -83,7 +83,7 @@ export type AdminResetRoomResponse = typeof AdminResetRoomResponse.Type
83
83
 
84
84
  export const AdminInfoRequest = Schema.TaggedStruct('SyncMessage.AdminInfoRequest', {
85
85
  adminSecret: Schema.String,
86
- }).annotations({ title: '@livestore/sync-cf:AdminInfoRequest' })
86
+ }).annotate({ title: '@livestore/sync-cf:AdminInfoRequest' })
87
87
 
88
88
  export type AdminInfoRequest = typeof AdminInfoRequest.Type
89
89
 
@@ -91,27 +91,27 @@ export const AdminInfoResponse = Schema.TaggedStruct('SyncMessage.AdminInfoRespo
91
91
  info: Schema.Struct({
92
92
  durableObjectId: Schema.String,
93
93
  }),
94
- }).annotations({ title: '@livestore/sync-cf:AdminInfoResponse' })
94
+ }).annotate({ title: '@livestore/sync-cf:AdminInfoResponse' })
95
95
 
96
96
  export type AdminInfoResponse = typeof AdminInfoResponse.Type
97
97
 
98
- export const BackendToClientMessage = Schema.Union(
98
+ export const BackendToClientMessage = Schema.Union([
99
99
  PullResponse,
100
100
  PushAck,
101
101
  Pong,
102
102
  AdminResetRoomResponse,
103
103
  AdminInfoResponse,
104
- )
104
+ ])
105
105
  export type BackendToClientMessage = typeof BackendToClientMessage.Type
106
106
 
107
- export const ClientToBackendMessage = Schema.Union(
107
+ export const ClientToBackendMessage = Schema.Union([
108
108
  PullRequest,
109
109
  PushRequest,
110
110
  Ping,
111
111
  AdminResetRoomRequest,
112
112
  AdminInfoRequest,
113
- )
113
+ ])
114
114
  export type ClientToBackendMessage = typeof ClientToBackendMessage.Type
115
115
 
116
- export const Message = Schema.Union(BackendToClientMessage, ClientToBackendMessage)
116
+ export const Message = Schema.Union([BackendToClientMessage, ClientToBackendMessage])
117
117
  export type Message = typeof Message.Type
@@ -14,23 +14,23 @@ export class SyncWsRpc extends RpcGroup.make(
14
14
  Rpc.make('SyncWsRpc.Pull', {
15
15
  payload: Schema.Struct({
16
16
  storeId: Schema.String,
17
- payload: Schema.optional(Schema.JsonValue),
17
+ payload: Schema.optional(Schema.Json),
18
18
  /** Whether to keep the pull stream alive and wait for more events */
19
19
  live: Schema.Boolean,
20
20
  ...SyncMessage.PullRequest.fields,
21
21
  }),
22
22
  success: SyncMessage.PullResponse,
23
- error: Schema.Union(UnknownError, BackendIdMismatchError),
23
+ error: Schema.Union([UnknownError, BackendIdMismatchError]),
24
24
  stream: true,
25
25
  }),
26
26
  Rpc.make('SyncWsRpc.Push', {
27
27
  payload: Schema.Struct({
28
28
  storeId: Schema.String,
29
- payload: Schema.optional(Schema.JsonValue),
29
+ payload: Schema.optional(Schema.Json),
30
30
  ...SyncMessage.PushRequest.fields,
31
31
  }),
32
32
  success: SyncMessage.PushAck,
33
- error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
33
+ error: Schema.Union([UnknownError, ServerAheadError, BackendIdMismatchError]),
34
34
  }),
35
35
  // Ping <> Pong is handled by DO WS auto-response
36
36
  // TODO add admin RPCs