@livestore/sync-cf 0.4.0-dev.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -8
- package/dist/.tsbuildinfo +1 -1
- package/dist/cf-worker/do/durable-object.d.ts +1 -1
- package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
- package/dist/cf-worker/do/durable-object.js +15 -14
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +6 -6
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +32 -9
- package/dist/cf-worker/do/layer.js.map +1 -1
- package/dist/cf-worker/do/pull.d.ts +8 -3
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +22 -10
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +5 -4
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +80 -41
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/sqlite.d.ts +10 -1
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js +13 -4
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +14 -9
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +92 -18
- package/dist/cf-worker/do/sync-storage.js.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts +2 -1
- package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/do-rpc-server.js +13 -7
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +3 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.js +24 -15
- package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +2 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
- package/dist/cf-worker/do/transport/ws-rpc-server.js +30 -8
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +123 -30
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/shared.js +50 -6
- package/dist/cf-worker/shared.js.map +1 -1
- package/dist/cf-worker/worker.d.ts +64 -71
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +70 -48
- package/dist/cf-worker/worker.js.map +1 -1
- package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/do-rpc-client.js +27 -10
- package/dist/client/transport/do-rpc-client.js.map +1 -1
- package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/http-rpc-client.js +29 -9
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts +2 -1
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +31 -17
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/constants.d.ts +7 -0
- package/dist/common/constants.d.ts.map +1 -0
- package/dist/common/constants.js +17 -0
- package/dist/common/constants.js.map +1 -0
- package/dist/common/do-rpc-schema.d.ts +6 -6
- package/dist/common/do-rpc-schema.d.ts.map +1 -1
- package/dist/common/do-rpc-schema.js +4 -4
- package/dist/common/do-rpc-schema.js.map +1 -1
- package/dist/common/http-rpc-schema.d.ts +4 -4
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +4 -4
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/mod.d.ts +4 -1
- package/dist/common/mod.d.ts.map +1 -1
- package/dist/common/mod.js +4 -1
- package/dist/common/mod.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +2 -2
- package/dist/common/sync-message-types.js +3 -3
- package/dist/common/sync-message-types.js.map +1 -1
- package/dist/common/ws-rpc-schema.d.ts +3 -3
- package/dist/common/ws-rpc-schema.d.ts.map +1 -1
- package/dist/common/ws-rpc-schema.js +3 -3
- package/dist/common/ws-rpc-schema.js.map +1 -1
- package/package.json +72 -14
- package/src/cf-worker/do/durable-object.ts +23 -18
- package/src/cf-worker/do/layer.ts +35 -13
- package/src/cf-worker/do/pull.ts +43 -14
- package/src/cf-worker/do/push.ts +107 -46
- package/src/cf-worker/do/sqlite.ts +14 -4
- package/src/cf-worker/do/sync-storage.ts +151 -31
- package/src/cf-worker/do/transport/do-rpc-server.ts +22 -9
- package/src/cf-worker/do/transport/http-rpc-server.ts +33 -13
- package/src/cf-worker/do/transport/ws-rpc-server.ts +40 -12
- package/src/cf-worker/shared.ts +149 -25
- package/src/cf-worker/worker.ts +138 -108
- package/src/client/transport/do-rpc-client.ts +41 -17
- package/src/client/transport/http-rpc-client.ts +43 -17
- package/src/client/transport/ws-rpc-client.ts +42 -19
- package/src/common/constants.ts +18 -0
- package/src/common/do-rpc-schema.ts +5 -4
- package/src/common/http-rpc-schema.ts +5 -4
- package/src/common/mod.ts +4 -2
- package/src/common/sync-message-types.ts +3 -3
- package/src/common/ws-rpc-schema.ts +4 -3
package/dist/cf-worker/worker.js
CHANGED
|
@@ -1,36 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
1
|
+
import { env as importedEnv } from 'cloudflare:workers';
|
|
2
|
+
import { UnknownError } from '@livestore/common';
|
|
3
|
+
import { Effect, Schema } from '@livestore/utils/effect';
|
|
4
|
+
import { matchSyncRequest } from "./shared.js";
|
|
5
|
+
/**
|
|
6
|
+
* Produces a Cloudflare Worker `fetch` handler that delegates sync traffic to the
|
|
7
|
+
* Durable Object identified by `syncBackendBinding`.
|
|
8
|
+
*
|
|
9
|
+
* For more complex setups prefer implementing a custom `fetch` and call {@link handleSyncRequest}
|
|
10
|
+
* from the branch that handles LiveStore sync requests.
|
|
11
|
+
*/
|
|
12
|
+
export const makeWorker = (options) => {
|
|
5
13
|
return {
|
|
6
14
|
fetch: async (request, env, _ctx) => {
|
|
7
15
|
const url = new URL(request.url);
|
|
8
|
-
const corsHeaders = options.enableCORS
|
|
16
|
+
const corsHeaders = options.enableCORS === true
|
|
9
17
|
? {
|
|
10
18
|
'Access-Control-Allow-Origin': '*',
|
|
11
19
|
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
12
20
|
'Access-Control-Allow-Headers': request.headers.get('Access-Control-Request-Headers') ?? '*',
|
|
13
21
|
}
|
|
14
22
|
: {};
|
|
15
|
-
if (request.method === 'OPTIONS' && options.enableCORS) {
|
|
23
|
+
if (request.method === 'OPTIONS' && options.enableCORS === true) {
|
|
16
24
|
return new Response(null, {
|
|
17
25
|
status: 204,
|
|
18
26
|
headers: corsHeaders,
|
|
19
27
|
});
|
|
20
28
|
}
|
|
21
|
-
const
|
|
29
|
+
const searchParams = matchSyncRequest(request);
|
|
22
30
|
// Check if this is a sync request first, before showing info message
|
|
23
|
-
if (
|
|
31
|
+
if (searchParams !== undefined) {
|
|
24
32
|
return handleSyncRequest({
|
|
25
33
|
request,
|
|
26
|
-
searchParams
|
|
34
|
+
searchParams,
|
|
27
35
|
env,
|
|
28
36
|
ctx: _ctx,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
},
|
|
37
|
+
syncBackendBinding: options.syncBackendBinding,
|
|
38
|
+
headers: corsHeaders,
|
|
39
|
+
validatePayload: options.validatePayload,
|
|
40
|
+
syncPayloadSchema: options.syncPayloadSchema,
|
|
34
41
|
});
|
|
35
42
|
}
|
|
36
43
|
// Only show info message for GET requests to / without sync parameters
|
|
@@ -52,57 +59,72 @@ export const makeWorker = (options = {}) => {
|
|
|
52
59
|
},
|
|
53
60
|
};
|
|
54
61
|
};
|
|
62
|
+
/** Convert CF Request headers to a ForwardedHeaders map */
|
|
63
|
+
const requestHeadersToMap = (request) => {
|
|
64
|
+
const result = new Map();
|
|
65
|
+
request.headers.forEach((value, key) => {
|
|
66
|
+
result.set(key.toLowerCase(), value);
|
|
67
|
+
});
|
|
68
|
+
return result;
|
|
69
|
+
};
|
|
55
70
|
/**
|
|
56
|
-
* Handles
|
|
71
|
+
* Handles LiveStore sync requests (e.g. with search params `?storeId=...&transport=...`).
|
|
57
72
|
*
|
|
58
|
-
* @example
|
|
73
|
+
* @example Token-based authentication
|
|
59
74
|
* ```ts
|
|
60
75
|
* const validatePayload = (payload: Schema.JsonValue | undefined, context: { storeId: string }) => {
|
|
61
|
-
* console.log(`Validating connection for store: ${context.storeId}`)
|
|
62
76
|
* if (payload?.authToken !== 'insecure-token-change-me') {
|
|
63
77
|
* throw new Error('Invalid auth token')
|
|
64
78
|
* }
|
|
65
79
|
* }
|
|
80
|
+
* ```
|
|
66
81
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* return handleSyncRequest({
|
|
74
|
-
* request,
|
|
75
|
-
* searchParams: requestParamsResult.value,
|
|
76
|
-
* env,
|
|
77
|
-
* ctx,
|
|
78
|
-
* options: { headers: {}, validatePayload }
|
|
79
|
-
* })
|
|
80
|
-
* }
|
|
81
|
-
*
|
|
82
|
-
* return new Response('Invalid path', { status: 400 })
|
|
83
|
-
* }
|
|
82
|
+
* @example Cookie-based authentication
|
|
83
|
+
* ```ts
|
|
84
|
+
* const validatePayload = async (payload: Schema.JsonValue | undefined, { storeId, headers }) => {
|
|
85
|
+
* const cookie = headers.get('cookie')
|
|
86
|
+
* const session = await validateSessionFromCookie(cookie)
|
|
87
|
+
* if (!session) throw new Error('Unauthorized')
|
|
84
88
|
* }
|
|
85
89
|
* ```
|
|
86
90
|
*
|
|
87
|
-
* @throws {
|
|
91
|
+
* @throws {UnknownError} If the payload is invalid
|
|
88
92
|
*/
|
|
89
|
-
export const handleSyncRequest = ({ request, searchParams, env,
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
if
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
export const handleSyncRequest = ({ request, searchParams: { storeId, payload, transport }, env: explicitlyProvidedEnv, syncBackendBinding, headers, validatePayload, syncPayloadSchema, }) => Effect.gen(function* () {
|
|
94
|
+
if (validatePayload !== undefined) {
|
|
95
|
+
// Convert request headers to a Map for the validation context
|
|
96
|
+
const requestHeaders = requestHeadersToMap(request);
|
|
97
|
+
// Always decode with the supplied schema when present, even if payload is undefined.
|
|
98
|
+
// This ensures required payloads are enforced by the schema.
|
|
99
|
+
if (syncPayloadSchema !== undefined) {
|
|
100
|
+
const decodedEither = Schema.decodeUnknownEither(syncPayloadSchema)(payload);
|
|
101
|
+
if (decodedEither._tag === 'Left') {
|
|
102
|
+
const message = decodedEither.left.toString();
|
|
103
|
+
console.error('Invalid payload (decode failed)', message);
|
|
104
|
+
return new Response(message, { status: 400, ...(headers !== undefined ? { headers } : {}) });
|
|
105
|
+
}
|
|
106
|
+
const result = yield* Effect.promise(async () => validatePayload(decodedEither.right, { storeId, headers: requestHeaders })).pipe(UnknownError.mapToUnknownError, Effect.either);
|
|
107
|
+
if (result._tag === 'Left') {
|
|
108
|
+
console.error('Invalid payload (validation failed)', result.left);
|
|
109
|
+
return new Response(result.left.toString(), { status: 400, ...(headers !== undefined ? { headers } : {}) });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const result = yield* Effect.promise(async () => validatePayload(payload, { storeId, headers: requestHeaders })).pipe(UnknownError.mapToUnknownError, Effect.either);
|
|
114
|
+
if (result._tag === 'Left') {
|
|
115
|
+
console.error('Invalid payload (validation failed)', result.left);
|
|
116
|
+
return new Response(result.left.toString(), { status: 400, ...(headers !== undefined ? { headers } : {}) });
|
|
117
|
+
}
|
|
96
118
|
}
|
|
97
119
|
}
|
|
98
|
-
const
|
|
99
|
-
if (!(
|
|
100
|
-
return new Response(`Failed dependency: Required Durable Object binding '${
|
|
120
|
+
const env = explicitlyProvidedEnv ?? importedEnv;
|
|
121
|
+
if (!(syncBackendBinding in env)) {
|
|
122
|
+
return new Response(`Failed dependency: Required Durable Object binding '${syncBackendBinding}' not available`, {
|
|
101
123
|
status: 424,
|
|
102
|
-
headers:
|
|
124
|
+
...(headers !== undefined ? { headers } : {}),
|
|
103
125
|
});
|
|
104
126
|
}
|
|
105
|
-
const durableObjectNamespace = env[
|
|
127
|
+
const durableObjectNamespace = env[syncBackendBinding];
|
|
106
128
|
const id = durableObjectNamespace.idFromName(storeId);
|
|
107
129
|
const durableObject = durableObjectNamespace.get(id);
|
|
108
130
|
// Handle WebSocket upgrade request
|
|
@@ -110,7 +132,7 @@ export const handleSyncRequest = ({ request, searchParams, env, options = {}, })
|
|
|
110
132
|
if (transport === 'ws' && (upgradeHeader === null || upgradeHeader !== 'websocket')) {
|
|
111
133
|
return new Response('Durable Object expected Upgrade: websocket', {
|
|
112
134
|
status: 426,
|
|
113
|
-
headers:
|
|
135
|
+
...(headers !== undefined ? { headers } : {}),
|
|
114
136
|
});
|
|
115
137
|
}
|
|
116
138
|
return yield* Effect.promise(() => durableObject.fetch(request));
|
|
@@ -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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"}
|
|
@@ -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;AAE7D,OAAO,EAAE,KAAK,OAAO,EAA8B,MAAM,sBAAsB,CAAA;AAgB/E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAIxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAEtE,MAAM,WAAW,kBAAmB,SAAQ,OAAO,CAAC,iBAAiB,EAAE,uBAAuB;CAAG;AAMjG,MAAM,WAAW,gBAAgB;IAC/B,kEAAkE;IAClE,eAAe,EAAE,kBAAkB,CAAA;IACnC,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,2CAA2C,gBAAgB,KAAG,WAAW,CAAC,sBAAsB,CAAC,YAAY,CA8GnD,CAAA;AAE7D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,kBAckD,CAAA"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
+
import { splitChunkBySize } from '@livestore/common/sync';
|
|
2
3
|
import { layerProtocolDurableObject } from '@livestore/common-cf';
|
|
3
4
|
import { omit, shouldNeverHappen } from '@livestore/utils';
|
|
4
|
-
import { Effect, identity, Layer, Mailbox, Option, RpcClient, RpcSerialization, Schema, Stream, SubscriptionRef, } from '@livestore/utils/effect';
|
|
5
|
+
import { Chunk, Effect, identity, Layer, Mailbox, Option, RpcClient, RpcSerialization, Schema, Stream, 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
9
|
const requestIdMailboxMap = new Map();
|
|
@@ -27,8 +29,8 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
27
29
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
28
30
|
}))),
|
|
29
31
|
storeId,
|
|
30
|
-
rpcContext: options?.live ? { callerContext: durableObjectContext } : undefined,
|
|
31
|
-
}).pipe(options?.live
|
|
32
|
+
rpcContext: options?.live === true ? { callerContext: durableObjectContext } : undefined,
|
|
33
|
+
}).pipe(options?.live === true
|
|
32
34
|
? Stream.concatWithLastElement((res) => Effect.gen(function* () {
|
|
33
35
|
if (res._tag === 'None')
|
|
34
36
|
return shouldNeverHappen('There should at least be a no-more page info response');
|
|
@@ -36,19 +38,34 @@ export const makeDoRpcSync = ({ syncBackendStub, durableObjectContext }) => ({ s
|
|
|
36
38
|
requestIdMailboxMap.set(res.value.rpcRequestId, mailbox);
|
|
37
39
|
return Mailbox.toStream(mailbox);
|
|
38
40
|
}).pipe(Stream.unwrapScoped))
|
|
39
|
-
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) =>
|
|
40
|
-
|
|
41
|
+
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
42
|
+
? cause
|
|
43
|
+
: new UnknownError({ cause })), Stream.withSpan('rpc-sync-client:pull'));
|
|
44
|
+
const push = Effect.fn('rpc-sync-client:push')(function* (batch) {
|
|
41
45
|
if (batch.length === 0) {
|
|
42
46
|
return;
|
|
43
47
|
}
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
const backendId = backendIdHelper.get();
|
|
49
|
+
const batchChunks = yield* Chunk.fromIterable(batch).pipe(splitChunkBySize({
|
|
50
|
+
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
51
|
+
maxBytes: MAX_DO_RPC_REQUEST_BYTES,
|
|
52
|
+
encode: (items) => ({
|
|
53
|
+
batch: items,
|
|
54
|
+
storeId,
|
|
55
|
+
backendId,
|
|
56
|
+
}),
|
|
57
|
+
}), Effect.mapError((cause) => new UnknownError({ cause })));
|
|
58
|
+
for (const chunk of Chunk.toReadonlyArray(batchChunks)) {
|
|
59
|
+
const chunkArray = Chunk.toReadonlyArray(chunk);
|
|
60
|
+
yield* rpcClient.SyncDoRpc.Push({ batch: chunkArray, storeId, backendId });
|
|
61
|
+
}
|
|
62
|
+
}, Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
46
63
|
? cause
|
|
47
|
-
:
|
|
64
|
+
: new UnknownError({ cause })));
|
|
48
65
|
const ping = rpcClient.SyncDoRpc.Ping({
|
|
49
66
|
storeId,
|
|
50
67
|
payload,
|
|
51
|
-
}).pipe(
|
|
68
|
+
}).pipe(UnknownError.mapToUnknownError, Effect.withSpan('rpc-sync-client:ping'));
|
|
52
69
|
return SyncBackend.of({
|
|
53
70
|
connect,
|
|
54
71
|
isConnected,
|
|
@@ -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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"}
|
|
@@ -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;AAI7D,OAAO,EAEL,KAAK,QAAQ,EAcd,MAAM,yBAAyB,CAAA;AAKhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAEtE,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,aAAa,CAAA;KACtC,CAAA;IACD,IAAI,CAAC,EAAE;QACL;;WAEG;QACH,OAAO,CAAC,EAAE,OAAO,CAAA;QACjB;;;WAGG;QACH,cAAc,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAA;QACvC;;;WAGG;QACH,eAAe,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAA;KACzC,CAAA;CACF;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GACtB,SAAS,eAAe,KAAG,WAAW,CAAC,sBAAsB,CAAC,YAAY,CAmKvE,CAAA"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
+
import { splitChunkBySize } from '@livestore/common/sync';
|
|
2
3
|
import { omit } from '@livestore/utils';
|
|
3
4
|
import { Chunk, Effect, HttpClient, HttpClientRequest, identity, Layer, Option, RpcClient, RpcSerialization, Schedule, Schema, Stream, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
5
|
+
import { MAX_HTTP_REQUEST_BYTES, MAX_PUSH_EVENTS_PER_REQUEST } from "../../common/constants.js";
|
|
4
6
|
import { SyncHttpRpc } from "../../common/http-rpc-schema.js";
|
|
5
7
|
import { SearchParamsSchema } from "../../common/mod.js";
|
|
6
8
|
/**
|
|
@@ -14,7 +16,7 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
14
16
|
storeId,
|
|
15
17
|
payload,
|
|
16
18
|
transport: 'http',
|
|
17
|
-
}).pipe(
|
|
19
|
+
}).pipe(UnknownError.mapToUnknownError);
|
|
18
20
|
const urlParams = UrlParams.fromInput(urlParamsData);
|
|
19
21
|
// Setup HTTP RPC Protocol
|
|
20
22
|
const HttpProtocolLive = RpcClient.layerProtocolHttp({
|
|
@@ -30,14 +32,14 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
30
32
|
const ping = Effect.gen(function* () {
|
|
31
33
|
yield* rpcClient.SyncHttpRpc.Ping({ storeId, payload });
|
|
32
34
|
yield* SubscriptionRef.set(isConnected, true);
|
|
33
|
-
}).pipe(
|
|
35
|
+
}).pipe(UnknownError.mapToUnknownError, Effect.timeout(pingTimeout), Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)));
|
|
34
36
|
const pingInterval = options.ping?.requestInterval ?? 10_000;
|
|
35
37
|
if (options.ping?.enabled !== false) {
|
|
36
38
|
// Automatically ping the server to keep the connection alive
|
|
37
39
|
yield* ping.pipe(Effect.repeat(Schedule.spaced(pingInterval)), Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
38
40
|
}
|
|
39
41
|
// Helps already establish a TCP connection to the server
|
|
40
|
-
const connect = ping.pipe(
|
|
42
|
+
const connect = ping.pipe(UnknownError.mapToUnknownError);
|
|
41
43
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper;
|
|
42
44
|
const mapCursor = (cursor) => cursor.pipe(Option.map((a) => ({
|
|
43
45
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
@@ -47,7 +49,7 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
47
49
|
storeId,
|
|
48
50
|
payload,
|
|
49
51
|
cursor: mapCursor(cursor),
|
|
50
|
-
}).pipe(options?.live
|
|
52
|
+
}).pipe(options?.live === true
|
|
51
53
|
? // Phase 2: Simulate `live` pull by polling for new events
|
|
52
54
|
Stream.concatWithLastElement((lastElement) => {
|
|
53
55
|
const initialPhase2Cursor = lastElement.pipe(Option.flatMap((_) => Option.fromNullable(_.batch.at(-1)?.eventEncoded.seqNum)), Option.map((eventSequenceNumber) => ({ eventSequenceNumber })), Option.orElse(() => cursor), mapCursor);
|
|
@@ -58,14 +60,32 @@ export const makeHttpSync = (options) => ({ storeId, payload }) => Effect.gen(fu
|
|
|
58
60
|
return Option.some([items, nextCursor]);
|
|
59
61
|
}));
|
|
60
62
|
})
|
|
61
|
-
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) =>
|
|
63
|
+
: identity, Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
64
|
+
? cause
|
|
65
|
+
: new UnknownError({ cause })), Stream.withSpan('http-sync-client:pull'));
|
|
62
66
|
const pushSemaphore = yield* Effect.makeSemaphore(1);
|
|
63
|
-
const push =
|
|
67
|
+
const push = Effect.fn('http-sync-client:push')(function* (batch) {
|
|
64
68
|
if (batch.length === 0) {
|
|
65
69
|
return;
|
|
66
70
|
}
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
const backendId = backendIdHelper.get();
|
|
72
|
+
const batchChunks = yield* Chunk.fromIterable(batch).pipe(splitChunkBySize({
|
|
73
|
+
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
74
|
+
maxBytes: MAX_HTTP_REQUEST_BYTES,
|
|
75
|
+
encode: (items) => ({
|
|
76
|
+
batch: items,
|
|
77
|
+
storeId,
|
|
78
|
+
payload,
|
|
79
|
+
backendId,
|
|
80
|
+
}),
|
|
81
|
+
}), Effect.mapError((cause) => new UnknownError({ cause })));
|
|
82
|
+
for (const chunk of Chunk.toReadonlyArray(batchChunks)) {
|
|
83
|
+
const chunkArray = Chunk.toReadonlyArray(chunk);
|
|
84
|
+
yield* rpcClient.SyncHttpRpc.Push({ storeId, payload, batch: chunkArray, backendId });
|
|
85
|
+
}
|
|
86
|
+
}, pushSemaphore.withPermits(1), Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
87
|
+
? cause
|
|
88
|
+
: new UnknownError({ cause })));
|
|
69
89
|
return SyncBackend.of({
|
|
70
90
|
connect,
|
|
71
91
|
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":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SyncBackend } from '@livestore/common';
|
|
2
|
-
import { type Duration, Effect, type Scope
|
|
2
|
+
import { type 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
|
/**
|
|
@@ -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;AAI7E,OAAO,EAEL,KAAK,QAAQ,EACb,MAAM,EAON,KAAK,KAAK,EAKX,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,aAAa,CAAA;QACvC;;;WAGG;QACH,eAAe,CAAC,EAAE,QAAQ,CAAC,aAAa,CAAA;KACzC,CAAA;CACF;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,GACpB,SAAS,aAAa,KAAG,WAAW,CAAC,sBAAsB,CAAC,YAAY,CAuIrE,CAAA"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IsOfflineError, SyncBackend, UnknownError } from '@livestore/common';
|
|
2
|
+
import { splitChunkBySize } from '@livestore/common/sync';
|
|
2
3
|
import { omit } from '@livestore/utils';
|
|
3
|
-
import { Effect, Layer, Option, RpcClient, RpcSerialization, Schedule, Schema, Socket, Stream, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
4
|
+
import { Chunk, Effect, Layer, Option, RpcClient, RpcSerialization, Schedule, Schema, Socket, Stream, SubscriptionRef, UrlParams, } from '@livestore/utils/effect';
|
|
5
|
+
import { MAX_PUSH_EVENTS_PER_REQUEST, MAX_WS_MESSAGE_BYTES } from "../../common/constants.js";
|
|
4
6
|
import { SearchParamsSchema } from "../../common/mod.js";
|
|
5
7
|
import { SyncWsRpc } from "../../common/ws-rpc-schema.js";
|
|
6
8
|
/**
|
|
@@ -17,7 +19,7 @@ export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(func
|
|
|
17
19
|
storeId,
|
|
18
20
|
payload,
|
|
19
21
|
transport: 'ws',
|
|
20
|
-
}).pipe(
|
|
22
|
+
}).pipe(UnknownError.mapToUnknownError);
|
|
21
23
|
const urlParams = UrlParams.fromInput(urlParamsData);
|
|
22
24
|
const wsUrl = `${options.url}?${UrlParams.toString(urlParams)}`;
|
|
23
25
|
const isConnected = yield* SubscriptionRef.make(false);
|
|
@@ -34,7 +36,7 @@ export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(func
|
|
|
34
36
|
const pingInterval = options.ping?.requestInterval ?? 10_000;
|
|
35
37
|
const ProtocolLive = RpcClient.layerProtocolSocketWithIsConnected({
|
|
36
38
|
isConnected,
|
|
37
|
-
retryTransientErrors: Schedule.fixed(
|
|
39
|
+
retryTransientErrors: Schedule.exponential('1 seconds').pipe(Schedule.union(Schedule.fixed('30 seconds')), Schedule.jittered),
|
|
38
40
|
pingSchedule: Schedule.once.pipe(Schedule.andThen(Schedule.fixed(pingInterval))),
|
|
39
41
|
url: wsUrl,
|
|
40
42
|
}).pipe(Layer.provide(Socket.layerWebSocket(wsUrl)), Layer.provide(Socket.layerWebSocketConstructorGlobal), Layer.provide(RpcSerialization.layerJson));
|
|
@@ -47,7 +49,7 @@ export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(func
|
|
|
47
49
|
const pinger = yield* RpcClient.SocketPinger.pipe(Effect.provide(ctx));
|
|
48
50
|
yield* pinger.ping;
|
|
49
51
|
yield* SubscriptionRef.set(isConnected, true);
|
|
50
|
-
}).pipe(Effect.timeout(pingTimeout), Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)),
|
|
52
|
+
}).pipe(Effect.timeout(pingTimeout), Effect.catchTag('TimeoutException', () => SubscriptionRef.set(isConnected, false)), UnknownError.mapToUnknownError, Effect.withSpan('ping'));
|
|
51
53
|
const backendIdHelper = yield* SyncBackend.makeBackendIdHelper;
|
|
52
54
|
return SyncBackend.of({
|
|
53
55
|
isConnected,
|
|
@@ -59,25 +61,37 @@ export const makeWsSync = (options) => ({ storeId, payload }) => Effect.gen(func
|
|
|
59
61
|
eventSequenceNumber: a.eventSequenceNumber,
|
|
60
62
|
backendId: backendIdHelper.get().pipe(Option.getOrThrow),
|
|
61
63
|
}))),
|
|
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)
|
|
64
|
+
live: options?.live === true,
|
|
65
|
+
}).pipe(Stream.tap((res) => backendIdHelper.lazySet(res.backendId)), Stream.map((res) => omit(res, ['backendId'])), Stream.mapError((cause) => cause._tag === 'RpcClientError' && Socket.isSocketError(cause.cause) === true
|
|
64
66
|
? new IsOfflineError({ cause: cause.cause })
|
|
65
|
-
: cause._tag === '
|
|
67
|
+
: cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
66
68
|
? cause
|
|
67
|
-
:
|
|
68
|
-
push:
|
|
69
|
-
if (batch.length === 0)
|
|
69
|
+
: new UnknownError({ cause })), Stream.withSpan('pull')),
|
|
70
|
+
push: Effect.fn('push')(function* (batch) {
|
|
71
|
+
if (batch.length === 0)
|
|
70
72
|
return;
|
|
71
|
-
|
|
72
|
-
return yield* rpcClient.SyncWsRpc.Push({
|
|
73
|
+
const encodePayload = (batch) => ({
|
|
73
74
|
storeId,
|
|
74
75
|
payload,
|
|
75
76
|
batch,
|
|
76
77
|
backendId: backendIdHelper.get(),
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
:
|
|
80
|
-
|
|
78
|
+
});
|
|
79
|
+
const chunksChunk = yield* Chunk.fromIterable(batch).pipe(splitChunkBySize({
|
|
80
|
+
maxItems: MAX_PUSH_EVENTS_PER_REQUEST,
|
|
81
|
+
maxBytes: MAX_WS_MESSAGE_BYTES,
|
|
82
|
+
encode: encodePayload,
|
|
83
|
+
}), Effect.mapError((cause) => new UnknownError({ cause })));
|
|
84
|
+
for (const sub of chunksChunk) {
|
|
85
|
+
yield* rpcClient.SyncWsRpc.Push({
|
|
86
|
+
storeId,
|
|
87
|
+
payload,
|
|
88
|
+
batch: Chunk.toReadonlyArray(sub),
|
|
89
|
+
backendId: backendIdHelper.get(),
|
|
90
|
+
}).pipe(Effect.mapError((cause) => cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
91
|
+
? cause
|
|
92
|
+
: new UnknownError({ cause })));
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
81
95
|
ping,
|
|
82
96
|
metadata: {
|
|
83
97
|
name: '@livestore/cf-sync',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/ws-rpc-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ws-rpc-client.js","sourceRoot":"","sources":["../../../src/client/transport/ws-rpc-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const MAX_TRANSPORT_PAYLOAD_BYTES = 900000;
|
|
2
|
+
export declare const MAX_WS_MESSAGE_BYTES = 900000;
|
|
3
|
+
export declare const MAX_DO_RPC_REQUEST_BYTES = 900000;
|
|
4
|
+
export declare const MAX_HTTP_REQUEST_BYTES = 900000;
|
|
5
|
+
export declare const MAX_PULL_EVENTS_PER_MESSAGE = 100;
|
|
6
|
+
export declare const MAX_PUSH_EVENTS_PER_REQUEST = 100;
|
|
7
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,2BAA2B,SAAU,CAAA;AAElD,eAAO,MAAM,oBAAoB,SAA8B,CAAA;AAC/D,eAAO,MAAM,wBAAwB,SAA8B,CAAA;AACnE,eAAO,MAAM,sBAAsB,SAA8B,CAAA;AAIjE,eAAO,MAAM,2BAA2B,MAAM,CAAA;AAC9C,eAAO,MAAM,2BAA2B,MAAM,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Shared transport limits for Cloudflare sync provider
|
|
2
|
+
// Keep payloads comfortably below ~1MB frame caps across Cloudflare transports.
|
|
3
|
+
// References:
|
|
4
|
+
// - Durable Objects WebSockets + hibernation best practices:
|
|
5
|
+
// https://developers.cloudflare.com/durable-objects/best-practices/websockets/
|
|
6
|
+
// - Workers platform limits (general context):
|
|
7
|
+
// https://developers.cloudflare.com/workers/platform/limits/
|
|
8
|
+
// Empirically, frames just below 1MB can fail on hibernated DO WebSockets; we use 900_000 bytes to keep a safety margin.
|
|
9
|
+
export const MAX_TRANSPORT_PAYLOAD_BYTES = 900_000;
|
|
10
|
+
export const MAX_WS_MESSAGE_BYTES = MAX_TRANSPORT_PAYLOAD_BYTES;
|
|
11
|
+
export const MAX_DO_RPC_REQUEST_BYTES = MAX_TRANSPORT_PAYLOAD_BYTES;
|
|
12
|
+
export const MAX_HTTP_REQUEST_BYTES = MAX_TRANSPORT_PAYLOAD_BYTES;
|
|
13
|
+
// Upper bound for items per message/request. Mirrors server broadcast chunking.
|
|
14
|
+
// Not Cloudflare-enforced; chosen to balance payload size and latency.
|
|
15
|
+
export const MAX_PULL_EVENTS_PER_MESSAGE = 100;
|
|
16
|
+
export const MAX_PUSH_EVENTS_PER_REQUEST = 100;
|
|
17
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,gFAAgF;AAChF,cAAc;AACd,6DAA6D;AAC7D,iFAAiF;AACjF,+CAA+C;AAC/C,+DAA+D;AAC/D,yHAAyH;AACzH,MAAM,CAAC,MAAM,2BAA2B,GAAG,OAAO,CAAA;AAElD,MAAM,CAAC,MAAM,oBAAoB,GAAG,2BAA2B,CAAA;AAC/D,MAAM,CAAC,MAAM,wBAAwB,GAAG,2BAA2B,CAAA;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,2BAA2B,CAAA;AAEjE,gFAAgF;AAChF,uEAAuE;AACvE,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAA;AAC9C,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAA"}
|