@livestore/sync-cf 0.4.0-dev.9 → 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.
- 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 +36 -18
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +24 -20
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +57 -24
- 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 +26 -21
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +20 -6
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +84 -56
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/push.test.d.ts +2 -0
- package/dist/cf-worker/do/push.test.d.ts.map +1 -0
- package/dist/cf-worker/do/push.test.js +30 -0
- package/dist/cf-worker/do/push.test.js.map +1 -0
- package/dist/cf-worker/do/sqlite.d.ts +49 -52
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js +14 -5
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +15 -9
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +111 -25
- package/dist/cf-worker/do/sync-storage.js.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts +2 -2
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.js +31 -23
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +5 -3
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.js +28 -19
- package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +3 -2
- 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 -10
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +124 -34
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +52 -17
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +47 -39
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +54 -35
- package/dist/cf-worker/worker.js.map +1 -1
- package/dist/client/transport/do-rpc-client.d.ts +13 -4
- package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/do-rpc-client.js +74 -28
- package/dist/client/transport/do-rpc-client.js.map +1 -1
- package/dist/client/transport/http-rpc-client.d.ts +3 -3
- package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/http-rpc-client.js +51 -22
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts +4 -3
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +40 -22
- 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 +42 -43
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +5 -5
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +37 -38
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +7 -7
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/mod.d.ts +5 -3
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +4 -2
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +113 -130
- package/dist/common/sync-message-types.d.ts.map +1 -1
- package/dist/common/sync-message-types.js +29 -17
- package/dist/common/sync-message-types.js.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +34 -35
- package/dist/common/ws-rpc-schema.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.js +5 -5
- package/dist/common/ws-rpc-schema.js.map +1 -1
- package/package.json +57 -15
- package/src/cf-worker/do/durable-object.ts +59 -41
- package/src/cf-worker/do/layer.ts +153 -88
- package/src/cf-worker/do/pull.ts +48 -31
- package/src/cf-worker/do/push.test.ts +40 -0
- package/src/cf-worker/do/push.ts +163 -125
- package/src/cf-worker/do/sqlite.ts +15 -5
- package/src/cf-worker/do/sync-storage.ts +171 -38
- package/src/cf-worker/do/transport/do-rpc-server.ts +40 -40
- package/src/cf-worker/do/transport/http-rpc-server.ts +37 -20
- package/src/cf-worker/do/transport/ws-rpc-server.ts +44 -16
- package/src/cf-worker/shared.ts +152 -36
- package/src/cf-worker/worker.ts +110 -58
- package/src/client/transport/do-rpc-client.ts +106 -40
- package/src/client/transport/http-rpc-client.ts +74 -38
- package/src/client/transport/ws-rpc-client.ts +55 -29
- package/src/common/constants.ts +18 -0
- package/src/common/do-rpc-schema.ts +6 -5
- package/src/common/http-rpc-schema.ts +8 -7
- package/src/common/mod.ts +4 -3
- package/src/common/sync-message-types.ts +19 -19
- package/src/common/ws-rpc-schema.ts +6 -5
- package/dist/cf-worker/do/ws-chunking.d.ts +0 -22
- package/dist/cf-worker/do/ws-chunking.d.ts.map +0 -1
- package/dist/cf-worker/do/ws-chunking.js +0 -49
- package/dist/cf-worker/do/ws-chunking.js.map +0 -1
- package/src/cf-worker/do/ws-chunking.ts +0 -76
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/cf-worker/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/cf-worker/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,11 @@ export interface SyncBackendRpcStub extends CfTypes.DurableObjectStub, SyncBacke
|
|
|
7
7
|
export interface DoRpcSyncOptions {
|
|
8
8
|
/** Durable Object stub that implements the SyncDoRpc interface */
|
|
9
9
|
syncBackendStub: SyncBackendRpcStub;
|
|
10
|
+
/**
|
|
11
|
+
* State handle of the client DurableObject running this sync backend. Scopes live-pull routing to
|
|
12
|
+
* this instance so it resets when the DO is reconstructed (see {@link handleSyncUpdateRpc}).
|
|
13
|
+
*/
|
|
14
|
+
durableObjectState: CfTypes.DurableObjectState;
|
|
10
15
|
/** Information about this DurableObject instance so the Sync DO instance can call back to this instance */
|
|
11
16
|
durableObjectContext: {
|
|
12
17
|
/** See `wrangler.toml` for the binding name */
|
|
@@ -20,8 +25,11 @@ export interface DoRpcSyncOptions {
|
|
|
20
25
|
*
|
|
21
26
|
* Used internally by `@livestore/adapter-cf` to connect to the sync backend.
|
|
22
27
|
*/
|
|
23
|
-
export declare const makeDoRpcSync: ({ syncBackendStub, durableObjectContext }: DoRpcSyncOptions) => SyncBackend.SyncBackendConstructor<SyncMetadata>;
|
|
28
|
+
export declare const makeDoRpcSync: ({ syncBackendStub, durableObjectState, durableObjectContext, }: DoRpcSyncOptions) => SyncBackend.SyncBackendConstructor<SyncMetadata>;
|
|
24
29
|
/**
|
|
30
|
+
* Routes an update from the sync backend into this client's live pull.
|
|
31
|
+
*
|
|
32
|
+
* Only `ctx` and `payload` go here; `storeId` is for reloading your store on a rebuilt DO (see example).
|
|
25
33
|
*
|
|
26
34
|
* ```ts
|
|
27
35
|
* import { DurableObject } from 'cloudflare:workers'
|
|
@@ -30,11 +38,12 @@ export declare const makeDoRpcSync: ({ syncBackendStub, durableObjectContext }:
|
|
|
30
38
|
* export class MyDurableObject extends DurableObject implements ClientDoWithRpcCallback {
|
|
31
39
|
* // ...
|
|
32
40
|
*
|
|
33
|
-
* async syncUpdateRpc(payload:
|
|
34
|
-
*
|
|
41
|
+
* async syncUpdateRpc(payload: Uint8Array<ArrayBuffer>, storeId: string) {
|
|
42
|
+
* await this.getStore(storeId)
|
|
43
|
+
* return handleSyncUpdateRpc(this.ctx, payload)
|
|
35
44
|
* }
|
|
36
45
|
* }
|
|
37
46
|
* ```
|
|
38
47
|
*/
|
|
39
|
-
export declare const handleSyncUpdateRpc: (payload:
|
|
48
|
+
export declare const handleSyncUpdateRpc: (ctx: CfTypes.DurableObjectState, payload: Uint8Array<ArrayBuffer>) => Promise<void>;
|
|
40
49
|
//# sourceMappingURL=do-rpc-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-rpc-client.d.ts","sourceRoot":"","sources":["../../../src/client/transport/do-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"do-rpc-client.d.ts","sourceRoot":"","sources":["../../../src/client/transport/do-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAE,KAAK,OAAO,EAA8B,MAAM,sBAAsB,CAAA;AAkB/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAIxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAItE,MAAM,WAAW,kBAAmB,SAAQ,OAAO,CAAC,iBAAiB,EAAE,uBAAuB;CAAG;AAEjG,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,eAAe,EAAE,kBAAkB,CAAA;IACnC;;;OAGG;IACH,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,CAAA;IAC9C,2GAA2G;IAC3G,oBAAoB,EAAE;QACpB,+CAA+C;QAC/C,WAAW,EAAE,MAAM,CAAA;QACnB,sCAAsC;QACtC,eAAe,EAAE,MAAM,CAAA;KACxB,CAAA;CACF;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GACvB,gEAIE,gBAAgB,KAAG,WAAW,CAAC,sBAAsB,CAAC,YAAY,CAkHV,CAAA;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,mBAAmB,GAAI,KAAK,OAAO,CAAC,kBAAkB,EAAE,SAAS,UAAU,CAAC,WAAW,CAAC,kBAmBC,CAAA"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyncBackend, UnknownError } from '@livestore/common';
|
|
2
2
|
import { layerProtocolDurableObject } from '@livestore/common-cf';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { splitArrayBySize } from '@livestore/common/sync';
|
|
4
|
+
import { shouldNeverHappen } from '@livestore/utils';
|
|
5
|
+
import { Effect, identity, Layer, Option, Queue, ReadonlyArray as EffectArray, RpcClient, RpcSerialization, Schema, Stream, Struct, SubscriptionRef, } from '@livestore/utils/effect';
|
|
6
|
+
import { MAX_DO_RPC_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from "../../common/constants.js";
|
|
5
7
|
import { SyncDoRpc } from "../../common/do-rpc-schema.js";
|
|
6
8
|
import { SyncMessage } from "../../common/mod.js";
|
|
7
|
-
const requestIdMailboxMap = new Map();
|
|
8
9
|
/**
|
|
9
10
|
* Creates a sync backend that uses Durable Object RPC to communicate with the sync backend.
|
|
10
11
|
*
|
|
11
12
|
* Used internally by `@livestore/adapter-cf` to connect to the sync backend.
|
|
12
13
|
*/
|
|
13
|
-
export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ storeId, payload }) => Effect.gen(function* () {
|
|
14
|
+
export const makeDoRpcSync = ({ syncBackendStub, durableObjectState, durableObjectContext, }) => ({ storeId, payload }) => Effect.gen(function* () {
|
|
14
15
|
const isConnected = yield* SubscriptionRef.make(true);
|
|
15
16
|
const ProtocolLive = layerProtocolDurableObject({
|
|
16
17
|
callRpc: (payload) => syncBackendStub.rpc(payload),
|
|
@@ -21,34 +22,55 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
21
22
|
// Nothing to do here
|
|
22
23
|
const connect = Effect.void;
|
|
23
24
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper;
|
|
24
|
-
const pull = (cursor, options) => rpcClient
|
|
25
|
+
const pull = (cursor, options) => rpcClient['SyncDoRpc.Pull']({
|
|
25
26
|
cursor: cursor.pipe(Option.map((a) => ({
|
|
26
27
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
27
28
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
28
29
|
}))),
|
|
29
30
|
storeId,
|
|
30
|
-
rpcContext: options?.live ? { callerContext: durableObjectContext } : undefined,
|
|
31
|
-
}).pipe(options?.live
|
|
31
|
+
rpcContext: options?.live === true ? { callerContext: durableObjectContext } : undefined,
|
|
32
|
+
}).pipe(options?.live === true
|
|
32
33
|
? Stream.concatWithLastElement((res) => Effect.gen(function* () {
|
|
33
34
|
if (res._tag === 'None')
|
|
34
35
|
return shouldNeverHappen('There should at least be a no-more page info response');
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
const requestId = res.value.rpcRequestId;
|
|
37
|
+
const routing = pullRoutingFor(durableObjectState);
|
|
38
|
+
const queue = yield* Effect.acquireRelease(Queue.unbounded(), (queue) =>
|
|
39
|
+
// Drop the routing entry on release so it can't outlive its (now shut-down) queue
|
|
40
|
+
Effect.sync(() => routing.delete(requestId)).pipe(Effect.andThen(Queue.shutdown(queue))));
|
|
41
|
+
routing.set(requestId, queue);
|
|
42
|
+
return Stream.fromQueue(queue);
|
|
43
|
+
}).pipe(Stream.unwrap))
|
|
44
|
+
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => Struct.omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
45
|
+
? cause
|
|
46
|
+
: new UnknownError({ cause })), Stream.withSpan('rpc-sync-client:pull'));
|
|
47
|
+
const push = Effect.fn('rpc-sync-client:push')(function* (batch) {
|
|
41
48
|
if (batch.length === 0) {
|
|
42
49
|
return;
|
|
43
50
|
}
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
const backendId = backendIdHelper.get();
|
|
52
|
+
if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const batchChunks = yield* splitArrayBySize({
|
|
56
|
+
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
57
|
+
maxBytes: MAX_DO_RPC_REQUEST_BYTES,
|
|
58
|
+
encode: (items) => ({
|
|
59
|
+
batch: items,
|
|
60
|
+
storeId,
|
|
61
|
+
backendId,
|
|
62
|
+
}),
|
|
63
|
+
})(batch).pipe(Effect.mapError((cause) => new UnknownError({ cause })));
|
|
64
|
+
for (const batchChunk of batchChunks) {
|
|
65
|
+
yield* rpcClient['SyncDoRpc.Push']({ batch: batchChunk, storeId, backendId });
|
|
66
|
+
}
|
|
67
|
+
}, Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
46
68
|
? cause
|
|
47
|
-
:
|
|
48
|
-
const ping = rpcClient
|
|
69
|
+
: new UnknownError({ cause })));
|
|
70
|
+
const ping = rpcClient['SyncDoRpc.Ping']({
|
|
49
71
|
storeId,
|
|
50
72
|
payload,
|
|
51
|
-
}).pipe(
|
|
73
|
+
}).pipe(UnknownError.mapToUnknownError, Effect.withSpan('rpc-sync-client:ping'));
|
|
52
74
|
return SyncBackend.of({
|
|
53
75
|
connect,
|
|
54
76
|
isConnected,
|
|
@@ -68,6 +90,9 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
68
90
|
});
|
|
69
91
|
}).pipe(Effect.withSpan('rpc-sync-client:makeDoRpcSync'));
|
|
70
92
|
/**
|
|
93
|
+
* Routes an update from the sync backend into this client's live pull.
|
|
94
|
+
*
|
|
95
|
+
* Only `ctx` and `payload` go here; `storeId` is for reloading your store on a rebuilt DO (see example).
|
|
71
96
|
*
|
|
72
97
|
* ```ts
|
|
73
98
|
* import { DurableObject } from 'cloudflare:workers'
|
|
@@ -76,27 +101,48 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
76
101
|
* export class MyDurableObject extends DurableObject implements ClientDoWithRpcCallback {
|
|
77
102
|
* // ...
|
|
78
103
|
*
|
|
79
|
-
* async syncUpdateRpc(payload:
|
|
80
|
-
*
|
|
104
|
+
* async syncUpdateRpc(payload: Uint8Array<ArrayBuffer>, storeId: string) {
|
|
105
|
+
* await this.getStore(storeId)
|
|
106
|
+
* return handleSyncUpdateRpc(this.ctx, payload)
|
|
81
107
|
* }
|
|
82
108
|
* }
|
|
83
109
|
* ```
|
|
84
110
|
*/
|
|
85
|
-
export const handleSyncUpdateRpc = (payload) => Effect.gen(function* () {
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
const
|
|
89
|
-
|
|
111
|
+
export const handleSyncUpdateRpc = (ctx, payload) => Effect.gen(function* () {
|
|
112
|
+
const parser = RpcSerialization.msgPack.makeUnsafe();
|
|
113
|
+
const decodedMessage = parser.decode(payload);
|
|
114
|
+
const [response] = Array.isArray(decodedMessage) === true ? decodedMessage.flat(1) : [decodedMessage];
|
|
115
|
+
const decodedPayload = yield* Schema.decodeUnknownEffect(ResponseChunkEncoded)(response);
|
|
116
|
+
const decoded = yield* Schema.decodeUnknownEffect(Schema.toCodecJson(SyncMessage.PullResponse))(decodedPayload.values[0]);
|
|
117
|
+
const pullStreamQueue = pullRoutingFor(ctx).get(decodedPayload.requestId);
|
|
118
|
+
if (pullStreamQueue === undefined) {
|
|
90
119
|
// Case: DO was hibernated, so we need to manually update the store
|
|
91
|
-
yield* Effect.log(`No
|
|
120
|
+
yield* Effect.log(`No pull stream queue found for ${decodedPayload.requestId}`);
|
|
92
121
|
}
|
|
93
122
|
else {
|
|
94
123
|
// Case: DO was still alive, so the existing `pull` will pick up the new events
|
|
95
|
-
yield*
|
|
124
|
+
yield* Queue.offer(pullStreamQueue, decoded);
|
|
96
125
|
}
|
|
97
126
|
}).pipe(Effect.withSpan('rpc-sync-client:rpcCallback'), Effect.tapCauseLogPretty, Effect.runPromise);
|
|
98
127
|
const ResponseChunkEncoded = Schema.Struct({
|
|
99
128
|
requestId: Schema.String,
|
|
100
129
|
values: Schema.Array(Schema.Any),
|
|
101
130
|
});
|
|
131
|
+
/**
|
|
132
|
+
* Per-instance map from a live pull's request id to its response queue, keyed off the client DO's
|
|
133
|
+
* `DurableObjectState` (not a module global) for two independent reasons:
|
|
134
|
+
* - Per-instance: a reconstructed DO starts empty, so a reverse-RPC whose store is gone hits the
|
|
135
|
+
* `handleSyncUpdateRpc` drop branch (the recovery hook) instead of a stale queue that outlived it.
|
|
136
|
+
* - Keyed by request id: a late chunk from a superseded pull generation finds no entry and is
|
|
137
|
+
* dropped here — never reaching `SyncState.merge`, which dies on an event at/below the upstream head.
|
|
138
|
+
*/
|
|
139
|
+
const pullRoutingByInstance = new WeakMap();
|
|
140
|
+
const pullRoutingFor = (ctx) => {
|
|
141
|
+
const existing = pullRoutingByInstance.get(ctx);
|
|
142
|
+
if (existing !== undefined)
|
|
143
|
+
return existing;
|
|
144
|
+
const routing = new Map();
|
|
145
|
+
pullRoutingByInstance.set(ctx, routing);
|
|
146
|
+
return routing;
|
|
147
|
+
};
|
|
102
148
|
//# sourceMappingURL=do-rpc-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"do-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/do-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"do-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/do-rpc-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ export interface HttpSyncOptions {
|
|
|
17
17
|
* How often to poll for new events
|
|
18
18
|
* @default 5 seconds
|
|
19
19
|
*/
|
|
20
|
-
pollInterval?: Duration.
|
|
20
|
+
pollInterval?: Duration.Input;
|
|
21
21
|
};
|
|
22
22
|
ping?: {
|
|
23
23
|
/**
|
|
@@ -28,12 +28,12 @@ export interface HttpSyncOptions {
|
|
|
28
28
|
* How long to wait for a ping response before timing out
|
|
29
29
|
* @default 10 seconds
|
|
30
30
|
*/
|
|
31
|
-
requestTimeout?: Duration.
|
|
31
|
+
requestTimeout?: Duration.Input;
|
|
32
32
|
/**
|
|
33
33
|
* How often to send ping requests
|
|
34
34
|
* @default 10 seconds
|
|
35
35
|
*/
|
|
36
|
-
requestInterval?: Duration.
|
|
36
|
+
requestInterval?: Duration.Input;
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-rpc-client.d.ts","sourceRoot":"","sources":["../../../src/client/transport/http-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"http-rpc-client.d.ts","sourceRoot":"","sources":["../../../src/client/transport/http-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAgB,MAAM,mBAAmB,CAAA;AAG7D,OAAO,EACL,KAAK,QAAQ,EAiBd,MAAM,yBAAyB,CAAA;AAKhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAItE,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,QAAQ,CAAC,EAAE;QACT;;;WAGG;QACH,YAAY,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAA;KAC9B,CAAA;IACD,IAAI,CAAC,EAAE;QACL;;WAEG;QACH,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB;;;WAGG;QACH,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAA;QAC/B;;;WAGG;QACH,eAAe,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAA;KACjC,CAAA;CACF;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GACtB,SAAS,eAAe,KAAG,WAAW,CAAC,sBAAsB,CAAC,YAAY,CA0KvE,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
+
import { splitArrayBySize } from '@livestore/common/sync';
|
|
3
|
+
import { Effect, HttpClient, HttpClientRequest, identity, Layer, Option, ReadonlyArray as EffectArray, RpcClient, RpcSerialization, Schedule, Schema, Semaphore, Stream, Struct, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
4
|
+
import { MAX_HTTP_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from "../../common/constants.js";
|
|
4
5
|
import { SyncHttpRpc } from "../../common/http-rpc-schema.js";
|
|
5
6
|
import { SearchParamsSchema } from "../../common/mod.js";
|
|
6
7
|
/**
|
|
@@ -10,16 +11,16 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
10
11
|
// Based on ping responses
|
|
11
12
|
const isConnected = yield* SubscriptionRef.make(false);
|
|
12
13
|
const livePullInterval = options.livePull?.pollInterval ?? 5_000;
|
|
13
|
-
const urlParamsData = yield* Schema.
|
|
14
|
+
const urlParamsData = yield* Schema.encodeEffect(SearchParamsSchema)({
|
|
14
15
|
storeId,
|
|
15
16
|
payload,
|
|
16
17
|
transport: 'http',
|
|
17
|
-
}).pipe(
|
|
18
|
+
}).pipe(UnknownError.mapToUnknownError);
|
|
18
19
|
const urlParams = UrlParams.fromInput(urlParamsData);
|
|
19
20
|
// Setup HTTP RPC Protocol
|
|
20
21
|
const HttpProtocolLive = RpcClient.layerProtocolHttp({
|
|
21
|
-
url:
|
|
22
|
-
transformClient: HttpClient.mapRequest((request) => request.pipe(HttpClientRequest.setHeaders({
|
|
22
|
+
url: options.url,
|
|
23
|
+
transformClient: HttpClient.mapRequest((request) => request.pipe(HttpClientRequest.appendUrlParams(urlParams), HttpClientRequest.setHeaders({
|
|
23
24
|
...options.headers,
|
|
24
25
|
// Used in CF Worker to identify the store (additionally to storeId embedded in the RPC requests)
|
|
25
26
|
'x-livestore-store-id': storeId,
|
|
@@ -28,44 +29,72 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
28
29
|
const rpcClient = yield* RpcClient.make(SyncHttpRpc).pipe(Effect.provide(HttpProtocolLive));
|
|
29
30
|
const pingTimeout = options.ping?.requestTimeout ?? 10_000;
|
|
30
31
|
const ping = Effect.gen(function* () {
|
|
31
|
-
yield* rpcClient
|
|
32
|
+
yield* rpcClient['SyncHttpRpc.Ping']({ storeId, payload });
|
|
32
33
|
yield* SubscriptionRef.set(isConnected, true);
|
|
33
|
-
}).pipe(
|
|
34
|
+
}).pipe(UnknownError.mapToUnknownError, Effect.timeout(pingTimeout), Effect.catchTag('TimeoutError', () => SubscriptionRef.set(isConnected, false)));
|
|
34
35
|
const pingInterval = options.ping?.requestInterval ?? 10_000;
|
|
35
36
|
if (options.ping?.enabled !== false) {
|
|
36
37
|
// Automatically ping the server to keep the connection alive
|
|
37
38
|
yield* ping.pipe(Effect.repeat(Schedule.spaced(pingInterval)), Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
38
39
|
}
|
|
39
40
|
// Helps already establish a TCP connection to the server
|
|
40
|
-
const connect = ping.pipe(
|
|
41
|
+
const connect = ping.pipe(UnknownError.mapToUnknownError);
|
|
41
42
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper;
|
|
42
43
|
const mapCursor = (cursor) => cursor.pipe(Option.map((a) => ({
|
|
43
44
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
44
45
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
45
46
|
})));
|
|
46
|
-
const pull = (cursor, options) => rpcClient
|
|
47
|
+
const pull = (cursor, options) => rpcClient['SyncHttpRpc.Pull']({
|
|
47
48
|
storeId,
|
|
48
49
|
payload,
|
|
49
50
|
cursor: mapCursor(cursor),
|
|
50
|
-
}).pipe(options?.live
|
|
51
|
+
}).pipe(options?.live === true
|
|
51
52
|
? // Phase 2: Simulate `live` pull by polling for new events
|
|
52
53
|
Stream.concatWithLastElement((lastElement) => {
|
|
53
|
-
const initialPhase2Cursor = lastElement.pipe(Option.flatMap((_) => Option.
|
|
54
|
-
return Stream.
|
|
54
|
+
const initialPhase2Cursor = lastElement.pipe(Option.flatMap((_) => Option.fromNullishOr(_.batch.at(-1)?.eventEncoded.seqNum)), Option.map((eventSequenceNumber) => ({ eventSequenceNumber })), Option.orElse(() => cursor), mapCursor);
|
|
55
|
+
return Stream.paginate(initialPhase2Cursor, (currentCursor) => Effect.gen(function* () {
|
|
55
56
|
yield* Effect.sleep(livePullInterval);
|
|
56
|
-
const items = yield* rpcClient
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const items = yield* rpcClient['SyncHttpRpc.Pull']({
|
|
58
|
+
storeId,
|
|
59
|
+
payload,
|
|
60
|
+
cursor: currentCursor,
|
|
61
|
+
}).pipe(Stream.runCollect);
|
|
62
|
+
const nextCursor = EffectArray.last(items).pipe(Option.flatMap((item) => Option.fromNullishOr(item.batch.at(-1)?.eventEncoded.seqNum)), Option.map((eventSequenceNumber) => ({ eventSequenceNumber })), Option.orElse(() => currentCursor), mapCursor);
|
|
63
|
+
const page = [
|
|
64
|
+
items,
|
|
65
|
+
Option.some(nextCursor),
|
|
66
|
+
];
|
|
67
|
+
return page;
|
|
59
68
|
}));
|
|
60
69
|
})
|
|
61
|
-
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) =>
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => Struct.omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
71
|
+
? cause
|
|
72
|
+
: new UnknownError({ cause })), Stream.withSpan('http-sync-client:pull'));
|
|
73
|
+
const pushSemaphore = yield* Semaphore.make(1);
|
|
74
|
+
const push = Effect.fn('http-sync-client:push')(function* (batch) {
|
|
64
75
|
if (batch.length === 0) {
|
|
65
76
|
return;
|
|
66
77
|
}
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
const backendId = backendIdHelper.get();
|
|
79
|
+
if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const batchChunks = yield* splitArrayBySize({
|
|
83
|
+
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
84
|
+
maxBytes: MAX_HTTP_REQUEST_BYTES,
|
|
85
|
+
encode: (items) => ({
|
|
86
|
+
batch: items,
|
|
87
|
+
storeId,
|
|
88
|
+
payload,
|
|
89
|
+
backendId,
|
|
90
|
+
}),
|
|
91
|
+
})(batch).pipe(Effect.mapError((cause) => new UnknownError({ cause })));
|
|
92
|
+
for (const batchChunk of batchChunks) {
|
|
93
|
+
yield* rpcClient['SyncHttpRpc.Push']({ storeId, payload, batch: batchChunk, backendId });
|
|
94
|
+
}
|
|
95
|
+
}, pushSemaphore.withPermits(1), Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
96
|
+
? cause
|
|
97
|
+
: new UnknownError({ cause })));
|
|
69
98
|
return SyncBackend.of({
|
|
70
99
|
connect,
|
|
71
100
|
isConnected,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/http-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"http-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/http-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAE7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAEL,MAAM,EACN,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,KAAK,EACL,MAAM,EACN,aAAa,IAAI,WAAW,EAC5B,SAAS,EACT,gBAAgB,EAChB,QAAQ,EACR,MAAM,EACN,SAAS,EACT,MAAM,EACN,MAAM,EACN,eAAe,EACf,SAAS,GACV,MAAM,yBAAyB,CAAA;AAEhC,OAAO,EAAE,sBAAsB,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAA;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AAyCxD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GACvB,CAAC,OAAwB,EAAoD,EAAE,CAC/E,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CACvB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,0BAA0B;IAC1B,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAEtD,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,EAAE,YAAY,IAAI,KAAK,CAAA;IAEhE,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;QACnE,OAAO;QACP,OAAO;QACP,SAAS,EAAE,MAAM;KAClB,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAA;IAEvC,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,aAAa,CAAC,CAAA;IAEpD,0BAA0B;IAC1B,MAAM,gBAAgB,GAAG,SAAS,CAAC,iBAAiB,CAAC;QACnD,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,eAAe,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,EAAE,CACjD,OAAO,CAAC,IAAI,CACV,iBAAiB,CAAC,eAAe,CAAC,SAAS,CAAC,EAC5C,iBAAiB,CAAC,UAAU,CAAC;YAC3B,GAAG,OAAO,CAAC,OAAO;YAClB,iGAAiG;YACjG,sBAAsB,EAAE,OAAO;SAChC,CAAC,CACH,CACF;KACF,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAA;IAElD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAA;IAE3F,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,EAAE,cAAc,IAAI,MAAM,CAAA;IAE1D,MAAM,IAAI,GAAkD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC9E,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QAE1D,KAAK,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAC,IAAI,CACL,YAAY,CAAC,iBAAiB,EAC9B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAC3B,MAAM,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAC/E,CAAA;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,EAAE,eAAe,IAAI,MAAM,CAAA;IAE5D,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;QACpC,6DAA6D;QAC7D,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;IAC7G,CAAC;IAED,yDAAyD;IACzD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,CAAA;IAEzD,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAA;IAE9D,MAAM,SAAS,GAAG,CAAC,MAAsD,EAAE,EAAE,CAC3E,MAAM,CAAC,IAAI,CACT,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACjB,mBAAmB,EAAE,CAAC,CAAC,mBAAsD;QAC7E,SAAS,EAAE,eAAe,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;KACzD,CAAC,CAAC,CACJ,CAAA;IAEH,MAAM,IAAI,GAAkD,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAC9E,SAAS,CAAC,kBAAkB,CAAC,CAAC;QAC5B,OAAO;QACP,OAAO;QACP,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;KAC1B,CAAC,CAAC,IAAI,CACL,OAAO,EAAE,IAAI,KAAK,IAAI;QACpB,CAAC,CAAC,0DAA0D;YAC1D,MAAM,CAAC,qBAAqB,CAAC,CAAC,WAAW,EAAE,EAAE;gBAC3C,MAAM,mBAAmB,GAAG,WAAW,CAAC,IAAI,CAC1C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,EAChF,MAAM,CAAC,GAAG,CAAC,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,EAC9D,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAC3B,SAAS,CACV,CAAA;gBAED,OAAO,MAAM,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC,aAAa,EAAE,EAAE,CAC5D,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;oBAClB,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;oBAErC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;wBACjD,OAAO;wBACP,OAAO;wBACP,MAAM,EAAE,aAAa;qBACtB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;oBAE1B,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,EACtF,MAAM,CAAC,GAAG,CAAC,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC,EAC9D,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,EAClC,SAAS,CACV,CAAA;oBAED,MAAM,IAAI,GAAiE;wBACzE,KAAK;wBACL,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;qBACxB,CAAA;oBACD,OAAO,IAAI,CAAA;gBACb,CAAC,CAAC,CACH,CAAA;YACH,CAAC,CAAC;QACJ,CAAC,CAAC,QAAQ,EACZ,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,EAC3D,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,EACpD,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB;QACtE,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAChC,EACD,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CACzC,CAAA;IAEH,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAE9C,MAAM,IAAI,GAAkD,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAC5F,QAAQ,CAAC,EAAE,KAAK;QACd,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,OAAM;QACR,CAAC;QAED,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,EAAE,CAAA;QACvC,IAAI,WAAW,CAAC,uBAAuB,CAAC,KAAK,CAAC,KAAK,KAAK,EAAE,CAAC;YACzD,OAAM;QACR,CAAC;QAED,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,gBAAgB,CAAC;YAC1C,QAAQ,EAAE,2BAA2B;YACrC,QAAQ,EAAE,sBAAsB;YAChC,MAAM,EAAE,CAAC,KAAmC,EAAE,EAAE,CAAC,CAAC;gBAChD,KAAK,EAAE,KAAK;gBACZ,OAAO;gBACP,OAAO;gBACP,SAAS;aACV,CAAC;SACH,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;QAEvE,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;YACrC,KAAK,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAA;QAC1F,CAAC;IACH,CAAC,EACD,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC,EAC5B,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CACxB,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB;QAC3G,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,IAAI,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,CAChC,CACF,CAAA;IAED,OAAO,WAAW,CAAC,EAAE,CAAC;QACpB,OAAO;QACP,WAAW;QACX,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,QAAQ,EAAE;YACR,IAAI,EAAE,yBAAyB;YAC/B,WAAW,EAAE,sDAAsD;YACnE,QAAQ,EAAE,MAAM;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAI;YACvB,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SyncBackend } from '@livestore/common';
|
|
2
|
-
import {
|
|
2
|
+
import { Duration, Effect, type Scope } from '@livestore/utils/effect';
|
|
3
|
+
import type { WebSocket } from '@livestore/utils/effect/browser';
|
|
3
4
|
import type { SyncMetadata } from '../../common/sync-message-types.ts';
|
|
4
5
|
export interface WsSyncOptions {
|
|
5
6
|
/**
|
|
@@ -24,12 +25,12 @@ export interface WsSyncOptions {
|
|
|
24
25
|
* How long to wait for a ping response before timing out
|
|
25
26
|
* @default 10 seconds
|
|
26
27
|
*/
|
|
27
|
-
requestTimeout?: Duration.
|
|
28
|
+
requestTimeout?: Duration.Input;
|
|
28
29
|
/**
|
|
29
30
|
* How often to send ping requests
|
|
30
31
|
* @default 10 seconds
|
|
31
32
|
*/
|
|
32
|
-
requestInterval?: Duration.
|
|
33
|
+
requestInterval?: Duration.Input;
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-rpc-client.d.ts","sourceRoot":"","sources":["../../../src/client/transport/ws-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ws-rpc-client.d.ts","sourceRoot":"","sources":["../../../src/client/transport/ws-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,WAAW,EAAgB,MAAM,mBAAmB,CAAA;AAG7E,OAAO,EACL,QAAQ,EACR,MAAM,EAQN,KAAK,KAAK,EAMX,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAIhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAGtE,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,EAAE,SAAS,CAAC,cAAc,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;IAChH,IAAI,CAAC,EAAE;QACL;;WAEG;QACH,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB;;;WAGG;QACH,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAA;QAC/B;;;WAGG;QACH,eAAe,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAA;KACjC,CAAA;CACF;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GACpB,SAAS,aAAa,KAAG,WAAW,CAAC,sBAAsB,CAAC,YAAY,CA0IrE,CAAA"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { Effect, Layer, Option, RpcClient, RpcSerialization, Schedule, Schema, Socket, Stream, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
1
|
+
import { IsOfflineError, SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
+
import { splitArrayBySize } from '@livestore/common/sync';
|
|
3
|
+
import { Duration, Effect, Layer, Option, ReadonlyArray as EffectArray, RpcClient, RpcSerialization, Schedule, Schema, Socket, Stream, Struct, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
4
|
+
import { MAX_PUSH_EVENTS_PER_REQUEST, MAX_WS_MESSAGE_BYTES } from "../../common/constants.js";
|
|
4
5
|
import { SearchParamsSchema } from "../../common/mod.js";
|
|
5
6
|
import { SyncWsRpc } from "../../common/ws-rpc-schema.js";
|
|
6
7
|
/**
|
|
@@ -13,11 +14,11 @@ import { SyncWsRpc } from "../../common/ws-rpc-schema.js";
|
|
|
13
14
|
* const syncBackend = makeWsSync({ url: 'wss://sync.example.com' })
|
|
14
15
|
*/
|
|
15
16
|
export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(function* () {
|
|
16
|
-
const urlParamsData = yield* Schema.
|
|
17
|
+
const urlParamsData = yield* Schema.encodeEffect(SearchParamsSchema)({
|
|
17
18
|
storeId,
|
|
18
19
|
payload,
|
|
19
20
|
transport: 'ws',
|
|
20
|
-
}).pipe(
|
|
21
|
+
}).pipe(UnknownError.mapToUnknownError);
|
|
21
22
|
const urlParams = UrlParams.fromInput(urlParamsData);
|
|
22
23
|
const wsUrl = `${options.url}?${UrlParams.toString(urlParams)}`;
|
|
23
24
|
const isConnected = yield* SubscriptionRef.make(false);
|
|
@@ -29,13 +30,13 @@ export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(func
|
|
|
29
30
|
// }
|
|
30
31
|
// TODO bring this back in a cross-platform way
|
|
31
32
|
// if (navigator.onLine === false) {
|
|
32
|
-
// yield* Effect.
|
|
33
|
+
// yield* Effect.callback((cb) => self.addEventListener('online', () => cb(Effect.void)))
|
|
33
34
|
// }
|
|
34
35
|
const pingInterval = options.ping?.requestInterval ?? 10_000;
|
|
35
36
|
const ProtocolLive = RpcClient.layerProtocolSocketWithIsConnected({
|
|
36
37
|
isConnected,
|
|
37
|
-
retryTransientErrors: Schedule.
|
|
38
|
-
pingSchedule: Schedule.
|
|
38
|
+
retryTransientErrors: Schedule.exponential('1 seconds').pipe(Schedule.modifyDelay(({ duration }) => Effect.succeed(Duration.min(duration, Duration.seconds(30)))), Schedule.jittered),
|
|
39
|
+
pingSchedule: Schedule.recurs(1).pipe(Schedule.concat(Schedule.fixed(pingInterval))),
|
|
39
40
|
url: wsUrl,
|
|
40
41
|
}).pipe(Layer.provide(Socket.layerWebSocket(wsUrl)), Layer.provide(Socket.layerWebSocketConstructorGlobal), Layer.provide(RpcSerialization.layerJson));
|
|
41
42
|
// Warning: we need to build the layer here eagerly to tie it to the scope
|
|
@@ -47,37 +48,54 @@ export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(func
|
|
|
47
48
|
const pinger = yield* RpcClient.SocketPinger.pipe(Effect.provide(ctx));
|
|
48
49
|
yield* pinger.ping;
|
|
49
50
|
yield* SubscriptionRef.set(isConnected, true);
|
|
50
|
-
}).pipe(Effect.timeout(pingTimeout), Effect.catchTag('
|
|
51
|
+
}).pipe(Effect.timeout(pingTimeout), Effect.catchTag('TimeoutError', () => SubscriptionRef.set(isConnected, false)), UnknownError.mapToUnknownError, Effect.withSpan('ping'));
|
|
51
52
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper;
|
|
52
53
|
return SyncBackend.of({
|
|
53
54
|
isConnected,
|
|
54
55
|
connect: ping,
|
|
55
|
-
pull: (cursor, options) => rpcClient
|
|
56
|
+
pull: (cursor, options) => rpcClient['SyncWsRpc.Pull']({
|
|
56
57
|
storeId,
|
|
57
58
|
payload,
|
|
58
59
|
cursor: cursor.pipe(Option.map((a) => ({
|
|
59
60
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
60
61
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
61
62
|
}))),
|
|
62
|
-
live: options?.live
|
|
63
|
-
}).pipe(Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'RpcClientError' && Socket.isSocketError(cause.cause)
|
|
63
|
+
live: options?.live === true,
|
|
64
|
+
}).pipe(Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => Struct.omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'RpcClientError' && Socket.isSocketError(cause.cause) === true
|
|
64
65
|
? new IsOfflineError({ cause: cause.cause })
|
|
65
|
-
: cause._tag === '
|
|
66
|
+
: cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
66
67
|
? cause
|
|
67
|
-
:
|
|
68
|
-
push:
|
|
69
|
-
if (batch.length === 0)
|
|
68
|
+
: new UnknownError({ cause })), Stream.withSpan('pull')),
|
|
69
|
+
push: Effect.fn('push')(function* (batch) {
|
|
70
|
+
if (batch.length === 0)
|
|
70
71
|
return;
|
|
71
|
-
|
|
72
|
-
return yield* rpcClient.SyncWsRpc.Push({
|
|
72
|
+
const encodePayload = (batch) => ({
|
|
73
73
|
storeId,
|
|
74
74
|
payload,
|
|
75
75
|
batch,
|
|
76
76
|
backendId: backendIdHelper.get(),
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
});
|
|
78
|
+
if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const batchChunks = yield* splitArrayBySize({
|
|
82
|
+
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
83
|
+
maxBytes: MAX_WS_MESSAGE_BYTES,
|
|
84
|
+
encode: encodePayload,
|
|
85
|
+
})(batch).pipe(Effect.mapError((cause) => new UnknownError({ cause })));
|
|
86
|
+
for (const batchChunk of batchChunks) {
|
|
87
|
+
yield* rpcClient['SyncWsRpc.Push']({
|
|
88
|
+
storeId,
|
|
89
|
+
payload,
|
|
90
|
+
batch: batchChunk,
|
|
91
|
+
backendId: backendIdHelper.get(),
|
|
92
|
+
}).pipe(Effect.mapError((cause) => cause._tag === 'UnknownError' ||
|
|
93
|
+
cause._tag === 'ServerAheadError' ||
|
|
94
|
+
cause._tag === 'BackendIdMismatchError'
|
|
95
|
+
? cause
|
|
96
|
+
: new UnknownError({ cause })));
|
|
97
|
+
}
|
|
98
|
+
}),
|
|
81
99
|
ping,
|
|
82
100
|
metadata: {
|
|
83
101
|
name: '@livestore/cf-sync',
|