@livestore/sync-cf 0.5.0-dev.0 → 0.5.0-dev.1
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 +5 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
- package/dist/cf-worker/do/durable-object.js +34 -30
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +2 -2
- package/dist/cf-worker/do/observability.d.ts +23 -0
- package/dist/cf-worker/do/observability.d.ts.map +1 -0
- package/dist/cf-worker/do/observability.js +52 -0
- package/dist/cf-worker/do/observability.js.map +1 -0
- package/dist/cf-worker/do/observability.test.d.ts +2 -0
- package/dist/cf-worker/do/observability.test.d.ts.map +1 -0
- package/dist/cf-worker/do/observability.test.js +204 -0
- package/dist/cf-worker/do/observability.test.js.map +1 -0
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +3 -3
- package/dist/cf-worker/do/push.d.ts +2 -2
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +7 -6
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/push.test.js +1 -1
- package/dist/cf-worker/do/sqlite.js +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +3 -3
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts +15 -0
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.js +23 -7
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.test.d.ts +2 -0
- package/dist/cf-worker/do/transport/do-rpc-server.test.d.ts.map +1 -0
- package/dist/cf-worker/do/transport/do-rpc-server.test.js +28 -0
- package/dist/cf-worker/do/transport/do-rpc-server.test.js.map +1 -0
- package/dist/cf-worker/do/transport/http-rpc-server.js +6 -6
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +8 -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 +32 -24
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/mod.js +3 -3
- package/dist/cf-worker/shared.d.ts +17 -12
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +2 -2
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +3 -3
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +2 -2
- package/dist/cf-worker/worker.js.map +1 -1
- package/dist/client/mod.js +3 -3
- package/dist/client/transport/do-rpc-client.d.ts +6 -3
- package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/do-rpc-client.js +65 -20
- package/dist/client/transport/do-rpc-client.js.map +1 -1
- package/dist/client/transport/do-rpc-client.test.d.ts +2 -0
- package/dist/client/transport/do-rpc-client.test.d.ts.map +1 -0
- package/dist/client/transport/do-rpc-client.test.js +268 -0
- package/dist/client/transport/do-rpc-client.test.js.map +1 -0
- package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/http-rpc-client.js +20 -10
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/rpc-client-error.d.ts +5 -0
- package/dist/client/transport/rpc-client-error.d.ts.map +1 -0
- package/dist/client/transport/rpc-client-error.js +8 -0
- package/dist/client/transport/rpc-client-error.js.map +1 -0
- package/dist/client/transport/rpc-client-error.test.d.ts +2 -0
- package/dist/client/transport/rpc-client-error.test.d.ts.map +1 -0
- package/dist/client/transport/rpc-client-error.test.js +33 -0
- package/dist/client/transport/rpc-client-error.test.js.map +1 -0
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +18 -12
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/do-rpc-schema.d.ts +24 -11
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +10 -1
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +8 -8
- package/dist/common/http-rpc-schema.js +1 -1
- package/dist/common/mod.d.ts +1 -0
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +4 -3
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +1 -1
- package/dist/common/ws-rpc-schema.js +1 -1
- package/package.json +41 -41
- package/src/cf-worker/do/durable-object.ts +42 -45
- package/src/cf-worker/do/observability.test.ts +337 -0
- package/src/cf-worker/do/observability.ts +121 -0
- package/src/cf-worker/do/push.ts +3 -2
- package/src/cf-worker/do/transport/do-rpc-server.test.ts +32 -0
- package/src/cf-worker/do/transport/do-rpc-server.ts +23 -1
- package/src/cf-worker/do/transport/ws-rpc-server.ts +45 -21
- package/src/cf-worker/shared.ts +13 -6
- package/src/cf-worker/worker.ts +1 -1
- package/src/client/transport/do-rpc-client.test.ts +411 -0
- package/src/client/transport/do-rpc-client.ts +100 -18
- package/src/client/transport/http-rpc-client.ts +20 -9
- package/src/client/transport/rpc-client-error.test.ts +41 -0
- package/src/client/transport/rpc-client-error.ts +9 -0
- package/src/client/transport/ws-rpc-client.ts +15 -10
- package/src/common/do-rpc-schema.ts +10 -0
- package/src/common/mod.ts +1 -0
|
@@ -25,6 +25,7 @@ import { MAX_HTTP_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from '../../commo
|
|
|
25
25
|
import { SyncHttpRpc } from '../../common/http-rpc-schema.ts'
|
|
26
26
|
import { SearchParamsSchema } from '../../common/mod.ts'
|
|
27
27
|
import type { SyncMetadata } from '../../common/sync-message-types.ts'
|
|
28
|
+
import { mapRpcClientError } from './rpc-client-error.ts'
|
|
28
29
|
|
|
29
30
|
type PushBatchItem = LiveStoreEvent.Global.Encoded
|
|
30
31
|
|
|
@@ -108,9 +109,13 @@ export const makeHttpSync =
|
|
|
108
109
|
|
|
109
110
|
yield* SubscriptionRef.set(isConnected, true)
|
|
110
111
|
}).pipe(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
Effect.mapError((cause) =>
|
|
113
|
+
cause._tag === 'RpcClientError' ? mapRpcClientError(cause) : new UnknownError({ cause }),
|
|
114
|
+
),
|
|
115
|
+
Effect.timeoutOrElse({
|
|
116
|
+
duration: pingTimeout,
|
|
117
|
+
orElse: () => SubscriptionRef.set(isConnected, false),
|
|
118
|
+
}),
|
|
114
119
|
)
|
|
115
120
|
|
|
116
121
|
const pingInterval = options.ping?.requestInterval ?? 10_000
|
|
@@ -178,9 +183,11 @@ export const makeHttpSync =
|
|
|
178
183
|
Stream.tap((res) => backendIdHelper.lazySet(res.backendId)),
|
|
179
184
|
Stream.map((res) => Struct.omit(res, ['backendId'])),
|
|
180
185
|
Stream.mapError((cause) =>
|
|
181
|
-
cause._tag === '
|
|
182
|
-
? cause
|
|
183
|
-
:
|
|
186
|
+
cause._tag === 'RpcClientError'
|
|
187
|
+
? mapRpcClientError(cause)
|
|
188
|
+
: cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
189
|
+
? cause
|
|
190
|
+
: new UnknownError({ cause }),
|
|
184
191
|
),
|
|
185
192
|
Stream.withSpan('http-sync-client:pull'),
|
|
186
193
|
)
|
|
@@ -215,9 +222,13 @@ export const makeHttpSync =
|
|
|
215
222
|
},
|
|
216
223
|
pushSemaphore.withPermits(1),
|
|
217
224
|
Effect.mapError((cause) =>
|
|
218
|
-
cause._tag === '
|
|
219
|
-
? cause
|
|
220
|
-
:
|
|
225
|
+
cause._tag === 'RpcClientError'
|
|
226
|
+
? mapRpcClientError(cause)
|
|
227
|
+
: cause._tag === 'UnknownError' ||
|
|
228
|
+
cause._tag === 'ServerAheadError' ||
|
|
229
|
+
cause._tag === 'BackendIdMismatchError'
|
|
230
|
+
? cause
|
|
231
|
+
: new UnknownError({ cause }),
|
|
221
232
|
),
|
|
222
233
|
)
|
|
223
234
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { IsOfflineError, UnknownError } from '@livestore/common'
|
|
4
|
+
import { HttpClientError, RpcClientError, Socket } from '@livestore/utils/effect'
|
|
5
|
+
|
|
6
|
+
import { mapRpcClientError } from './rpc-client-error.ts'
|
|
7
|
+
|
|
8
|
+
const socketReasons = [
|
|
9
|
+
new Socket.SocketCloseError({ code: 1012, closeReason: 'Restart' }),
|
|
10
|
+
new Socket.SocketReadError({ cause: new Error('Disconnected') }),
|
|
11
|
+
new Socket.SocketWriteError({ cause: new Error('Disconnected') }),
|
|
12
|
+
new Socket.SocketOpenError({ kind: 'Timeout', cause: new Error('Unavailable') }),
|
|
13
|
+
new Socket.SocketUpgradeError({ cause: new Error('Upgrade failed') }),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
it.each(socketReasons)('maps $\u005ftag to offline', (reason) => {
|
|
17
|
+
const result = mapRpcClientError(new RpcClientError.RpcClientError({ reason }))
|
|
18
|
+
expect(result).toBeInstanceOf(IsOfflineError)
|
|
19
|
+
expect(result.cause).toBe(reason)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('maps an HTTP transport failure to offline', () => {
|
|
23
|
+
const reason = new HttpClientError.HttpClientErrorSchema({ kind: 'TransportError' })
|
|
24
|
+
const result = mapRpcClientError(new RpcClientError.RpcClientError({ reason }))
|
|
25
|
+
expect(result).toBeInstanceOf(IsOfflineError)
|
|
26
|
+
expect(result.cause).toBe(reason)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const protocolReasons = [
|
|
30
|
+
new RpcClientError.RpcClientDefect({ message: 'Malformed RPC response', cause: new Error('Invalid message') }),
|
|
31
|
+
...(['EncodeError', 'DecodeError', 'InvalidUrlError', 'StatusCodeError', 'EmptyBodyError'] as const).map(
|
|
32
|
+
(kind) => new HttpClientError.HttpClientErrorSchema({ kind }),
|
|
33
|
+
),
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
it.each(protocolReasons)('keeps protocol failure $\u005ftag terminal', (reason) => {
|
|
37
|
+
const error = new RpcClientError.RpcClientError({ reason })
|
|
38
|
+
const result = mapRpcClientError(error)
|
|
39
|
+
expect(result).toBeInstanceOf(UnknownError)
|
|
40
|
+
expect(result.cause).toBe(error)
|
|
41
|
+
})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IsOfflineError, UnknownError } from '@livestore/common'
|
|
2
|
+
import { type RpcClientError, Schema, Socket } from '@livestore/utils/effect'
|
|
3
|
+
|
|
4
|
+
/** Only transport loss is retryable. RPC defects and HTTP protocol failures stay terminal. */
|
|
5
|
+
export const mapRpcClientError = (error: RpcClientError.RpcClientError): IsOfflineError | UnknownError =>
|
|
6
|
+
Schema.is(Socket.SocketErrorReason)(error.reason) === true ||
|
|
7
|
+
(error.reason._tag === 'HttpError' && error.reason.kind === 'TransportError')
|
|
8
|
+
? new IsOfflineError({ cause: error.reason })
|
|
9
|
+
: new UnknownError({ cause: error })
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyncBackend, UnknownError } from '@livestore/common'
|
|
2
2
|
import type { LiveStoreEvent } from '@livestore/common/schema'
|
|
3
3
|
import { splitArrayBySize } from '@livestore/common/sync'
|
|
4
4
|
import {
|
|
@@ -24,6 +24,7 @@ import { MAX_PUSH_EVENTS_PER_REQUEST, MAX_WS_MESSAGE_BYTES } from '../../common/
|
|
|
24
24
|
import { SearchParamsSchema } from '../../common/mod.ts'
|
|
25
25
|
import type { SyncMetadata } from '../../common/sync-message-types.ts'
|
|
26
26
|
import { SyncWsRpc } from '../../common/ws-rpc-schema.ts'
|
|
27
|
+
import { mapRpcClientError } from './rpc-client-error.ts'
|
|
27
28
|
|
|
28
29
|
export interface WsSyncOptions {
|
|
29
30
|
/**
|
|
@@ -121,8 +122,10 @@ export const makeWsSync =
|
|
|
121
122
|
yield* pinger.ping
|
|
122
123
|
yield* SubscriptionRef.set(isConnected, true)
|
|
123
124
|
}).pipe(
|
|
124
|
-
Effect.
|
|
125
|
-
|
|
125
|
+
Effect.timeoutOrElse({
|
|
126
|
+
duration: pingTimeout,
|
|
127
|
+
orElse: () => SubscriptionRef.set(isConnected, false),
|
|
128
|
+
}),
|
|
126
129
|
UnknownError.mapToUnknownError,
|
|
127
130
|
Effect.withSpan('ping'),
|
|
128
131
|
)
|
|
@@ -147,8 +150,8 @@ export const makeWsSync =
|
|
|
147
150
|
Stream.tap((res) => backendIdHelper.lazySet(res.backendId)),
|
|
148
151
|
Stream.map((res) => Struct.omit(res, ['backendId'])),
|
|
149
152
|
Stream.mapError((cause) =>
|
|
150
|
-
cause._tag === 'RpcClientError'
|
|
151
|
-
?
|
|
153
|
+
cause._tag === 'RpcClientError'
|
|
154
|
+
? mapRpcClientError(cause)
|
|
152
155
|
: cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
153
156
|
? cause
|
|
154
157
|
: new UnknownError({ cause }),
|
|
@@ -184,11 +187,13 @@ export const makeWsSync =
|
|
|
184
187
|
backendId: backendIdHelper.get(),
|
|
185
188
|
}).pipe(
|
|
186
189
|
Effect.mapError((cause) =>
|
|
187
|
-
cause._tag === '
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
cause._tag === 'RpcClientError'
|
|
191
|
+
? mapRpcClientError(cause)
|
|
192
|
+
: cause._tag === 'UnknownError' ||
|
|
193
|
+
cause._tag === 'ServerAheadError' ||
|
|
194
|
+
cause._tag === 'BackendIdMismatchError'
|
|
195
|
+
? cause
|
|
196
|
+
: new UnknownError({ cause }),
|
|
192
197
|
),
|
|
193
198
|
)
|
|
194
199
|
}
|
|
@@ -52,4 +52,14 @@ export class SyncDoRpc extends RpcGroup.make(
|
|
|
52
52
|
},
|
|
53
53
|
success: Schema.Void,
|
|
54
54
|
}),
|
|
55
|
+
Rpc.make('SyncDoRpc.Unsubscribe', {
|
|
56
|
+
payload: {
|
|
57
|
+
/** Client DO id whose live-pull subscription row to drop. */
|
|
58
|
+
durableObjectId: Schema.String,
|
|
59
|
+
/** Request id of the live pull that registered the row; the row is only dropped if it still matches. */
|
|
60
|
+
requestId: Schema.String,
|
|
61
|
+
...commonPayloadFields,
|
|
62
|
+
},
|
|
63
|
+
success: Schema.Void,
|
|
64
|
+
}),
|
|
55
65
|
) {}
|
package/src/common/mod.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { Schema } from '@livestore/utils/effect'
|
|
|
3
3
|
|
|
4
4
|
export type { CfTypes } from '@livestore/common-cf'
|
|
5
5
|
export * from './constants.ts'
|
|
6
|
+
export { SyncDoRpc } from './do-rpc-schema.ts'
|
|
6
7
|
export { SyncHttpRpc } from './http-rpc-schema.ts'
|
|
7
8
|
export * as SyncMessage from './sync-message-types.ts'
|
|
8
9
|
|