@livestore/sync-cf 0.4.0-dev.8 → 0.4.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/README.md +7 -8
- package/dist/.tsbuildinfo +1 -1
- package/dist/cf-worker/do/durable-object.d.ts +1 -1
- package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
- package/dist/cf-worker/do/durable-object.js +15 -14
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +6 -6
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +32 -9
- package/dist/cf-worker/do/layer.js.map +1 -1
- package/dist/cf-worker/do/pull.d.ts +8 -3
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +22 -10
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +5 -4
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +80 -41
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/sqlite.d.ts +10 -1
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js +13 -4
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +14 -9
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +92 -18
- package/dist/cf-worker/do/sync-storage.js.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts +2 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.js +13 -7
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +3 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.js +24 -15
- 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 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.js +30 -8
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +123 -30
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +50 -6
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +64 -71
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +70 -48
- package/dist/cf-worker/worker.js.map +1 -1
- package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/do-rpc-client.js +27 -10
- package/dist/client/transport/do-rpc-client.js.map +1 -1
- package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/http-rpc-client.js +29 -9
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts +2 -1
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +31 -17
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/constants.d.ts +7 -0
- package/dist/common/constants.d.ts.map +1 -0
- package/dist/common/constants.js +17 -0
- package/dist/common/constants.js.map +1 -0
- package/dist/common/do-rpc-schema.d.ts +6 -6
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +4 -4
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +4 -4
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +4 -4
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/mod.d.ts +4 -1
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +4 -1
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +2 -2
- package/dist/common/sync-message-types.js +3 -3
- package/dist/common/sync-message-types.js.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +3 -3
- package/dist/common/ws-rpc-schema.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.js +3 -3
- package/dist/common/ws-rpc-schema.js.map +1 -1
- package/package.json +72 -14
- package/src/cf-worker/do/durable-object.ts +23 -18
- package/src/cf-worker/do/layer.ts +35 -13
- package/src/cf-worker/do/pull.ts +43 -14
- package/src/cf-worker/do/push.ts +107 -46
- package/src/cf-worker/do/sqlite.ts +14 -4
- package/src/cf-worker/do/sync-storage.ts +151 -31
- package/src/cf-worker/do/transport/do-rpc-server.ts +22 -9
- package/src/cf-worker/do/transport/http-rpc-server.ts +33 -13
- package/src/cf-worker/do/transport/ws-rpc-server.ts +40 -12
- package/src/cf-worker/shared.ts +149 -25
- package/src/cf-worker/worker.ts +138 -108
- package/src/client/transport/do-rpc-client.ts +41 -17
- package/src/client/transport/http-rpc-client.ts +43 -17
- package/src/client/transport/ws-rpc-client.ts +42 -19
- package/src/common/constants.ts +18 -0
- package/src/common/do-rpc-schema.ts +5 -4
- package/src/common/http-rpc-schema.ts +5 -4
- package/src/common/mod.ts +4 -2
- package/src/common/sync-message-types.ts +3 -3
- package/src/common/ws-rpc-schema.ts +4 -3
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyncBackend, UnknownError } from '@livestore/common'
|
|
2
2
|
import type { EventSequenceNumber } from '@livestore/common/schema'
|
|
3
|
+
import { splitChunkBySize } from '@livestore/common/sync'
|
|
3
4
|
import { omit } from '@livestore/utils'
|
|
4
5
|
import {
|
|
5
6
|
Chunk,
|
|
@@ -18,6 +19,8 @@ import {
|
|
|
18
19
|
SubscriptionRef,
|
|
19
20
|
UrlParams,
|
|
20
21
|
} from '@livestore/utils/effect'
|
|
22
|
+
|
|
23
|
+
import { MAX_HTTP_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from '../../common/constants.ts'
|
|
21
24
|
import { SyncHttpRpc } from '../../common/http-rpc-schema.ts'
|
|
22
25
|
import { SearchParamsSchema } from '../../common/mod.ts'
|
|
23
26
|
import type { SyncMetadata } from '../../common/sync-message-types.ts'
|
|
@@ -74,7 +77,7 @@ export const makeHttpSync =
|
|
|
74
77
|
storeId,
|
|
75
78
|
payload,
|
|
76
79
|
transport: 'http',
|
|
77
|
-
}).pipe(
|
|
80
|
+
}).pipe(UnknownError.mapToUnknownError)
|
|
78
81
|
|
|
79
82
|
const urlParams = UrlParams.fromInput(urlParamsData)
|
|
80
83
|
|
|
@@ -101,7 +104,7 @@ export const makeHttpSync =
|
|
|
101
104
|
|
|
102
105
|
yield* SubscriptionRef.set(isConnected, true)
|
|
103
106
|
}).pipe(
|
|
104
|
-
|
|
107
|
+
UnknownError.mapToUnknownError,
|
|
105
108
|
Effect.timeout(pingTimeout),
|
|
106
109
|
Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)),
|
|
107
110
|
)
|
|
@@ -114,14 +117,14 @@ export const makeHttpSync =
|
|
|
114
117
|
}
|
|
115
118
|
|
|
116
119
|
// Helps already establish a TCP connection to the server
|
|
117
|
-
const connect = ping.pipe(
|
|
120
|
+
const connect = ping.pipe(UnknownError.mapToUnknownError)
|
|
118
121
|
|
|
119
122
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper
|
|
120
123
|
|
|
121
124
|
const mapCursor = (cursor: Option.Option<{ eventSequenceNumber: number }>) =>
|
|
122
125
|
cursor.pipe(
|
|
123
126
|
Option.map((a) => ({
|
|
124
|
-
eventSequenceNumber: a.eventSequenceNumber as EventSequenceNumber.
|
|
127
|
+
eventSequenceNumber: a.eventSequenceNumber as EventSequenceNumber.Global.Type,
|
|
125
128
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
126
129
|
})),
|
|
127
130
|
)
|
|
@@ -132,7 +135,7 @@ export const makeHttpSync =
|
|
|
132
135
|
payload,
|
|
133
136
|
cursor: mapCursor(cursor),
|
|
134
137
|
}).pipe(
|
|
135
|
-
options?.live
|
|
138
|
+
options?.live === true
|
|
136
139
|
? // Phase 2: Simulate `live` pull by polling for new events
|
|
137
140
|
Stream.concatWithLastElement((lastElement) => {
|
|
138
141
|
const initialPhase2Cursor = lastElement.pipe(
|
|
@@ -164,26 +167,49 @@ export const makeHttpSync =
|
|
|
164
167
|
: identity,
|
|
165
168
|
Stream.tap((res) => backendIdHelper.lazySet(res.backendId)),
|
|
166
169
|
Stream.map((res) => omit(res, ['backendId'])),
|
|
167
|
-
Stream.mapError((cause) =>
|
|
170
|
+
Stream.mapError((cause) =>
|
|
171
|
+
cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
172
|
+
? cause
|
|
173
|
+
: new UnknownError({ cause }),
|
|
174
|
+
),
|
|
168
175
|
Stream.withSpan('http-sync-client:pull'),
|
|
169
176
|
)
|
|
170
177
|
|
|
171
178
|
const pushSemaphore = yield* Effect.makeSemaphore(1)
|
|
172
179
|
|
|
173
|
-
const push: SyncBackend.SyncBackend<SyncMetadata>['push'] = (
|
|
174
|
-
|
|
180
|
+
const push: SyncBackend.SyncBackend<SyncMetadata>['push'] = Effect.fn('http-sync-client:push')(
|
|
181
|
+
function* (batch) {
|
|
175
182
|
if (batch.length === 0) {
|
|
176
183
|
return
|
|
177
184
|
}
|
|
178
185
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
186
|
+
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
|
+
}),
|
|
198
|
+
Effect.mapError((cause) => new UnknownError({ cause })),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
for (const chunk of Chunk.toReadonlyArray(batchChunks)) {
|
|
202
|
+
const chunkArray = Chunk.toReadonlyArray(chunk)
|
|
203
|
+
yield* rpcClient.SyncHttpRpc.Push({ storeId, payload, batch: chunkArray, backendId })
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
pushSemaphore.withPermits(1),
|
|
207
|
+
Effect.mapError((cause) =>
|
|
208
|
+
cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
209
|
+
? cause
|
|
210
|
+
: new UnknownError({ cause }),
|
|
211
|
+
),
|
|
212
|
+
)
|
|
187
213
|
|
|
188
214
|
return SyncBackend.of({
|
|
189
215
|
connect,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IsOfflineError, SyncBackend, UnknownError } from '@livestore/common'
|
|
2
|
+
import type { LiveStoreEvent } from '@livestore/common/schema'
|
|
3
|
+
import { splitChunkBySize } from '@livestore/common/sync'
|
|
2
4
|
import { omit } from '@livestore/utils'
|
|
3
5
|
import {
|
|
6
|
+
Chunk,
|
|
4
7
|
type Duration,
|
|
5
8
|
Effect,
|
|
6
9
|
Layer,
|
|
@@ -14,8 +17,10 @@ import {
|
|
|
14
17
|
Stream,
|
|
15
18
|
SubscriptionRef,
|
|
16
19
|
UrlParams,
|
|
17
|
-
type WebSocket,
|
|
18
20
|
} from '@livestore/utils/effect'
|
|
21
|
+
import type { WebSocket } from '@livestore/utils/effect/browser'
|
|
22
|
+
|
|
23
|
+
import { MAX_PUSH_EVENTS_PER_REQUEST, MAX_WS_MESSAGE_BYTES } from '../../common/constants.ts'
|
|
19
24
|
import { SearchParamsSchema } from '../../common/mod.ts'
|
|
20
25
|
import type { SyncMetadata } from '../../common/sync-message-types.ts'
|
|
21
26
|
import { SyncWsRpc } from '../../common/ws-rpc-schema.ts'
|
|
@@ -69,7 +74,7 @@ export const makeWsSync =
|
|
|
69
74
|
storeId,
|
|
70
75
|
payload,
|
|
71
76
|
transport: 'ws',
|
|
72
|
-
}).pipe(
|
|
77
|
+
}).pipe(UnknownError.mapToUnknownError)
|
|
73
78
|
|
|
74
79
|
const urlParams = UrlParams.fromInput(urlParamsData)
|
|
75
80
|
const wsUrl = `${options.url}?${UrlParams.toString(urlParams)}`
|
|
@@ -91,7 +96,10 @@ export const makeWsSync =
|
|
|
91
96
|
|
|
92
97
|
const ProtocolLive = RpcClient.layerProtocolSocketWithIsConnected({
|
|
93
98
|
isConnected,
|
|
94
|
-
retryTransientErrors: Schedule.
|
|
99
|
+
retryTransientErrors: Schedule.exponential('1 seconds').pipe(
|
|
100
|
+
Schedule.union(Schedule.fixed('30 seconds')),
|
|
101
|
+
Schedule.jittered,
|
|
102
|
+
),
|
|
95
103
|
pingSchedule: Schedule.once.pipe(Schedule.andThen(Schedule.fixed(pingInterval))),
|
|
96
104
|
url: wsUrl,
|
|
97
105
|
}).pipe(
|
|
@@ -115,7 +123,7 @@ export const makeWsSync =
|
|
|
115
123
|
}).pipe(
|
|
116
124
|
Effect.timeout(pingTimeout),
|
|
117
125
|
Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)),
|
|
118
|
-
|
|
126
|
+
UnknownError.mapToUnknownError,
|
|
119
127
|
Effect.withSpan('ping'),
|
|
120
128
|
)
|
|
121
129
|
|
|
@@ -134,39 +142,54 @@ export const makeWsSync =
|
|
|
134
142
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
135
143
|
})),
|
|
136
144
|
),
|
|
137
|
-
live: options?.live
|
|
145
|
+
live: options?.live === true,
|
|
138
146
|
}).pipe(
|
|
139
147
|
Stream.tap((res) => backendIdHelper.lazySet(res.backendId)),
|
|
140
148
|
Stream.map((res) => omit(res, ['backendId'])),
|
|
141
149
|
Stream.mapError((cause) =>
|
|
142
|
-
cause._tag === 'RpcClientError' && Socket.isSocketError(cause.cause)
|
|
150
|
+
cause._tag === 'RpcClientError' && Socket.isSocketError(cause.cause) === true
|
|
143
151
|
? new IsOfflineError({ cause: cause.cause })
|
|
144
|
-
: cause._tag === '
|
|
152
|
+
: cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
145
153
|
? cause
|
|
146
|
-
:
|
|
154
|
+
: new UnknownError({ cause }),
|
|
147
155
|
),
|
|
148
156
|
Stream.withSpan('pull'),
|
|
149
157
|
),
|
|
150
158
|
|
|
151
|
-
push: (batch)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
push: Effect.fn('push')(function* (batch) {
|
|
160
|
+
if (batch.length === 0) return
|
|
161
|
+
|
|
162
|
+
const encodePayload = (batch: ReadonlyArray<LiveStoreEvent.Global.Encoded>) => ({
|
|
163
|
+
storeId,
|
|
164
|
+
payload,
|
|
165
|
+
batch,
|
|
166
|
+
backendId: backendIdHelper.get(),
|
|
167
|
+
})
|
|
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
|
+
)
|
|
156
177
|
|
|
157
|
-
|
|
178
|
+
for (const sub of chunksChunk) {
|
|
179
|
+
yield* rpcClient.SyncWsRpc.Push({
|
|
158
180
|
storeId,
|
|
159
181
|
payload,
|
|
160
|
-
batch,
|
|
182
|
+
batch: Chunk.toReadonlyArray(sub),
|
|
161
183
|
backendId: backendIdHelper.get(),
|
|
162
184
|
}).pipe(
|
|
163
185
|
Effect.mapError((cause) =>
|
|
164
|
-
cause._tag === '
|
|
186
|
+
cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
165
187
|
? cause
|
|
166
|
-
: new
|
|
188
|
+
: new UnknownError({ cause }),
|
|
167
189
|
),
|
|
168
190
|
)
|
|
169
|
-
}
|
|
191
|
+
}
|
|
192
|
+
}),
|
|
170
193
|
ping,
|
|
171
194
|
metadata: {
|
|
172
195
|
name: '@livestore/cf-sync',
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Shared transport limits for Cloudflare sync provider
|
|
2
|
+
// Keep payloads comfortably below ~1MB frame caps across Cloudflare transports.
|
|
3
|
+
// References:
|
|
4
|
+
// - Durable Objects WebSockets + hibernation best practices:
|
|
5
|
+
// https://developers.cloudflare.com/durable-objects/best-practices/websockets/
|
|
6
|
+
// - Workers platform limits (general context):
|
|
7
|
+
// https://developers.cloudflare.com/workers/platform/limits/
|
|
8
|
+
// Empirically, frames just below 1MB can fail on hibernated DO WebSockets; we use 900_000 bytes to keep a safety margin.
|
|
9
|
+
export const MAX_TRANSPORT_PAYLOAD_BYTES = 900_000
|
|
10
|
+
|
|
11
|
+
export const MAX_WS_MESSAGE_BYTES = MAX_TRANSPORT_PAYLOAD_BYTES
|
|
12
|
+
export const MAX_DO_RPC_REQUEST_BYTES = MAX_TRANSPORT_PAYLOAD_BYTES
|
|
13
|
+
export const MAX_HTTP_REQUEST_BYTES = MAX_TRANSPORT_PAYLOAD_BYTES
|
|
14
|
+
|
|
15
|
+
// Upper bound for items per message/request. Mirrors server broadcast chunking.
|
|
16
|
+
// Not Cloudflare-enforced; chosen to balance payload size and latency.
|
|
17
|
+
export const MAX_PULL_EVENTS_PER_MESSAGE = 100
|
|
18
|
+
export const MAX_PUSH_EVENTS_PER_REQUEST = 100
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common'
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import * as SyncMessage from './sync-message-types.ts'
|
|
4
5
|
|
|
5
6
|
const commonPayloadFields = {
|
|
6
7
|
/**
|
|
7
|
-
* While the storeId is already implied by the
|
|
8
|
+
* While the storeId is already implied by the Durable Object, we still need the explicit storeId
|
|
8
9
|
* since a DO doesn't know its own id.name value. 🫠
|
|
9
10
|
* https://community.cloudflare.com/t/how-can-i-get-the-name-of-a-durable-object-from-itself/505961/8
|
|
10
11
|
*/
|
|
@@ -34,7 +35,7 @@ export class SyncDoRpc extends RpcGroup.make(
|
|
|
34
35
|
rpcRequestId: Schema.String,
|
|
35
36
|
...SyncMessage.PullResponse.fields,
|
|
36
37
|
}),
|
|
37
|
-
error:
|
|
38
|
+
error: Schema.Union(UnknownError, BackendIdMismatchError),
|
|
38
39
|
stream: true,
|
|
39
40
|
}),
|
|
40
41
|
Rpc.make('SyncDoRpc.Push', {
|
|
@@ -43,7 +44,7 @@ export class SyncDoRpc extends RpcGroup.make(
|
|
|
43
44
|
...commonPayloadFields,
|
|
44
45
|
},
|
|
45
46
|
success: SyncMessage.PushAck,
|
|
46
|
-
error:
|
|
47
|
+
error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
|
|
47
48
|
}),
|
|
48
49
|
Rpc.make('SyncDoRpc.Ping', {
|
|
49
50
|
payload: {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common'
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import * as SyncMessage from './sync-message-types.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -17,7 +18,7 @@ export class SyncHttpRpc extends RpcGroup.make(
|
|
|
17
18
|
...SyncMessage.PullRequest.fields,
|
|
18
19
|
}),
|
|
19
20
|
success: SyncMessage.PullResponse,
|
|
20
|
-
error:
|
|
21
|
+
error: Schema.Union(UnknownError, BackendIdMismatchError),
|
|
21
22
|
stream: true,
|
|
22
23
|
}),
|
|
23
24
|
Rpc.make('SyncHttpRpc.Push', {
|
|
@@ -27,7 +28,7 @@ export class SyncHttpRpc extends RpcGroup.make(
|
|
|
27
28
|
...SyncMessage.PushRequest.fields,
|
|
28
29
|
}),
|
|
29
30
|
success: SyncMessage.PushAck,
|
|
30
|
-
error:
|
|
31
|
+
error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
|
|
31
32
|
}),
|
|
32
33
|
Rpc.make('SyncHttpRpc.Ping', {
|
|
33
34
|
payload: Schema.Struct({
|
|
@@ -35,6 +36,6 @@ export class SyncHttpRpc extends RpcGroup.make(
|
|
|
35
36
|
payload: Schema.optional(Schema.JsonValue),
|
|
36
37
|
}),
|
|
37
38
|
success: SyncMessage.Pong,
|
|
38
|
-
error:
|
|
39
|
+
error: UnknownError,
|
|
39
40
|
}),
|
|
40
41
|
) {}
|
package/src/common/mod.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { OversizeChunkItemError, splitChunkBySize } from '@livestore/common/sync'
|
|
1
2
|
import { Schema } from '@livestore/utils/effect'
|
|
2
3
|
|
|
3
4
|
export type { CfTypes } from '@livestore/common-cf'
|
|
4
|
-
|
|
5
|
+
export * from './constants.ts'
|
|
5
6
|
export { SyncHttpRpc } from './http-rpc-schema.ts'
|
|
6
7
|
export * as SyncMessage from './sync-message-types.ts'
|
|
8
|
+
export { OversizeChunkItemError, splitChunkBySize }
|
|
7
9
|
|
|
8
10
|
export const SearchParamsSchema = Schema.Struct({
|
|
9
11
|
storeId: Schema.String,
|
|
10
12
|
payload: Schema.compose(Schema.StringFromUriComponent, Schema.parseJson(Schema.JsonValue)).pipe(Schema.UndefinedOr),
|
|
11
13
|
// NOTE `do-rpc` is handled differently
|
|
12
|
-
transport: Schema.
|
|
14
|
+
transport: Schema.Literal('http', 'ws'),
|
|
13
15
|
})
|
|
14
16
|
|
|
15
17
|
export type SearchParams = typeof SearchParamsSchema.Type
|
|
@@ -20,7 +20,7 @@ export const PullRequest = Schema.Struct({
|
|
|
20
20
|
cursor: Schema.Option(
|
|
21
21
|
Schema.Struct({
|
|
22
22
|
backendId: BackendId,
|
|
23
|
-
eventSequenceNumber: EventSequenceNumber.
|
|
23
|
+
eventSequenceNumber: EventSequenceNumber.Global.Schema,
|
|
24
24
|
}),
|
|
25
25
|
),
|
|
26
26
|
}).annotations({ title: '@livestore/sync-cf:PullRequest' })
|
|
@@ -30,7 +30,7 @@ export type PullRequest = typeof PullRequest.Type
|
|
|
30
30
|
export const PullResponse = Schema.Struct({
|
|
31
31
|
batch: Schema.Array(
|
|
32
32
|
Schema.Struct({
|
|
33
|
-
eventEncoded: LiveStoreEvent.
|
|
33
|
+
eventEncoded: LiveStoreEvent.Global.Encoded,
|
|
34
34
|
metadata: Schema.Option(SyncMetadata),
|
|
35
35
|
}),
|
|
36
36
|
),
|
|
@@ -48,7 +48,7 @@ export const emptyPullResponse = (backendId: string) =>
|
|
|
48
48
|
export type PullResponse = typeof PullResponse.Type
|
|
49
49
|
|
|
50
50
|
export const PushRequest = Schema.Struct({
|
|
51
|
-
batch: Schema.Array(LiveStoreEvent.
|
|
51
|
+
batch: Schema.Array(LiveStoreEvent.Global.Encoded),
|
|
52
52
|
backendId: Schema.Option(BackendId),
|
|
53
53
|
}).annotations({ title: '@livestore/sync-cf:PushRequest' })
|
|
54
54
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common'
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import * as SyncMessage from './sync-message-types.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -19,7 +20,7 @@ export class SyncWsRpc extends RpcGroup.make(
|
|
|
19
20
|
...SyncMessage.PullRequest.fields,
|
|
20
21
|
}),
|
|
21
22
|
success: SyncMessage.PullResponse,
|
|
22
|
-
error:
|
|
23
|
+
error: Schema.Union(UnknownError, BackendIdMismatchError),
|
|
23
24
|
stream: true,
|
|
24
25
|
}),
|
|
25
26
|
Rpc.make('SyncWsRpc.Push', {
|
|
@@ -29,7 +30,7 @@ export class SyncWsRpc extends RpcGroup.make(
|
|
|
29
30
|
...SyncMessage.PushRequest.fields,
|
|
30
31
|
}),
|
|
31
32
|
success: SyncMessage.PushAck,
|
|
32
|
-
error:
|
|
33
|
+
error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
|
|
33
34
|
}),
|
|
34
35
|
// Ping <> Pong is handled by DO WS auto-response
|
|
35
36
|
// TODO add admin RPCs
|