@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.
Files changed (78) hide show
  1. package/README.md +6 -7
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
  4. package/dist/cf-worker/do/durable-object.js +5 -5
  5. package/dist/cf-worker/do/durable-object.js.map +1 -1
  6. package/dist/cf-worker/do/layer.d.ts +1 -1
  7. package/dist/cf-worker/do/layer.d.ts.map +1 -1
  8. package/dist/cf-worker/do/layer.js +2 -2
  9. package/dist/cf-worker/do/layer.js.map +1 -1
  10. package/dist/cf-worker/do/pull.d.ts +2 -2
  11. package/dist/cf-worker/do/pull.d.ts.map +1 -1
  12. package/dist/cf-worker/do/pull.js +11 -5
  13. package/dist/cf-worker/do/pull.js.map +1 -1
  14. package/dist/cf-worker/do/push.d.ts +2 -2
  15. package/dist/cf-worker/do/push.d.ts.map +1 -1
  16. package/dist/cf-worker/do/push.js +16 -9
  17. package/dist/cf-worker/do/push.js.map +1 -1
  18. package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
  19. package/dist/cf-worker/do/sqlite.js.map +1 -1
  20. package/dist/cf-worker/do/sync-storage.d.ts +1 -1
  21. package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
  22. package/dist/cf-worker/do/sync-storage.js +2 -1
  23. package/dist/cf-worker/do/sync-storage.js.map +1 -1
  24. package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
  25. package/dist/cf-worker/do/transport/do-rpc-server.js +9 -5
  26. package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
  27. package/dist/cf-worker/do/transport/http-rpc-server.d.ts +1 -1
  28. package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
  29. package/dist/cf-worker/do/transport/http-rpc-server.js +2 -2
  30. package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
  31. package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
  32. package/dist/cf-worker/do/transport/ws-rpc-server.js +7 -3
  33. package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
  34. package/dist/cf-worker/shared.d.ts +7 -7
  35. package/dist/cf-worker/shared.d.ts.map +1 -1
  36. package/dist/cf-worker/worker.d.ts.map +1 -1
  37. package/dist/cf-worker/worker.js +7 -7
  38. package/dist/cf-worker/worker.js.map +1 -1
  39. package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
  40. package/dist/client/transport/do-rpc-client.js +11 -7
  41. package/dist/client/transport/do-rpc-client.js.map +1 -1
  42. package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
  43. package/dist/client/transport/http-rpc-client.js +10 -6
  44. package/dist/client/transport/http-rpc-client.js.map +1 -1
  45. package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
  46. package/dist/client/transport/ws-rpc-client.js +11 -11
  47. package/dist/client/transport/ws-rpc-client.js.map +1 -1
  48. package/dist/common/do-rpc-schema.d.ts +3 -3
  49. package/dist/common/do-rpc-schema.d.ts.map +1 -1
  50. package/dist/common/do-rpc-schema.js +3 -3
  51. package/dist/common/do-rpc-schema.js.map +1 -1
  52. package/dist/common/http-rpc-schema.d.ts +3 -3
  53. package/dist/common/http-rpc-schema.d.ts.map +1 -1
  54. package/dist/common/http-rpc-schema.js +3 -3
  55. package/dist/common/http-rpc-schema.js.map +1 -1
  56. package/dist/common/sync-message-types.d.ts +2 -2
  57. package/dist/common/ws-rpc-schema.d.ts +3 -3
  58. package/dist/common/ws-rpc-schema.d.ts.map +1 -1
  59. package/dist/common/ws-rpc-schema.js +3 -3
  60. package/dist/common/ws-rpc-schema.js.map +1 -1
  61. package/package.json +71 -13
  62. package/src/cf-worker/do/durable-object.ts +10 -8
  63. package/src/cf-worker/do/layer.ts +4 -3
  64. package/src/cf-worker/do/pull.ts +17 -6
  65. package/src/cf-worker/do/push.ts +20 -9
  66. package/src/cf-worker/do/sqlite.ts +1 -0
  67. package/src/cf-worker/do/sync-storage.ts +4 -2
  68. package/src/cf-worker/do/transport/do-rpc-server.ts +14 -5
  69. package/src/cf-worker/do/transport/http-rpc-server.ts +17 -17
  70. package/src/cf-worker/do/transport/ws-rpc-server.ts +13 -4
  71. package/src/cf-worker/shared.ts +3 -3
  72. package/src/cf-worker/worker.ts +17 -14
  73. package/src/client/transport/do-rpc-client.ts +20 -14
  74. package/src/client/transport/http-rpc-client.ts +19 -13
  75. package/src/client/transport/ws-rpc-client.ts +39 -36
  76. package/src/common/do-rpc-schema.ts +4 -3
  77. package/src/common/http-rpc-schema.ts +4 -3
  78. package/src/common/ws-rpc-schema.ts +4 -3
@@ -1,4 +1,4 @@
1
- import { InvalidPullError, InvalidPushError } from '@livestore/common';
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 InvalidPullError>, typeof Schema.Never, never> | Rpc.Rpc<"SyncWsRpc.Push", Schema.Struct<{
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 InvalidPushError, never>>;
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,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;;;;;;;;IAezD,qEAAqE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAZ3E;;;;;;GAMG;AACH,qBAAa,SAAU,SAAQ,cAwB9B;CAAG"}
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 { InvalidPullError, InvalidPushError } from '@livestore/common';
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: InvalidPullError,
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: InvalidPushError,
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,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAC/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,gBAAgB;IACvB,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,gBAAgB;CACxB,CAAC,CAGH;CAAG"}
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.22",
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-cf": "0.4.0-dev.22",
14
- "@livestore/utils": "0.4.0-dev.22",
15
- "@livestore/common": "0.4.0-dev.22"
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
- "files": [
18
- "dist",
19
- "src",
20
- "package.json",
21
- "README.md"
22
- ],
23
- "license": "Apache-2.0",
24
- "publishConfig": {
25
- "access": "public"
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<Env> as any as new (
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?.http?.responseHeaders,
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 (!db) {
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 }
@@ -1,6 +1,7 @@
1
- import { BackendIdMismatchError, InvalidPullError, SyncBackend, UnknownError } from '@livestore/common'
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, InvalidPullError, DoCtx> =>
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(() => doOptions!.onPull!(req, { storeId, payload, headers })).pipe(
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) => InvalidPullError.make({ 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
  )
@@ -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(() => options.onPush!(pushRequest, { storeId, payload, headers })).pipe(
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.decodeSync(WebSocketAttachmentSchema)(conn.deserializeAttachment())
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(JSON.stringify(res))
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) => InvalidPushError.make({ 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,5 +1,6 @@
1
1
  import { EventSequenceNumber, State } from '@livestore/common/schema'
2
2
  import { Schema } from '@livestore/utils/effect'
3
+
3
4
  import { PERSISTENCE_FORMAT_VERSION } from '../shared.ts'
4
5
 
5
6
  /**
@@ -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(JSON.stringify(rawEvents)).byteLength
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 { InvalidPullError, InvalidPushError } from '@livestore/common'
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) => (cause._tag === 'InvalidPullError' ? cause : InvalidPullError.make({ 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) => (cause._tag === 'InvalidPushError' ? cause : InvalidPushError.make({ 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
- Effect.gen(function* () {
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)
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
- return response
35
- }).pipe(Effect.withSpan('createHttpRpcHandler'))
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 { InvalidPullError, InvalidPushError } from '@livestore/common'
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) => (cause._tag === 'InvalidPullError' ? cause : InvalidPullError.make({ 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) => (cause._tag === 'InvalidPushError' ? cause : InvalidPushError.make({ 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
  })
@@ -1,4 +1,4 @@
1
- import type { InvalidPullError, InvalidPushError } from '@livestore/common'
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 | InvalidPushError) => Effect.SyncOrPromiseOrEffect<void>
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 | InvalidPullError) => Effect.SyncOrPromiseOrEffect<void>
32
+ onPullRes?: (message: SyncMessage.PullResponse | UnknownError) => Effect.SyncOrPromiseOrEffect<void>
33
33
 
34
34
  /**
35
35
  * Forward request headers to `onPush`/`onPull` callbacks for authentication.