@livestore/sync-cf 0.4.0-dev.22 → 0.4.0-dev.24
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 +6 -7
- 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 +5 -5
- package/dist/cf-worker/do/durable-object.js.map +1 -1
- package/dist/cf-worker/do/layer.d.ts +1 -1
- package/dist/cf-worker/do/layer.d.ts.map +1 -1
- package/dist/cf-worker/do/layer.js +2 -2
- package/dist/cf-worker/do/layer.js.map +1 -1
- package/dist/cf-worker/do/pull.d.ts +2 -2
- package/dist/cf-worker/do/pull.d.ts.map +1 -1
- package/dist/cf-worker/do/pull.js +11 -5
- package/dist/cf-worker/do/pull.js.map +1 -1
- package/dist/cf-worker/do/push.d.ts +2 -2
- package/dist/cf-worker/do/push.d.ts.map +1 -1
- package/dist/cf-worker/do/push.js +16 -9
- package/dist/cf-worker/do/push.js.map +1 -1
- package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
- package/dist/cf-worker/do/sqlite.js.map +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts +1 -1
- package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
- package/dist/cf-worker/do/sync-storage.js +2 -1
- package/dist/cf-worker/do/sync-storage.js.map +1 -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 +9 -5
- package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
- package/dist/cf-worker/do/transport/http-rpc-server.d.ts +1 -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 +2 -2
- package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -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 +7 -3
- package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
- package/dist/cf-worker/shared.d.ts +7 -7
- package/dist/cf-worker/shared.d.ts.map +1 -1
- package/dist/cf-worker/worker.d.ts.map +1 -1
- package/dist/cf-worker/worker.js +7 -7
- 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 +11 -7
- 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 +10 -6
- package/dist/client/transport/http-rpc-client.js.map +1 -1
- package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
- package/dist/client/transport/ws-rpc-client.js +11 -11
- package/dist/client/transport/ws-rpc-client.js.map +1 -1
- package/dist/common/do-rpc-schema.d.ts +3 -3
- 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 +3 -3
- package/dist/common/http-rpc-schema.d.ts.map +1 -1
- package/dist/common/http-rpc-schema.js +3 -3
- package/dist/common/http-rpc-schema.js.map +1 -1
- package/dist/common/sync-message-types.d.ts +2 -2
- 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 +71 -13
- package/src/cf-worker/do/durable-object.ts +10 -8
- package/src/cf-worker/do/layer.ts +4 -3
- package/src/cf-worker/do/pull.ts +17 -6
- package/src/cf-worker/do/push.ts +20 -9
- package/src/cf-worker/do/sqlite.ts +1 -0
- package/src/cf-worker/do/sync-storage.ts +4 -2
- package/src/cf-worker/do/transport/do-rpc-server.ts +14 -5
- package/src/cf-worker/do/transport/http-rpc-server.ts +17 -17
- package/src/cf-worker/do/transport/ws-rpc-server.ts +13 -4
- package/src/cf-worker/shared.ts +3 -3
- package/src/cf-worker/worker.ts +17 -14
- package/src/client/transport/do-rpc-client.ts +20 -14
- package/src/client/transport/http-rpc-client.ts +19 -13
- package/src/client/transport/ws-rpc-client.ts +39 -36
- package/src/common/do-rpc-schema.ts +4 -3
- package/src/common/http-rpc-schema.ts +4 -3
- package/src/common/ws-rpc-schema.ts +4 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common';
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect';
|
|
3
3
|
declare const SyncWsRpc_base: RpcGroup.RpcGroup<Rpc.Rpc<"SyncWsRpc.Pull", Schema.Struct<{
|
|
4
4
|
cursor: Schema.Option<Schema.Struct<{
|
|
@@ -29,7 +29,7 @@ declare const SyncWsRpc_base: RpcGroup.RpcGroup<Rpc.Rpc<"SyncWsRpc.Pull", Schema
|
|
|
29
29
|
remaining: typeof Schema.Number;
|
|
30
30
|
}>, Schema.TaggedStruct<"NoMore", {}>]>;
|
|
31
31
|
backendId: Schema.SchemaClass<string, string, never>;
|
|
32
|
-
}>, typeof
|
|
32
|
+
}>, Schema.Union<[typeof UnknownError, typeof BackendIdMismatchError]>>, typeof Schema.Never, never> | Rpc.Rpc<"SyncWsRpc.Push", Schema.Struct<{
|
|
33
33
|
batch: Schema.Array$<Schema.Struct<{
|
|
34
34
|
name: typeof Schema.String;
|
|
35
35
|
args: typeof Schema.Any;
|
|
@@ -41,7 +41,7 @@ declare const SyncWsRpc_base: RpcGroup.RpcGroup<Rpc.Rpc<"SyncWsRpc.Pull", Schema
|
|
|
41
41
|
backendId: Schema.Option<Schema.SchemaClass<string, string, never>>;
|
|
42
42
|
storeId: typeof Schema.String;
|
|
43
43
|
payload: Schema.optional<Schema.Schema<Schema.JsonValue, Schema.JsonValue, never>>;
|
|
44
|
-
}>, Schema.Struct<{}>, typeof
|
|
44
|
+
}>, Schema.Struct<{}>, Schema.Union<[typeof UnknownError, typeof ServerAheadError, typeof BackendIdMismatchError]>, never>>;
|
|
45
45
|
/**
|
|
46
46
|
* WebSocket RPC Schema for LiveStore CF Sync Provider
|
|
47
47
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-rpc-schema.d.ts","sourceRoot":"","sources":["../../src/common/ws-rpc-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ws-rpc-schema.d.ts","sourceRoot":"","sources":["../../src/common/ws-rpc-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC1F,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;;;;;;;;IAgBzD,qEAAqE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAZ3E;;;;;;GAMG;AACH,qBAAa,SAAU,SAAQ,cAwB9B;CAAG"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BackendIdMismatchError, ServerAheadError, UnknownError } from '@livestore/common';
|
|
2
2
|
import { Rpc, RpcGroup, Schema } from '@livestore/utils/effect';
|
|
3
3
|
import * as SyncMessage from "./sync-message-types.js";
|
|
4
4
|
/**
|
|
@@ -17,7 +17,7 @@ export class SyncWsRpc extends RpcGroup.make(Rpc.make('SyncWsRpc.Pull', {
|
|
|
17
17
|
...SyncMessage.PullRequest.fields,
|
|
18
18
|
}),
|
|
19
19
|
success: SyncMessage.PullResponse,
|
|
20
|
-
error:
|
|
20
|
+
error: Schema.Union(UnknownError, BackendIdMismatchError),
|
|
21
21
|
stream: true,
|
|
22
22
|
}), Rpc.make('SyncWsRpc.Push', {
|
|
23
23
|
payload: Schema.Struct({
|
|
@@ -26,7 +26,7 @@ export class SyncWsRpc extends RpcGroup.make(Rpc.make('SyncWsRpc.Pull', {
|
|
|
26
26
|
...SyncMessage.PushRequest.fields,
|
|
27
27
|
}),
|
|
28
28
|
success: SyncMessage.PushAck,
|
|
29
|
-
error:
|
|
29
|
+
error: Schema.Union(UnknownError, ServerAheadError, BackendIdMismatchError),
|
|
30
30
|
})) {
|
|
31
31
|
}
|
|
32
32
|
//# sourceMappingURL=ws-rpc-schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-rpc-schema.js","sourceRoot":"","sources":["../../src/common/ws-rpc-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ws-rpc-schema.js","sourceRoot":"","sources":["../../src/common/ws-rpc-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC1F,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAE/D,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AAEtD;;;;;;GAMG;AACH,MAAM,OAAO,SAAU,SAAQ,QAAQ,CAAC,IAAI,CAC1C,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC,MAAM;QACtB,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;QAC1C,qEAAqE;QACrE,IAAI,EAAE,MAAM,CAAC,OAAO;QACpB,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM;KAClC,CAAC;IACF,OAAO,EAAE,WAAW,CAAC,YAAY;IACjC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,sBAAsB,CAAC;IACzD,MAAM,EAAE,IAAI;CACb,CAAC,EACF,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE;IACzB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC,MAAM;QACtB,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;QAC1C,GAAG,WAAW,CAAC,WAAW,CAAC,MAAM;KAClC,CAAC;IACF,OAAO,EAAE,WAAW,CAAC,OAAO;IAC5B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,gBAAgB,EAAE,sBAAsB,CAAC;CAC5E,CAAC,CAGH;CAAG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@livestore/sync-cf",
|
|
3
|
-
"version": "0.4.0-dev.
|
|
3
|
+
"version": "0.4.0-dev.24",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/livestorejs/livestore.git"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"package.json",
|
|
12
|
+
"src",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
4
15
|
"type": "module",
|
|
5
16
|
"sideEffects": false,
|
|
6
17
|
"exports": {
|
|
@@ -8,21 +19,68 @@
|
|
|
8
19
|
"./common": "./dist/common/mod.js",
|
|
9
20
|
"./cf-worker": "./dist/cf-worker/mod.js"
|
|
10
21
|
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
11
25
|
"dependencies": {
|
|
12
26
|
"@cloudflare/workers-types": "4.20251118.0",
|
|
13
|
-
"@livestore/common
|
|
14
|
-
"@livestore/
|
|
15
|
-
"@livestore/
|
|
27
|
+
"@livestore/common": "^0.4.0-dev.24",
|
|
28
|
+
"@livestore/common-cf": "^0.4.0-dev.24",
|
|
29
|
+
"@livestore/utils": "^0.4.0-dev.24"
|
|
16
30
|
},
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@effect/ai": "0.35.0",
|
|
33
|
+
"@effect/cli": "0.75.1",
|
|
34
|
+
"@effect/cluster": "0.58.2",
|
|
35
|
+
"@effect/experimental": "0.60.0",
|
|
36
|
+
"@effect/opentelemetry": "0.63.0",
|
|
37
|
+
"@effect/platform": "0.96.1",
|
|
38
|
+
"@effect/platform-browser": "0.76.0",
|
|
39
|
+
"@effect/platform-bun": "0.89.0",
|
|
40
|
+
"@effect/platform-node": "0.106.0",
|
|
41
|
+
"@effect/printer": "0.49.0",
|
|
42
|
+
"@effect/printer-ansi": "0.49.0",
|
|
43
|
+
"@effect/rpc": "0.75.1",
|
|
44
|
+
"@effect/sql": "0.51.1",
|
|
45
|
+
"@effect/typeclass": "0.40.0",
|
|
46
|
+
"@effect/vitest": "0.29.0",
|
|
47
|
+
"@opentelemetry/api": "1.9.0",
|
|
48
|
+
"@opentelemetry/resources": "2.2.0",
|
|
49
|
+
"@standard-schema/spec": "1.1.0",
|
|
50
|
+
"effect": "3.21.2"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@effect/ai": "^0.35.0",
|
|
54
|
+
"@effect/cli": "^0.75.1",
|
|
55
|
+
"@effect/cluster": "^0.58.2",
|
|
56
|
+
"@effect/experimental": "^0.60.0",
|
|
57
|
+
"@effect/opentelemetry": "^0.63.0",
|
|
58
|
+
"@effect/platform": "^0.96.1",
|
|
59
|
+
"@effect/platform-browser": "^0.76.0",
|
|
60
|
+
"@effect/platform-bun": "^0.89.0",
|
|
61
|
+
"@effect/platform-node": "^0.106.0",
|
|
62
|
+
"@effect/printer": "^0.49.0",
|
|
63
|
+
"@effect/printer-ansi": "^0.49.0",
|
|
64
|
+
"@effect/rpc": "^0.75.1",
|
|
65
|
+
"@effect/sql": "^0.51.1",
|
|
66
|
+
"@effect/typeclass": "^0.40.0",
|
|
67
|
+
"@effect/vitest": "^0.29.0",
|
|
68
|
+
"@opentelemetry/api": "^1.9.0",
|
|
69
|
+
"@opentelemetry/resources": "^2.2.0",
|
|
70
|
+
"@standard-schema/spec": "^1.1.0",
|
|
71
|
+
"effect": "^3.21.2"
|
|
72
|
+
},
|
|
73
|
+
"$genie": {
|
|
74
|
+
"source": "package.json.genie.ts",
|
|
75
|
+
"warning": "DO NOT EDIT - changes will be overwritten",
|
|
76
|
+
"workspaceClosureDirs": [
|
|
77
|
+
"packages/@livestore/common",
|
|
78
|
+
"packages/@livestore/common-cf",
|
|
79
|
+
"packages/@livestore/sync-cf",
|
|
80
|
+
"packages/@livestore/utils",
|
|
81
|
+
"packages/@livestore/utils-dev",
|
|
82
|
+
"packages/@livestore/webmesh"
|
|
83
|
+
]
|
|
26
84
|
},
|
|
27
85
|
"scripts": {
|
|
28
86
|
"test": "echo 'No tests yet'"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="@cloudflare/workers-types" />
|
|
2
2
|
|
|
3
3
|
import { DurableObject } from 'cloudflare:workers'
|
|
4
|
+
|
|
4
5
|
import { type CfTypes, setupDurableObjectWebSocketRpc } from '@livestore/common-cf'
|
|
5
6
|
import { CfDeclare } from '@livestore/common-cf/declare'
|
|
6
7
|
import {
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
Schema,
|
|
15
16
|
type Scope,
|
|
16
17
|
} from '@livestore/utils/effect'
|
|
18
|
+
|
|
17
19
|
import {
|
|
18
20
|
type Env,
|
|
19
21
|
extractForwardedHeaders,
|
|
@@ -34,7 +36,7 @@ declare class Response extends CfDeclare.Response {}
|
|
|
34
36
|
declare class WebSocketPair extends CfDeclare.WebSocketPair {}
|
|
35
37
|
declare class WebSocketRequestResponsePair extends CfDeclare.WebSocketRequestResponsePair {}
|
|
36
38
|
|
|
37
|
-
const DurableObjectBase = DurableObject
|
|
39
|
+
const DurableObjectBase = DurableObject as any as new (
|
|
38
40
|
state: CfTypes.DurableObjectState,
|
|
39
41
|
env: Env,
|
|
40
42
|
) => CfTypes.DurableObject & { ctx: CfTypes.DurableObjectState; env: Env }
|
|
@@ -88,14 +90,14 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
|
|
|
88
90
|
|
|
89
91
|
const Logging = Logger.consoleWithThread('SyncDo')
|
|
90
92
|
|
|
91
|
-
const Observability = options?.otel?.baseUrl
|
|
92
|
-
? Otlp.layer({
|
|
93
|
+
const Observability: Layer.Layer<never> = options?.otel?.baseUrl !== undefined
|
|
94
|
+
? (Otlp.layer({
|
|
93
95
|
baseUrl: options.otel.baseUrl,
|
|
94
96
|
tracerExportInterval: 50,
|
|
95
97
|
resource: {
|
|
96
98
|
serviceName: options.otel.serviceName ?? 'sync-cf-do',
|
|
97
99
|
},
|
|
98
|
-
}).pipe(Layer.provide(FetchHttpClient.layer))
|
|
100
|
+
}).pipe(Layer.provide(FetchHttpClient.layer)) as Layer.Layer<never>)
|
|
99
101
|
: Layer.empty
|
|
100
102
|
|
|
101
103
|
return class SyncBackendDOBase extends DurableObjectBase implements SyncBackendRpcInterface {
|
|
@@ -107,7 +109,7 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
|
|
|
107
109
|
const WebSocketRpcServerLive = makeRpcServer({ doSelf: this, doOptions: options })
|
|
108
110
|
|
|
109
111
|
// This registers the `webSocketMessage` and `webSocketClose` handlers
|
|
110
|
-
if (enabledTransports.has('ws')) {
|
|
112
|
+
if (enabledTransports.has('ws') === true) {
|
|
111
113
|
setupDurableObjectWebSocketRpc({
|
|
112
114
|
doSelf: this,
|
|
113
115
|
rpcLayer: WebSocketRpcServerLive,
|
|
@@ -143,7 +145,7 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
|
|
|
143
145
|
}
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
fetch = async (request: Request): Promise<Response> =>
|
|
148
|
+
override fetch = async (request: Request): Promise<Response> =>
|
|
147
149
|
Effect.gen(this, function* () {
|
|
148
150
|
const searchParams = matchSyncRequest(request)
|
|
149
151
|
if (searchParams === undefined) {
|
|
@@ -228,8 +230,8 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
|
|
|
228
230
|
private handleHttp = (request: CfTypes.Request, forwardedHeaders: Record<string, string> | undefined) =>
|
|
229
231
|
createHttpRpcHandler({
|
|
230
232
|
request,
|
|
231
|
-
responseHeaders: options
|
|
232
|
-
forwardedHeaders,
|
|
233
|
+
...(options?.http?.responseHeaders !== undefined ? { responseHeaders: options.http.responseHeaders } : {}),
|
|
234
|
+
...(forwardedHeaders !== undefined ? { forwardedHeaders } : {}),
|
|
233
235
|
}).pipe(Effect.withSpan('@livestore/sync-cf:durable-object:handleHttp'))
|
|
234
236
|
|
|
235
237
|
private runEffectAsPromise = <T, E = never>(effect: Effect.Effect<T, E, Scope.Scope>): Promise<T> =>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { UnknownError } from '@livestore/common'
|
|
2
|
-
import { EventSequenceNumber, State } from '@livestore/common/schema'
|
|
3
2
|
import type { CfTypes } from '@livestore/common-cf'
|
|
3
|
+
import { EventSequenceNumber, State } from '@livestore/common/schema'
|
|
4
4
|
import { shouldNeverHappen } from '@livestore/utils'
|
|
5
5
|
import { Effect, Predicate } from '@livestore/utils/effect'
|
|
6
6
|
import { nanoid } from '@livestore/utils/nanoid'
|
|
7
|
+
|
|
7
8
|
import type { Env, MakeDurableObjectClassOptions, RpcSubscription } from '../shared.ts'
|
|
8
9
|
import { contextTable, eventlogTable } from './sqlite.ts'
|
|
9
10
|
import { makeStorage } from './sync-storage.ts'
|
|
@@ -27,7 +28,7 @@ export class DoCtx extends Effect.Service<DoCtx>()('DoCtx', {
|
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
const getStoreId = (from: CfTypes.Request | { storeId: string }) => {
|
|
30
|
-
if (Predicate.hasProperty(from, 'url')) {
|
|
31
|
+
if (Predicate.hasProperty(from, 'url') === true) {
|
|
31
32
|
const url = new URL(from.url)
|
|
32
33
|
return (
|
|
33
34
|
url.searchParams.get('storeId') ?? shouldNeverHappen(`No storeId provided in request URL search params`)
|
|
@@ -42,7 +43,7 @@ export class DoCtx extends Effect.Service<DoCtx>()('DoCtx', {
|
|
|
42
43
|
const opt = doOptions?.storage
|
|
43
44
|
if (opt?._tag === 'd1') {
|
|
44
45
|
const db = (doSelf.env as any)[opt.binding]
|
|
45
|
-
if (
|
|
46
|
+
if (db == null) {
|
|
46
47
|
return yield* UnknownError.make({ cause: new Error(`D1 binding '${opt.binding}' not found on env`) })
|
|
47
48
|
}
|
|
48
49
|
return { _tag: 'd1' as const, db }
|
package/src/cf-worker/do/pull.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { BackendIdMismatchError,
|
|
1
|
+
import { BackendIdMismatchError, SyncBackend, UnknownError } from '@livestore/common'
|
|
2
2
|
import { splitChunkBySize } from '@livestore/common/sync'
|
|
3
3
|
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
|
4
|
+
|
|
4
5
|
import { MAX_PULL_EVENTS_PER_MESSAGE, MAX_WS_MESSAGE_BYTES } from '../../common/constants.ts'
|
|
5
6
|
import { SyncMessage } from '../../common/mod.ts'
|
|
6
7
|
import type { ForwardedHeaders } from '../shared.ts'
|
|
@@ -25,12 +26,18 @@ export const makeEndingPullStream = ({
|
|
|
25
26
|
req: SyncMessage.PullRequest
|
|
26
27
|
payload: Schema.JsonValue | undefined
|
|
27
28
|
headers: ForwardedHeaders | undefined
|
|
28
|
-
}): Stream.Stream<SyncMessage.PullResponse,
|
|
29
|
+
}): Stream.Stream<SyncMessage.PullResponse, UnknownError | BackendIdMismatchError, DoCtx> =>
|
|
29
30
|
Effect.gen(function* () {
|
|
30
31
|
const { doOptions, backendId, storeId, storage } = yield* DoCtx
|
|
31
32
|
|
|
32
|
-
if (doOptions?.onPull) {
|
|
33
|
-
yield* Effect.tryAll(() =>
|
|
33
|
+
if (doOptions?.onPull !== undefined) {
|
|
34
|
+
yield* Effect.tryAll(() =>
|
|
35
|
+
doOptions.onPull!(req, {
|
|
36
|
+
storeId,
|
|
37
|
+
...(payload !== undefined ? { payload } : {}),
|
|
38
|
+
...(headers !== undefined ? { headers } : {}),
|
|
39
|
+
}),
|
|
40
|
+
).pipe(
|
|
34
41
|
UnknownError.mapToUnknownError,
|
|
35
42
|
)
|
|
36
43
|
}
|
|
@@ -69,7 +76,7 @@ export const makeEndingPullStream = ({
|
|
|
69
76
|
}),
|
|
70
77
|
Stream.tap(
|
|
71
78
|
Effect.fn(function* (res) {
|
|
72
|
-
if (doOptions?.onPullRes) {
|
|
79
|
+
if (doOptions?.onPullRes !== undefined) {
|
|
73
80
|
yield* Effect.tryAll(() => doOptions.onPullRes!(res)).pipe(UnknownError.mapToUnknownError)
|
|
74
81
|
}
|
|
75
82
|
}),
|
|
@@ -78,6 +85,10 @@ export const makeEndingPullStream = ({
|
|
|
78
85
|
)
|
|
79
86
|
}).pipe(
|
|
80
87
|
Stream.unwrap,
|
|
81
|
-
Stream.mapError((cause) =>
|
|
88
|
+
Stream.mapError((cause) =>
|
|
89
|
+
cause._tag === 'BackendIdMismatchError' || cause._tag === 'UnknownError'
|
|
90
|
+
? cause
|
|
91
|
+
: new UnknownError({ cause }),
|
|
92
|
+
),
|
|
82
93
|
Stream.withSpan('cloudflare-provider:pull'),
|
|
83
94
|
)
|
package/src/cf-worker/do/push.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BackendIdMismatchError,
|
|
3
|
-
InvalidPushError,
|
|
4
3
|
ServerAheadError,
|
|
5
4
|
SyncBackend,
|
|
6
5
|
UnknownError,
|
|
7
6
|
} from '@livestore/common'
|
|
8
|
-
import { splitChunkBySize } from '@livestore/common/sync'
|
|
9
7
|
import { type CfTypes, emitStreamResponse } from '@livestore/common-cf'
|
|
8
|
+
import { splitChunkBySize } from '@livestore/common/sync'
|
|
10
9
|
import { Chunk, Effect, Option, type RpcMessage, Schema } from '@livestore/utils/effect'
|
|
10
|
+
|
|
11
11
|
import { MAX_PUSH_EVENTS_PER_REQUEST, MAX_WS_MESSAGE_BYTES } from '../../common/constants.ts'
|
|
12
12
|
import { SyncMessage } from '../../common/mod.ts'
|
|
13
13
|
import {
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
import { DoCtx } from './layer.ts'
|
|
21
21
|
|
|
22
22
|
const encodePullResponse = Schema.encodeSync(SyncMessage.PullResponse)
|
|
23
|
+
const jsonStringify = Schema.encodeSync(Schema.parseJson())
|
|
23
24
|
type PullBatchItem = SyncMessage.PullResponse['batch'][number]
|
|
24
25
|
|
|
25
26
|
export const makePush =
|
|
@@ -47,8 +48,14 @@ export const makePush =
|
|
|
47
48
|
return SyncMessage.PushAck.make({})
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
if (options?.onPush) {
|
|
51
|
-
yield* Effect.tryAll(() =>
|
|
51
|
+
if (options?.onPush !== undefined) {
|
|
52
|
+
yield* Effect.tryAll(() =>
|
|
53
|
+
options.onPush!(pushRequest, {
|
|
54
|
+
storeId,
|
|
55
|
+
...(payload !== undefined ? { payload } : {}),
|
|
56
|
+
...(headers !== undefined ? { headers } : {}),
|
|
57
|
+
}),
|
|
58
|
+
).pipe(
|
|
52
59
|
UnknownError.mapToUnknownError,
|
|
53
60
|
)
|
|
54
61
|
}
|
|
@@ -134,13 +141,13 @@ export const makePush =
|
|
|
134
141
|
if (connectedClients.length > 0) {
|
|
135
142
|
for (const { response, encoded } of responses) {
|
|
136
143
|
// Only calling once for now.
|
|
137
|
-
if (options?.onPullRes) {
|
|
144
|
+
if (options?.onPullRes !== undefined) {
|
|
138
145
|
yield* Effect.tryAll(() => options.onPullRes!(response)).pipe(UnknownError.mapToUnknownError)
|
|
139
146
|
}
|
|
140
147
|
|
|
141
148
|
// NOTE we're also sending the pullRes chunk to the pushing ws client as confirmation
|
|
142
149
|
for (const conn of connectedClients) {
|
|
143
|
-
const attachment = Schema.
|
|
150
|
+
const attachment = yield* Schema.decode(WebSocketAttachmentSchema)(conn.deserializeAttachment())
|
|
144
151
|
|
|
145
152
|
// We're doing something a bit "advanced" here as we're directly emitting Effect RPC-compatible
|
|
146
153
|
// response messsages on the Effect RPC-managed websocket connection to the WS client.
|
|
@@ -151,7 +158,7 @@ export const makePush =
|
|
|
151
158
|
requestId,
|
|
152
159
|
values: [encoded],
|
|
153
160
|
}
|
|
154
|
-
conn.send(
|
|
161
|
+
conn.send(jsonStringify(res))
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
164
|
}
|
|
@@ -188,12 +195,16 @@ export const makePush =
|
|
|
188
195
|
}).pipe(
|
|
189
196
|
Effect.tap(
|
|
190
197
|
Effect.fn(function* (message) {
|
|
191
|
-
if (options?.onPushRes) {
|
|
198
|
+
if (options?.onPushRes !== undefined) {
|
|
192
199
|
yield* Effect.tryAll(() => options.onPushRes!(message)).pipe(UnknownError.mapToUnknownError)
|
|
193
200
|
}
|
|
194
201
|
}),
|
|
195
202
|
),
|
|
196
|
-
Effect.mapError((cause) =>
|
|
203
|
+
Effect.mapError((cause) =>
|
|
204
|
+
cause._tag === 'BackendIdMismatchError' || cause._tag === 'ServerAheadError' || cause._tag === 'UnknownError'
|
|
205
|
+
? cause
|
|
206
|
+
: new UnknownError({ cause }),
|
|
207
|
+
),
|
|
197
208
|
Effect.withSpan('sync-cf:do:push', { attributes: { storeId, batchSize: pushRequest.batch.length } }),
|
|
198
209
|
)
|
|
199
210
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { UnknownError } from '@livestore/common'
|
|
2
|
-
import type { LiveStoreEvent } from '@livestore/common/schema'
|
|
3
2
|
import type { CfTypes } from '@livestore/common-cf'
|
|
3
|
+
import type { LiveStoreEvent } from '@livestore/common/schema'
|
|
4
4
|
import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
|
|
5
|
+
|
|
5
6
|
import { SyncMetadata } from '../../common/sync-message-types.ts'
|
|
6
7
|
import { PERSISTENCE_FORMAT_VERSION, type StoreId } from '../shared.ts'
|
|
7
8
|
import { eventlogTable } from './sqlite.ts'
|
|
@@ -51,6 +52,7 @@ export const makeStorage = (
|
|
|
51
52
|
const D1_MIN_PAGE_SIZE = 1
|
|
52
53
|
|
|
53
54
|
const decodeEventlogRows = Schema.decodeUnknownSync(Schema.Array(eventlogTable.rowSchema))
|
|
55
|
+
const jsonStringify = Schema.encodeSync(Schema.parseJson())
|
|
54
56
|
const textEncoder = new TextEncoder()
|
|
55
57
|
|
|
56
58
|
const decreaseLimit = (limit: number) => Math.max(D1_MIN_PAGE_SIZE, Math.floor(limit / 2))
|
|
@@ -120,7 +122,7 @@ export const makeStorage = (
|
|
|
120
122
|
return Option.none()
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
const encodedSize = textEncoder.encode(
|
|
125
|
+
const encodedSize = textEncoder.encode(jsonStringify(rawEvents)).byteLength
|
|
124
126
|
|
|
125
127
|
if (encodedSize > D1_TARGET_RESPONSE_BYTES && state.limit > D1_MIN_PAGE_SIZE) {
|
|
126
128
|
const nextLimit = decreaseLimit(state.limit)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UnknownError } from '@livestore/common'
|
|
2
2
|
import { type CfTypes, toDurableObjectHandler } from '@livestore/common-cf'
|
|
3
3
|
import {
|
|
4
4
|
Effect,
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
RpcSerialization,
|
|
12
12
|
Stream,
|
|
13
13
|
} from '@livestore/utils/effect'
|
|
14
|
+
|
|
14
15
|
import { SyncDoRpc } from '../../../common/do-rpc-schema.ts'
|
|
15
16
|
import { SyncMessage } from '../../../common/mod.ts'
|
|
16
17
|
import { DoCtx, type DoCtxInput } from '../layer.ts'
|
|
@@ -39,13 +40,13 @@ export const createDoRpcHandler = (
|
|
|
39
40
|
const { rpcSubscriptions } = yield* DoCtx
|
|
40
41
|
|
|
41
42
|
// TODO rename `req.rpcContext` to something more appropriate
|
|
42
|
-
if (req.rpcContext) {
|
|
43
|
+
if (req.rpcContext !== undefined) {
|
|
43
44
|
rpcSubscriptions.set(req.storeId, {
|
|
44
45
|
storeId: req.storeId,
|
|
45
|
-
payload: req.payload,
|
|
46
46
|
subscribedAt: Date.now(),
|
|
47
47
|
requestId: Headers.get(headers, 'x-rpc-request-id').pipe(Option.getOrThrow),
|
|
48
48
|
callerContext: req.rpcContext.callerContext,
|
|
49
|
+
...(req.payload !== undefined ? { payload: req.payload } : {}),
|
|
49
50
|
})
|
|
50
51
|
}
|
|
51
52
|
|
|
@@ -58,7 +59,11 @@ export const createDoRpcHandler = (
|
|
|
58
59
|
rpcRequestId: Headers.get(headers, 'x-rpc-request-id').pipe(Option.getOrThrow),
|
|
59
60
|
})),
|
|
60
61
|
Stream.provideLayer(DoCtx.Default({ ...input, from: { storeId: req.storeId } })),
|
|
61
|
-
Stream.mapError((cause) =>
|
|
62
|
+
Stream.mapError((cause) =>
|
|
63
|
+
cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
64
|
+
? cause
|
|
65
|
+
: new UnknownError({ cause }),
|
|
66
|
+
),
|
|
62
67
|
Stream.tapErrorCause(Effect.log),
|
|
63
68
|
),
|
|
64
69
|
'SyncDoRpc.Push': (req) =>
|
|
@@ -70,7 +75,11 @@ export const createDoRpcHandler = (
|
|
|
70
75
|
return yield* push(req)
|
|
71
76
|
}).pipe(
|
|
72
77
|
Effect.provide(DoCtx.Default({ ...input, from: { storeId: req.storeId } })),
|
|
73
|
-
Effect.mapError((cause) =>
|
|
78
|
+
Effect.mapError((cause) =>
|
|
79
|
+
cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
80
|
+
? cause
|
|
81
|
+
: new UnknownError({ cause }),
|
|
82
|
+
),
|
|
74
83
|
Effect.tapCauseLogPretty,
|
|
75
84
|
),
|
|
76
85
|
})
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CfTypes } from '@livestore/common-cf'
|
|
2
2
|
import { Effect, HttpApp, Layer, RpcSerialization, RpcServer } from '@livestore/utils/effect'
|
|
3
|
+
|
|
3
4
|
import { SyncHttpRpc } from '../../../common/http-rpc-schema.ts'
|
|
4
5
|
import * as SyncMessage from '../../../common/sync-message-types.ts'
|
|
5
6
|
import { headersRecordToMap } from '../../shared.ts'
|
|
@@ -7,7 +8,7 @@ import { DoCtx } from '../layer.ts'
|
|
|
7
8
|
import { makeEndingPullStream } from '../pull.ts'
|
|
8
9
|
import { makePush } from '../push.ts'
|
|
9
10
|
|
|
10
|
-
export const createHttpRpcHandler = ({
|
|
11
|
+
export const createHttpRpcHandler = Effect.fn('createHttpRpcHandler')(function* ({
|
|
11
12
|
request,
|
|
12
13
|
responseHeaders,
|
|
13
14
|
forwardedHeaders,
|
|
@@ -15,24 +16,23 @@ export const createHttpRpcHandler = ({
|
|
|
15
16
|
request: CfTypes.Request
|
|
16
17
|
responseHeaders?: Record<string, string>
|
|
17
18
|
forwardedHeaders?: Record<string, string>
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
response.headers.set(key, value)
|
|
31
|
-
}
|
|
19
|
+
}) {
|
|
20
|
+
const handlerLayer = createHttpRpcLayer(forwardedHeaders)
|
|
21
|
+
const httpApp = RpcServer.toHttpApp(SyncHttpRpc).pipe(Effect.provide(handlerLayer))
|
|
22
|
+
const webHandler = yield* httpApp.pipe(Effect.map(HttpApp.toWebHandler))
|
|
23
|
+
|
|
24
|
+
const response = yield* Effect.promise(
|
|
25
|
+
() => webHandler(request as TODO as Request) as TODO as Promise<CfTypes.Response>,
|
|
26
|
+
).pipe(Effect.timeout(10000))
|
|
27
|
+
|
|
28
|
+
if (responseHeaders !== undefined) {
|
|
29
|
+
for (const [key, value] of Object.entries(responseHeaders)) {
|
|
30
|
+
response.headers.set(key, value)
|
|
32
31
|
}
|
|
32
|
+
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
return response
|
|
35
|
+
})
|
|
36
36
|
|
|
37
37
|
const createHttpRpcLayer = (forwardedHeaders: Record<string, string> | undefined) => {
|
|
38
38
|
const headers = headersRecordToMap(forwardedHeaders)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UnknownError } from '@livestore/common'
|
|
2
2
|
import { WsContext } from '@livestore/common-cf'
|
|
3
3
|
import { Effect, identity, Layer, RpcServer, Schema, Stream } from '@livestore/utils/effect'
|
|
4
|
+
|
|
4
5
|
import { SyncWsRpc } from '../../../common/ws-rpc-schema.ts'
|
|
5
6
|
import { headersRecordToMap, WebSocketAttachmentSchema } from '../../shared.ts'
|
|
6
7
|
import { DoCtx, type DoCtxInput } from '../layer.ts'
|
|
@@ -14,9 +15,13 @@ export const makeRpcServer = ({ doSelf, doOptions }: Omit<DoCtxInput, 'from'>) =
|
|
|
14
15
|
const headers = yield* getForwardedHeaders
|
|
15
16
|
return makeEndingPullStream({ req, payload: req.payload, headers }).pipe(
|
|
16
17
|
// Needed to keep the stream alive on the client side for phase 2 (i.e. not send the `Exit` stream RPC message)
|
|
17
|
-
req.live ? Stream.concat(Stream.never) : identity,
|
|
18
|
+
req.live === true ? Stream.concat(Stream.never) : identity,
|
|
18
19
|
Stream.provideLayer(DoCtx.Default({ doSelf, doOptions, from: { storeId: req.storeId } })),
|
|
19
|
-
Stream.mapError((cause) =>
|
|
20
|
+
Stream.mapError((cause) =>
|
|
21
|
+
cause._tag === 'UnknownError' || cause._tag === 'BackendIdMismatchError'
|
|
22
|
+
? cause
|
|
23
|
+
: new UnknownError({ cause }),
|
|
24
|
+
),
|
|
20
25
|
)
|
|
21
26
|
}).pipe(Stream.unwrap),
|
|
22
27
|
'SyncWsRpc.Push': (req) =>
|
|
@@ -29,7 +34,11 @@ export const makeRpcServer = ({ doSelf, doOptions }: Omit<DoCtxInput, 'from'>) =
|
|
|
29
34
|
return yield* push(req)
|
|
30
35
|
}).pipe(
|
|
31
36
|
Effect.provide(DoCtx.Default({ doSelf, doOptions, from: { storeId: req.storeId } })),
|
|
32
|
-
Effect.mapError((cause) =>
|
|
37
|
+
Effect.mapError((cause) =>
|
|
38
|
+
cause._tag === 'UnknownError' || cause._tag === 'ServerAheadError' || cause._tag === 'BackendIdMismatchError'
|
|
39
|
+
? cause
|
|
40
|
+
: new UnknownError({ cause }),
|
|
41
|
+
),
|
|
33
42
|
Effect.tapCauseLogPretty,
|
|
34
43
|
),
|
|
35
44
|
})
|
package/src/cf-worker/shared.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnknownError } from '@livestore/common'
|
|
2
2
|
import type { CfTypes } from '@livestore/common-cf'
|
|
3
3
|
import { Effect, Schema, UrlParams } from '@livestore/utils/effect'
|
|
4
4
|
|
|
@@ -27,9 +27,9 @@ export type CallbackContext = {
|
|
|
27
27
|
|
|
28
28
|
export type MakeDurableObjectClassOptions = {
|
|
29
29
|
onPush?: (message: SyncMessage.PushRequest, context: CallbackContext) => Effect.SyncOrPromiseOrEffect<void>
|
|
30
|
-
onPushRes?: (message: SyncMessage.PushAck |
|
|
30
|
+
onPushRes?: (message: SyncMessage.PushAck | UnknownError) => Effect.SyncOrPromiseOrEffect<void>
|
|
31
31
|
onPull?: (message: SyncMessage.PullRequest, context: CallbackContext) => Effect.SyncOrPromiseOrEffect<void>
|
|
32
|
-
onPullRes?: (message: SyncMessage.PullResponse |
|
|
32
|
+
onPullRes?: (message: SyncMessage.PullResponse | UnknownError) => Effect.SyncOrPromiseOrEffect<void>
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Forward request headers to `onPush`/`onPull` callbacks for authentication.
|