@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.
- 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 +24 -11
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +22 -18
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +43 -33
- package/dist/cf-worker/do/layer.js.map +1 -1
- package/dist/cf-worker/do/pull.d.ts +3 -3
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +17 -18
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +16 -3
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +69 -49
- 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 +34 -46
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js +1 -1
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +7 -6
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +26 -14
- 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 +21 -19
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +2 -2
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.js +7 -7
- 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 -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 +9 -9
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +22 -19
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +13 -11
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +6 -6
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +16 -14
- 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 +55 -26
- 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 +30 -21
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts +3 -3
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +20 -16
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/do-rpc-schema.d.ts +38 -39
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +3 -3
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +36 -37
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +5 -5
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/mod.d.ts +4 -5
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +3 -4
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +116 -133
- package/dist/common/sync-message-types.d.ts.map +1 -1
- package/dist/common/sync-message-types.js +26 -14
- package/dist/common/sync-message-types.js.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +33 -34
- package/dist/common/ws-rpc-schema.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.js +4 -4
- package/dist/common/ws-rpc-schema.js.map +1 -1
- package/package.json +21 -37
- package/src/cf-worker/do/durable-object.ts +45 -36
- package/src/cf-worker/do/layer.ts +142 -99
- package/src/cf-worker/do/pull.ts +28 -28
- package/src/cf-worker/do/push.test.ts +40 -0
- package/src/cf-worker/do/push.ts +138 -115
- package/src/cf-worker/do/sqlite.ts +1 -1
- package/src/cf-worker/do/sync-storage.ts +34 -21
- package/src/cf-worker/do/transport/do-rpc-server.ts +23 -34
- package/src/cf-worker/do/transport/http-rpc-server.ts +7 -10
- package/src/cf-worker/do/transport/ws-rpc-server.ts +10 -10
- package/src/cf-worker/shared.ts +18 -13
- package/src/cf-worker/worker.ts +21 -22
- package/src/client/transport/do-rpc-client.ts +82 -40
- package/src/client/transport/http-rpc-client.ts +47 -37
- package/src/client/transport/ws-rpc-client.ts +29 -26
- package/src/common/do-rpc-schema.ts +3 -3
- package/src/common/http-rpc-schema.ts +5 -5
- package/src/common/mod.ts +3 -4
- package/src/common/sync-message-types.ts +16 -16
- package/src/common/ws-rpc-schema.ts +4 -4
|
@@ -15,7 +15,7 @@ export type ValidatePayloadContext = {
|
|
|
15
15
|
* Options accepted by {@link makeWorker}. The Durable Object binding has to be
|
|
16
16
|
* supplied explicitly so we never fall back to deprecated defaults when Cloudflare config changes.
|
|
17
17
|
*/
|
|
18
|
-
export type MakeWorkerOptions<TEnv extends Env = Env, TSyncPayload = Schema.
|
|
18
|
+
export type MakeWorkerOptions<TEnv extends Env = Env, TSyncPayload = Schema.Json> = {
|
|
19
19
|
/**
|
|
20
20
|
* Binding name of the sync Durable Object declared in wrangler config.
|
|
21
21
|
*/
|
|
@@ -24,7 +24,7 @@ export type MakeWorkerOptions<TEnv extends Env = Env, TSyncPayload = Schema.Json
|
|
|
24
24
|
* Optionally pass a schema to decode the client-provided payload into a typed object
|
|
25
25
|
* before calling {@link validatePayload}. If omitted, the raw JSON value is forwarded.
|
|
26
26
|
*/
|
|
27
|
-
syncPayloadSchema?: Schema.
|
|
27
|
+
syncPayloadSchema?: Schema.Decoder<TSyncPayload>;
|
|
28
28
|
/**
|
|
29
29
|
* Validates the (optionally decoded) payload during WebSocket connection establishment.
|
|
30
30
|
* If {@link syncPayloadSchema} is provided, `payload` will be of the schema's inferred type.
|
|
@@ -54,13 +54,13 @@ export type MakeWorkerOptions<TEnv extends Env = Env, TSyncPayload = Schema.Json
|
|
|
54
54
|
* For more complex setups prefer implementing a custom `fetch` and call {@link handleSyncRequest}
|
|
55
55
|
* from the branch that handles LiveStore sync requests.
|
|
56
56
|
*/
|
|
57
|
-
export declare const makeWorker: <TEnv extends Env = Env, TDurableObjectRpc extends CfTypes.Rpc.DurableObjectBranded | undefined = undefined, TSyncPayload = Schema.
|
|
57
|
+
export declare const makeWorker: <TEnv extends Env = Env, TDurableObjectRpc extends CfTypes.Rpc.DurableObjectBranded | undefined = undefined, TSyncPayload = Schema.Json>(options: MakeWorkerOptions<TEnv, TSyncPayload>) => CFWorker<TEnv, TDurableObjectRpc>;
|
|
58
58
|
/**
|
|
59
59
|
* Handles LiveStore sync requests (e.g. with search params `?storeId=...&transport=...`).
|
|
60
60
|
*
|
|
61
61
|
* @example Token-based authentication
|
|
62
62
|
* ```ts
|
|
63
|
-
* const validatePayload = (payload: Schema.
|
|
63
|
+
* const validatePayload = (payload: Schema.Json | undefined, context: { storeId: string }) => {
|
|
64
64
|
* if (payload?.authToken !== 'insecure-token-change-me') {
|
|
65
65
|
* throw new Error('Invalid auth token')
|
|
66
66
|
* }
|
|
@@ -69,7 +69,7 @@ export declare const makeWorker: <TEnv extends Env = Env, TDurableObjectRpc exte
|
|
|
69
69
|
*
|
|
70
70
|
* @example Cookie-based authentication
|
|
71
71
|
* ```ts
|
|
72
|
-
* const validatePayload = async (payload: Schema.
|
|
72
|
+
* const validatePayload = async (payload: Schema.Json | undefined, { storeId, headers }) => {
|
|
73
73
|
* const cookie = headers.get('cookie')
|
|
74
74
|
* const session = await validateSessionFromCookie(cookie)
|
|
75
75
|
* if (!session) throw new Error('Unauthorized')
|
|
@@ -78,7 +78,7 @@ export declare const makeWorker: <TEnv extends Env = Env, TDurableObjectRpc exte
|
|
|
78
78
|
*
|
|
79
79
|
* @throws {UnknownError} If the payload is invalid
|
|
80
80
|
*/
|
|
81
|
-
export declare const handleSyncRequest: <TEnv extends Env = Env, TDurableObjectRpc extends CfTypes.Rpc.DurableObjectBranded | undefined = undefined, CFHostMetada = unknown, TSyncPayload = Schema.
|
|
81
|
+
export declare const handleSyncRequest: <TEnv extends Env = Env, TDurableObjectRpc extends CfTypes.Rpc.DurableObjectBranded | undefined = undefined, CFHostMetada = unknown, TSyncPayload = Schema.Json>({ request, searchParams: { storeId, payload, transport }, env: explicitlyProvidedEnv, syncBackendBinding, headers, validatePayload, syncPayloadSchema, }: {
|
|
82
82
|
request: CfTypes.Request<CFHostMetada>;
|
|
83
83
|
searchParams: SearchParams;
|
|
84
84
|
env?: TEnv | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/cf-worker/worker.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/cf-worker/worker.ts"],"names":[],"mappings":"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"}
|
package/dist/cf-worker/worker.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { env as importedEnv } from 'cloudflare:workers';
|
|
2
2
|
import { UnknownError } from '@livestore/common';
|
|
3
|
-
import {
|
|
3
|
+
import { CfDeclare } from '@livestore/common-cf/declare';
|
|
4
|
+
import { Effect, Result, Schema } from '@livestore/utils/effect';
|
|
4
5
|
import { matchSyncRequest } from "./shared.js";
|
|
6
|
+
const Response = CfDeclare.Response;
|
|
5
7
|
/**
|
|
6
8
|
* Produces a Cloudflare Worker `fetch` handler that delegates sync traffic to the
|
|
7
9
|
* Durable Object identified by `syncBackendBinding`.
|
|
@@ -72,7 +74,7 @@ const requestHeadersToMap = (request) => {
|
|
|
72
74
|
*
|
|
73
75
|
* @example Token-based authentication
|
|
74
76
|
* ```ts
|
|
75
|
-
* const validatePayload = (payload: Schema.
|
|
77
|
+
* const validatePayload = (payload: Schema.Json | undefined, context: { storeId: string }) => {
|
|
76
78
|
* if (payload?.authToken !== 'insecure-token-change-me') {
|
|
77
79
|
* throw new Error('Invalid auth token')
|
|
78
80
|
* }
|
|
@@ -81,7 +83,7 @@ const requestHeadersToMap = (request) => {
|
|
|
81
83
|
*
|
|
82
84
|
* @example Cookie-based authentication
|
|
83
85
|
* ```ts
|
|
84
|
-
* const validatePayload = async (payload: Schema.
|
|
86
|
+
* const validatePayload = async (payload: Schema.Json | undefined, { storeId, headers }) => {
|
|
85
87
|
* const cookie = headers.get('cookie')
|
|
86
88
|
* const session = await validateSessionFromCookie(cookie)
|
|
87
89
|
* if (!session) throw new Error('Unauthorized')
|
|
@@ -97,23 +99,23 @@ export const handleSyncRequest = ({ request, searchParams: { storeId, payload, t
|
|
|
97
99
|
// Always decode with the supplied schema when present, even if payload is undefined.
|
|
98
100
|
// This ensures required payloads are enforced by the schema.
|
|
99
101
|
if (syncPayloadSchema !== undefined) {
|
|
100
|
-
const
|
|
101
|
-
if (
|
|
102
|
-
const message =
|
|
102
|
+
const decodedResult = Schema.decodeUnknownResult(syncPayloadSchema)(payload);
|
|
103
|
+
if (Result.isFailure(decodedResult) === true) {
|
|
104
|
+
const message = decodedResult.failure.toString();
|
|
103
105
|
console.error('Invalid payload (decode failed)', message);
|
|
104
106
|
return new Response(message, { status: 400, ...(headers !== undefined ? { headers } : {}) });
|
|
105
107
|
}
|
|
106
|
-
const result = yield* Effect.promise(async () => validatePayload(
|
|
107
|
-
if (result
|
|
108
|
-
console.error('Invalid payload (validation failed)', result.
|
|
109
|
-
return new Response(result.
|
|
108
|
+
const result = yield* Effect.promise(async () => validatePayload(decodedResult.success, { storeId, headers: requestHeaders })).pipe(UnknownError.mapToUnknownError, Effect.result);
|
|
109
|
+
if (Result.isFailure(result) === true) {
|
|
110
|
+
console.error('Invalid payload (validation failed)', result.failure);
|
|
111
|
+
return new Response(result.failure.toString(), { status: 400, ...(headers !== undefined ? { headers } : {}) });
|
|
110
112
|
}
|
|
111
113
|
}
|
|
112
114
|
else {
|
|
113
|
-
const result = yield* Effect.promise(async () => validatePayload(payload, { storeId, headers: requestHeaders })).pipe(UnknownError.mapToUnknownError, Effect.
|
|
114
|
-
if (result
|
|
115
|
-
console.error('Invalid payload (validation failed)', result.
|
|
116
|
-
return new Response(result.
|
|
115
|
+
const result = yield* Effect.promise(async () => validatePayload(payload, { storeId, headers: requestHeaders })).pipe(UnknownError.mapToUnknownError, Effect.result);
|
|
116
|
+
if (Result.isFailure(result) === true) {
|
|
117
|
+
console.error('Invalid payload (validation failed)', result.failure);
|
|
118
|
+
return new Response(result.failure.toString(), { status: 400, ...(headers !== undefined ? { headers } : {}) });
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/cf-worker/worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;
|
|
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,EAAE,WAAW,EAAgB,MAAM,mBAAmB,CAAA;
|
|
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,18 +1,17 @@
|
|
|
1
1
|
import { SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
-
import { splitChunkBySize } from '@livestore/common/sync';
|
|
3
2
|
import { layerProtocolDurableObject } from '@livestore/common-cf';
|
|
4
|
-
import {
|
|
5
|
-
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
6
|
import { MAX_DO_RPC_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from "../../common/constants.js";
|
|
7
7
|
import { SyncDoRpc } from "../../common/do-rpc-schema.js";
|
|
8
8
|
import { SyncMessage } from "../../common/mod.js";
|
|
9
|
-
const requestIdMailboxMap = new Map();
|
|
10
9
|
/**
|
|
11
10
|
* Creates a sync backend that uses Durable Object RPC to communicate with the sync backend.
|
|
12
11
|
*
|
|
13
12
|
* Used internally by `@livestore/adapter-cf` to connect to the sync backend.
|
|
14
13
|
*/
|
|
15
|
-
export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ storeId, payload }) => Effect.gen(function* () {
|
|
14
|
+
export const makeDoRpcSync = ({ syncBackendStub, durableObjectState, durableObjectContext, }) => ({ storeId, payload }) => Effect.gen(function* () {
|
|
16
15
|
const isConnected = yield* SubscriptionRef.make(true);
|
|
17
16
|
const ProtocolLive = layerProtocolDurableObject({
|
|
18
17
|
callRpc: (payload) => syncBackendStub.rpc(payload),
|
|
@@ -23,7 +22,7 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
23
22
|
// Nothing to do here
|
|
24
23
|
const connect = Effect.void;
|
|
25
24
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper;
|
|
26
|
-
const pull = (cursor, options) => rpcClient
|
|
25
|
+
const pull = (cursor, options) => rpcClient['SyncDoRpc.Pull']({
|
|
27
26
|
cursor: cursor.pipe(Option.map((a) => ({
|
|
28
27
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
29
28
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
@@ -34,11 +33,15 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
34
33
|
? Stream.concatWithLastElement((res) => Effect.gen(function* () {
|
|
35
34
|
if (res._tag === 'None')
|
|
36
35
|
return shouldNeverHappen('There should at least be a no-more page info response');
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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'
|
|
42
45
|
? cause
|
|
43
46
|
: new UnknownError({ cause })), Stream.withSpan('rpc-sync-client:pull'));
|
|
44
47
|
const push = Effect.fn('rpc-sync-client:push')(function* (batch) {
|
|
@@ -46,7 +49,10 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
46
49
|
return;
|
|
47
50
|
}
|
|
48
51
|
const backendId = backendIdHelper.get();
|
|
49
|
-
|
|
52
|
+
if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const batchChunks = yield* splitArrayBySize({
|
|
50
56
|
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
51
57
|
maxBytes: MAX_DO_RPC_REQUEST_BYTES,
|
|
52
58
|
encode: (items) => ({
|
|
@@ -54,15 +60,14 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
54
60
|
storeId,
|
|
55
61
|
backendId,
|
|
56
62
|
}),
|
|
57
|
-
})
|
|
58
|
-
for (const
|
|
59
|
-
|
|
60
|
-
yield* rpcClient.SyncDoRpc.Push({ batch: chunkArray, storeId, backendId });
|
|
63
|
+
})(batch).pipe(Effect.mapError((cause) => new UnknownError({ cause })));
|
|
64
|
+
for (const batchChunk of batchChunks) {
|
|
65
|
+
yield* rpcClient['SyncDoRpc.Push']({ batch: batchChunk, storeId, backendId });
|
|
61
66
|
}
|
|
62
67
|
}, Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
63
68
|
? cause
|
|
64
69
|
: new UnknownError({ cause })));
|
|
65
|
-
const ping = rpcClient
|
|
70
|
+
const ping = rpcClient['SyncDoRpc.Ping']({
|
|
66
71
|
storeId,
|
|
67
72
|
payload,
|
|
68
73
|
}).pipe(UnknownError.mapToUnknownError, Effect.withSpan('rpc-sync-client:ping'));
|
|
@@ -85,6 +90,9 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
85
90
|
});
|
|
86
91
|
}).pipe(Effect.withSpan('rpc-sync-client:makeDoRpcSync'));
|
|
87
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).
|
|
88
96
|
*
|
|
89
97
|
* ```ts
|
|
90
98
|
* import { DurableObject } from 'cloudflare:workers'
|
|
@@ -93,27 +101,48 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
93
101
|
* export class MyDurableObject extends DurableObject implements ClientDoWithRpcCallback {
|
|
94
102
|
* // ...
|
|
95
103
|
*
|
|
96
|
-
* async syncUpdateRpc(payload:
|
|
97
|
-
*
|
|
104
|
+
* async syncUpdateRpc(payload: Uint8Array<ArrayBuffer>, storeId: string) {
|
|
105
|
+
* await this.getStore(storeId)
|
|
106
|
+
* return handleSyncUpdateRpc(this.ctx, payload)
|
|
98
107
|
* }
|
|
99
108
|
* }
|
|
100
109
|
* ```
|
|
101
110
|
*/
|
|
102
|
-
export const handleSyncUpdateRpc = (payload) => Effect.gen(function* () {
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
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) {
|
|
107
119
|
// Case: DO was hibernated, so we need to manually update the store
|
|
108
|
-
yield* Effect.log(`No
|
|
120
|
+
yield* Effect.log(`No pull stream queue found for ${decodedPayload.requestId}`);
|
|
109
121
|
}
|
|
110
122
|
else {
|
|
111
123
|
// Case: DO was still alive, so the existing `pull` will pick up the new events
|
|
112
|
-
yield*
|
|
124
|
+
yield* Queue.offer(pullStreamQueue, decoded);
|
|
113
125
|
}
|
|
114
126
|
}).pipe(Effect.withSpan('rpc-sync-client:rpcCallback'), Effect.tapCauseLogPretty, Effect.runPromise);
|
|
115
127
|
const ResponseChunkEncoded = Schema.Struct({
|
|
116
128
|
requestId: Schema.String,
|
|
117
129
|
values: Schema.Array(Schema.Any),
|
|
118
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
|
+
};
|
|
119
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,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,
|
|
1
|
+
{"version":3,"file":"do-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/do-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC7D,OAAO,EAAgB,0BAA0B,EAAE,MAAM,sBAAsB,CAAA;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EACL,MAAM,EACN,QAAQ,EACR,KAAK,EACL,MAAM,EACN,KAAK,EACL,aAAa,IAAI,WAAW,EAC5B,SAAS,EACT,gBAAgB,EAChB,MAAM,EACN,MAAM,EACN,MAAM,EACN,eAAe,GAChB,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAA;AACjG,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAA;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAwBjD;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GACxB,CAAC,EACC,eAAe,EACf,kBAAkB,EAClB,oBAAoB,GACH,EAAoD,EAAE,CACzE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CACvB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAErD,MAAM,YAAY,GAAG,0BAA0B,CAAC;QAC9C,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;QAClD,aAAa,EAAE,oBAAoB;KACpC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAA;IAElD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IAEhD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;IAEhF,qBAAqB;IACrB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAA;IAE3B,MAAM,eAAe,GAAG,KAAK,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAA;IAE9D,MAAM,IAAI,GAAkD,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAC9E,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC,IAAI,CACjB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjB,mBAAmB,EAAE,CAAC,CAAC,mBAAmB;YAC1C,SAAS,EAAE,eAAe,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;SACzD,CAAC,CAAC,CACJ;QACD,OAAO;QACP,UAAU,EAAE,OAAO,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC,SAAS;KACzF,CAAC,CAAC,IAAI,CACL,OAAO,EAAE,IAAI,KAAK,IAAI;QACpB,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,GAAG,EAAE,EAAE,CACnC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YAClB,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM;gBACrB,OAAO,iBAAiB,CAAC,uDAAuD,CAAC,CAAA;YAEnF,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAA;YACxC,MAAM,OAAO,GAAG,cAAc,CAAC,kBAAkB,CAAC,CAAA;YAElD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,EAA4B,EAAE,CAAC,KAAK,EAAE,EAAE;YAChG,kFAAkF;YAClF,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CACzF,CAAA;YAED,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAA;YAE7B,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;QAChC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CACvB;QACH,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,sBAAsB,CAAC,CACxC,CAAA;IAEH,MAAM,IAAI,GAA2D,MAAM,CAAC,EAAE,CAAC,sBAAsB,CAAC,CACpG,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,wBAAwB;YAClC,MAAM,EAAE,CAAC,KAAmC,EAAE,EAAE,CAAC,CAAC;gBAChD,KAAK,EAAE,KAAK;gBACZ,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,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;QAC/E,CAAC;IACH,CAAC,EACD,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,MAAM,IAAI,GAA2D,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC/F,OAAO;QACP,OAAO;KACR,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAEhF,OAAO,WAAW,CAAC,EAAE,CAAC;QACpB,OAAO;QACP,WAAW;QACX,IAAI;QACJ,IAAI;QACJ,IAAI;QACJ,QAAQ,EAAE;YACR,IAAI,EAAE,iBAAiB;YACvB,WAAW,EAAE,2CAA2C;YACxD,QAAQ,EAAE,KAAK;YACf,OAAO;SACR;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAI;YACvB,QAAQ,EAAE,IAAI;SACf;KACF,CAAC,CAAA;AACJ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC,CAAA;AAE7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,GAA+B,EAAE,OAAgC,EAAE,EAAE,CACvG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,UAAU,EAAE,CAAA;IACpD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC7C,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAA;IACrG,MAAM,cAAc,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,CAAA;IACxF,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAC7F,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CACzB,CAAA;IAED,MAAM,eAAe,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;IAEzE,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,mEAAmE;QACnE,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,kCAAkC,cAAc,CAAC,SAAS,EAAE,CAAC,CAAA;IACjF,CAAC;SAAM,CAAC;QACN,+EAA+E;QAC/E,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;AACH,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;AAEtG,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC,MAAM;IACxB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC;CACjC,CAAC,CAAA;AAKF;;;;;;;GAOG;AACH,MAAM,qBAAqB,GAAG,IAAI,OAAO,EAA2C,CAAA;AAEpF,MAAM,cAAc,GAAG,CAAC,GAA+B,EAAe,EAAE;IACtE,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC/C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAA;IAC3C,MAAM,OAAO,GAAgB,IAAI,GAAG,EAAE,CAAA;IACtC,qBAAqB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACvC,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
|
|
@@ -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,EAAE,WAAW,EAAgB,MAAM,mBAAmB,CAAA;
|
|
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,7 +1,6 @@
|
|
|
1
1
|
import { SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { Chunk, Effect, HttpClient, HttpClientRequest, identity, Layer, Option, RpcClient, RpcSerialization, Schedule, Schema, Stream, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
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';
|
|
5
4
|
import { MAX_HTTP_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from "../../common/constants.js";
|
|
6
5
|
import { SyncHttpRpc } from "../../common/http-rpc-schema.js";
|
|
7
6
|
import { SearchParamsSchema } from "../../common/mod.js";
|
|
@@ -12,7 +11,7 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
12
11
|
// Based on ping responses
|
|
13
12
|
const isConnected = yield* SubscriptionRef.make(false);
|
|
14
13
|
const livePullInterval = options.livePull?.pollInterval ?? 5_000;
|
|
15
|
-
const urlParamsData = yield* Schema.
|
|
14
|
+
const urlParamsData = yield* Schema.encodeEffect(SearchParamsSchema)({
|
|
16
15
|
storeId,
|
|
17
16
|
payload,
|
|
18
17
|
transport: 'http',
|
|
@@ -20,8 +19,8 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
20
19
|
const urlParams = UrlParams.fromInput(urlParamsData);
|
|
21
20
|
// Setup HTTP RPC Protocol
|
|
22
21
|
const HttpProtocolLive = RpcClient.layerProtocolHttp({
|
|
23
|
-
url:
|
|
24
|
-
transformClient: HttpClient.mapRequest((request) => request.pipe(HttpClientRequest.setHeaders({
|
|
22
|
+
url: options.url,
|
|
23
|
+
transformClient: HttpClient.mapRequest((request) => request.pipe(HttpClientRequest.appendUrlParams(urlParams), HttpClientRequest.setHeaders({
|
|
25
24
|
...options.headers,
|
|
26
25
|
// Used in CF Worker to identify the store (additionally to storeId embedded in the RPC requests)
|
|
27
26
|
'x-livestore-store-id': storeId,
|
|
@@ -30,9 +29,9 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
30
29
|
const rpcClient = yield* RpcClient.make(SyncHttpRpc).pipe(Effect.provide(HttpProtocolLive));
|
|
31
30
|
const pingTimeout = options.ping?.requestTimeout ?? 10_000;
|
|
32
31
|
const ping = Effect.gen(function* () {
|
|
33
|
-
yield* rpcClient
|
|
32
|
+
yield* rpcClient['SyncHttpRpc.Ping']({ storeId, payload });
|
|
34
33
|
yield* SubscriptionRef.set(isConnected, true);
|
|
35
|
-
}).pipe(UnknownError.mapToUnknownError, Effect.timeout(pingTimeout), Effect.catchTag('
|
|
34
|
+
}).pipe(UnknownError.mapToUnknownError, Effect.timeout(pingTimeout), Effect.catchTag('TimeoutError', () => SubscriptionRef.set(isConnected, false)));
|
|
36
35
|
const pingInterval = options.ping?.requestInterval ?? 10_000;
|
|
37
36
|
if (options.ping?.enabled !== false) {
|
|
38
37
|
// Automatically ping the server to keep the connection alive
|
|
@@ -45,31 +44,42 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
45
44
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
46
45
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
47
46
|
})));
|
|
48
|
-
const pull = (cursor, options) => rpcClient
|
|
47
|
+
const pull = (cursor, options) => rpcClient['SyncHttpRpc.Pull']({
|
|
49
48
|
storeId,
|
|
50
49
|
payload,
|
|
51
50
|
cursor: mapCursor(cursor),
|
|
52
51
|
}).pipe(options?.live === true
|
|
53
52
|
? // Phase 2: Simulate `live` pull by polling for new events
|
|
54
53
|
Stream.concatWithLastElement((lastElement) => {
|
|
55
|
-
const initialPhase2Cursor = lastElement.pipe(Option.flatMap((_) => Option.
|
|
56
|
-
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* () {
|
|
57
56
|
yield* Effect.sleep(livePullInterval);
|
|
58
|
-
const items = yield* rpcClient
|
|
59
|
-
|
|
60
|
-
|
|
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;
|
|
61
68
|
}));
|
|
62
69
|
})
|
|
63
|
-
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
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'
|
|
64
71
|
? cause
|
|
65
72
|
: new UnknownError({ cause })), Stream.withSpan('http-sync-client:pull'));
|
|
66
|
-
const pushSemaphore = yield*
|
|
73
|
+
const pushSemaphore = yield* Semaphore.make(1);
|
|
67
74
|
const push = Effect.fn('http-sync-client:push')(function* (batch) {
|
|
68
75
|
if (batch.length === 0) {
|
|
69
76
|
return;
|
|
70
77
|
}
|
|
71
78
|
const backendId = backendIdHelper.get();
|
|
72
|
-
|
|
79
|
+
if (EffectArray.isReadonlyArrayNonEmpty(batch) === false) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const batchChunks = yield* splitArrayBySize({
|
|
73
83
|
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
74
84
|
maxBytes: MAX_HTTP_REQUEST_BYTES,
|
|
75
85
|
encode: (items) => ({
|
|
@@ -78,10 +88,9 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
78
88
|
payload,
|
|
79
89
|
backendId,
|
|
80
90
|
}),
|
|
81
|
-
})
|
|
82
|
-
for (const
|
|
83
|
-
|
|
84
|
-
yield* rpcClient.SyncHttpRpc.Push({ storeId, payload, batch: chunkArray, backendId });
|
|
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 });
|
|
85
94
|
}
|
|
86
95
|
}, pushSemaphore.withPermits(1), Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
87
96
|
? cause
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
1
|
+
{"version":3,"file":"http-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/http-rpc-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SyncBackend } from '@livestore/common';
|
|
2
|
-
import {
|
|
2
|
+
import { Duration, Effect, type Scope } from '@livestore/utils/effect';
|
|
3
3
|
import type { WebSocket } from '@livestore/utils/effect/browser';
|
|
4
4
|
import type { SyncMetadata } from '../../common/sync-message-types.ts';
|
|
5
5
|
export interface WsSyncOptions {
|
|
@@ -25,12 +25,12 @@ export interface WsSyncOptions {
|
|
|
25
25
|
* How long to wait for a ping response before timing out
|
|
26
26
|
* @default 10 seconds
|
|
27
27
|
*/
|
|
28
|
-
requestTimeout?: Duration.
|
|
28
|
+
requestTimeout?: Duration.Input;
|
|
29
29
|
/**
|
|
30
30
|
* How often to send ping requests
|
|
31
31
|
* @default 10 seconds
|
|
32
32
|
*/
|
|
33
|
-
requestInterval?: Duration.
|
|
33
|
+
requestInterval?: Duration.Input;
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
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,EAAkB,WAAW,EAAgB,MAAM,mBAAmB,CAAA;
|
|
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"}
|