@livestore/sync-cf 0.4.0-dev.9 → 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.
Files changed (104) hide show
  1. package/README.md +7 -8
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/cf-worker/do/durable-object.d.ts +1 -1
  4. package/dist/cf-worker/do/durable-object.d.ts.map +1 -1
  5. package/dist/cf-worker/do/durable-object.js +13 -8
  6. package/dist/cf-worker/do/durable-object.js.map +1 -1
  7. package/dist/cf-worker/do/layer.d.ts +5 -5
  8. package/dist/cf-worker/do/layer.d.ts.map +1 -1
  9. package/dist/cf-worker/do/layer.js +32 -9
  10. package/dist/cf-worker/do/layer.js.map +1 -1
  11. package/dist/cf-worker/do/pull.d.ts +7 -2
  12. package/dist/cf-worker/do/pull.d.ts.map +1 -1
  13. package/dist/cf-worker/do/pull.js +16 -10
  14. package/dist/cf-worker/do/pull.js.map +1 -1
  15. package/dist/cf-worker/do/push.d.ts +5 -4
  16. package/dist/cf-worker/do/push.d.ts.map +1 -1
  17. package/dist/cf-worker/do/push.js +25 -17
  18. package/dist/cf-worker/do/push.js.map +1 -1
  19. package/dist/cf-worker/do/sqlite.d.ts +10 -1
  20. package/dist/cf-worker/do/sqlite.d.ts.map +1 -1
  21. package/dist/cf-worker/do/sqlite.js +13 -4
  22. package/dist/cf-worker/do/sqlite.js.map +1 -1
  23. package/dist/cf-worker/do/sync-storage.d.ts +14 -9
  24. package/dist/cf-worker/do/sync-storage.d.ts.map +1 -1
  25. package/dist/cf-worker/do/sync-storage.js +92 -18
  26. package/dist/cf-worker/do/sync-storage.js.map +1 -1
  27. package/dist/cf-worker/do/transport/do-rpc-server.d.ts.map +1 -1
  28. package/dist/cf-worker/do/transport/do-rpc-server.js +13 -7
  29. package/dist/cf-worker/do/transport/do-rpc-server.js.map +1 -1
  30. package/dist/cf-worker/do/transport/http-rpc-server.d.ts +4 -2
  31. package/dist/cf-worker/do/transport/http-rpc-server.d.ts.map +1 -1
  32. package/dist/cf-worker/do/transport/http-rpc-server.js +24 -15
  33. package/dist/cf-worker/do/transport/http-rpc-server.js.map +1 -1
  34. package/dist/cf-worker/do/transport/ws-rpc-server.d.ts +2 -1
  35. package/dist/cf-worker/do/transport/ws-rpc-server.d.ts.map +1 -1
  36. package/dist/cf-worker/do/transport/ws-rpc-server.js +30 -8
  37. package/dist/cf-worker/do/transport/ws-rpc-server.js.map +1 -1
  38. package/dist/cf-worker/shared.d.ts +118 -31
  39. package/dist/cf-worker/shared.d.ts.map +1 -1
  40. package/dist/cf-worker/shared.js +40 -7
  41. package/dist/cf-worker/shared.js.map +1 -1
  42. package/dist/cf-worker/worker.d.ts +46 -38
  43. package/dist/cf-worker/worker.d.ts.map +1 -1
  44. package/dist/cf-worker/worker.js +51 -34
  45. package/dist/cf-worker/worker.js.map +1 -1
  46. package/dist/client/transport/do-rpc-client.d.ts.map +1 -1
  47. package/dist/client/transport/do-rpc-client.js +27 -10
  48. package/dist/client/transport/do-rpc-client.js.map +1 -1
  49. package/dist/client/transport/http-rpc-client.d.ts.map +1 -1
  50. package/dist/client/transport/http-rpc-client.js +29 -9
  51. package/dist/client/transport/http-rpc-client.js.map +1 -1
  52. package/dist/client/transport/ws-rpc-client.d.ts +2 -1
  53. package/dist/client/transport/ws-rpc-client.d.ts.map +1 -1
  54. package/dist/client/transport/ws-rpc-client.js +31 -17
  55. package/dist/client/transport/ws-rpc-client.js.map +1 -1
  56. package/dist/common/constants.d.ts +7 -0
  57. package/dist/common/constants.d.ts.map +1 -0
  58. package/dist/common/constants.js +17 -0
  59. package/dist/common/constants.js.map +1 -0
  60. package/dist/common/do-rpc-schema.d.ts +6 -6
  61. package/dist/common/do-rpc-schema.d.ts.map +1 -1
  62. package/dist/common/do-rpc-schema.js +4 -4
  63. package/dist/common/do-rpc-schema.js.map +1 -1
  64. package/dist/common/http-rpc-schema.d.ts +4 -4
  65. package/dist/common/http-rpc-schema.d.ts.map +1 -1
  66. package/dist/common/http-rpc-schema.js +4 -4
  67. package/dist/common/http-rpc-schema.js.map +1 -1
  68. package/dist/common/mod.d.ts +4 -1
  69. package/dist/common/mod.d.ts.map +1 -1
  70. package/dist/common/mod.js +4 -1
  71. package/dist/common/mod.js.map +1 -1
  72. package/dist/common/sync-message-types.d.ts +7 -7
  73. package/dist/common/sync-message-types.js +3 -3
  74. package/dist/common/sync-message-types.js.map +1 -1
  75. package/dist/common/ws-rpc-schema.d.ts +3 -3
  76. package/dist/common/ws-rpc-schema.d.ts.map +1 -1
  77. package/dist/common/ws-rpc-schema.js +3 -3
  78. package/dist/common/ws-rpc-schema.js.map +1 -1
  79. package/package.json +72 -14
  80. package/src/cf-worker/do/durable-object.ts +19 -10
  81. package/src/cf-worker/do/layer.ts +35 -13
  82. package/src/cf-worker/do/pull.ts +31 -14
  83. package/src/cf-worker/do/push.ts +49 -34
  84. package/src/cf-worker/do/sqlite.ts +14 -4
  85. package/src/cf-worker/do/sync-storage.ts +151 -31
  86. package/src/cf-worker/do/transport/do-rpc-server.ts +18 -7
  87. package/src/cf-worker/do/transport/http-rpc-server.ts +33 -13
  88. package/src/cf-worker/do/transport/ws-rpc-server.ts +40 -12
  89. package/src/cf-worker/shared.ts +136 -25
  90. package/src/cf-worker/worker.ts +107 -54
  91. package/src/client/transport/do-rpc-client.ts +41 -17
  92. package/src/client/transport/http-rpc-client.ts +43 -17
  93. package/src/client/transport/ws-rpc-client.ts +42 -19
  94. package/src/common/constants.ts +18 -0
  95. package/src/common/do-rpc-schema.ts +5 -4
  96. package/src/common/http-rpc-schema.ts +5 -4
  97. package/src/common/mod.ts +4 -2
  98. package/src/common/sync-message-types.ts +3 -3
  99. package/src/common/ws-rpc-schema.ts +4 -3
  100. package/dist/cf-worker/do/ws-chunking.d.ts +0 -22
  101. package/dist/cf-worker/do/ws-chunking.d.ts.map +0 -1
  102. package/dist/cf-worker/do/ws-chunking.js +0 -49
  103. package/dist/cf-worker/do/ws-chunking.js.map +0 -1
  104. package/src/cf-worker/do/ws-chunking.ts +0 -76
@@ -42,19 +42,20 @@ export declare const PullResponse: Schema.Struct<{
42
42
  backendId: Schema.SchemaClass<string, string, never>;
43
43
  }>;
44
44
  export declare const emptyPullResponse: (backendId: string) => {
45
+ readonly backendId: string;
45
46
  readonly batch: readonly {
47
+ readonly metadata: import("effect/Option").Option<{
48
+ readonly createdAt: string;
49
+ readonly _tag: "SyncMessage.SyncMetadata";
50
+ }>;
46
51
  readonly eventEncoded: {
47
52
  readonly name: string;
48
53
  readonly args: any;
49
- readonly seqNum: any;
50
- readonly parentSeqNum: any;
54
+ readonly seqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
55
+ readonly parentSeqNum: number & import("effect/Brand").Brand<"GlobalEventSequenceNumber">;
51
56
  readonly clientId: string;
52
57
  readonly sessionId: string;
53
58
  };
54
- readonly metadata: import("effect/Option").Option<{
55
- readonly _tag: "SyncMessage.SyncMetadata";
56
- readonly createdAt: string;
57
- }>;
58
59
  }[];
59
60
  readonly pageInfo: {
60
61
  readonly _tag: "MoreUnknown";
@@ -64,7 +65,6 @@ export declare const emptyPullResponse: (backendId: string) => {
64
65
  } | {
65
66
  readonly _tag: "NoMore";
66
67
  };
67
- readonly backendId: string;
68
68
  };
69
69
  export type PullResponse = typeof PullResponse.Type;
70
70
  export declare const PushRequest: Schema.Struct<{
@@ -14,12 +14,12 @@ export const PullRequest = Schema.Struct({
14
14
  /** Omitting the cursor will start from the beginning */
15
15
  cursor: Schema.Option(Schema.Struct({
16
16
  backendId: BackendId,
17
- eventSequenceNumber: EventSequenceNumber.GlobalEventSequenceNumber,
17
+ eventSequenceNumber: EventSequenceNumber.Global.Schema,
18
18
  })),
19
19
  }).annotations({ title: '@livestore/sync-cf:PullRequest' });
20
20
  export const PullResponse = Schema.Struct({
21
21
  batch: Schema.Array(Schema.Struct({
22
- eventEncoded: LiveStoreEvent.AnyEncodedGlobal,
22
+ eventEncoded: LiveStoreEvent.Global.Encoded,
23
23
  metadata: Schema.Option(SyncMetadata),
24
24
  })),
25
25
  pageInfo: SyncBackend.PullResPageInfo,
@@ -31,7 +31,7 @@ export const emptyPullResponse = (backendId) => PullResponse.make({
31
31
  backendId,
32
32
  });
33
33
  export const PushRequest = Schema.Struct({
34
- batch: Schema.Array(LiveStoreEvent.AnyEncodedGlobal),
34
+ batch: Schema.Array(LiveStoreEvent.Global.Encoded),
35
35
  backendId: Schema.Option(BackendId),
36
36
  }).annotations({ title: '@livestore/sync-cf:PushRequest' });
37
37
  export const PushAck = Schema.Struct({}).annotations({
@@ -1 +1 @@
1
- {"version":3,"file":"sync-message-types.js","sourceRoot":"","sources":["../../src/common/sync-message-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync-message-types.js","sourceRoot":"","sources":["../../src/common/sync-message-types.ts"],"names":[],"mappings":"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"}
@@ -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.9",
3
+ "version": "0.4.0",
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,22 +19,69 @@
8
19
  "./common": "./dist/common/mod.js",
9
20
  "./cf-worker": "./dist/cf-worker/mod.js"
10
21
  },
11
- "dependencies": {
12
- "@cloudflare/workers-types": "4.20250923.0",
13
- "@livestore/common": "0.4.0-dev.9",
14
- "@livestore/common-cf": "0.4.0-dev.9",
15
- "@livestore/utils": "0.4.0-dev.9"
16
- },
17
- "files": [
18
- "dist",
19
- "src",
20
- "package.json",
21
- "README.md"
22
- ],
23
- "license": "Apache-2.0",
24
22
  "publishConfig": {
25
23
  "access": "public"
26
24
  },
25
+ "dependencies": {
26
+ "@cloudflare/workers-types": "4.20251118.0",
27
+ "@livestore/common": "^0.4.0",
28
+ "@livestore/common-cf": "^0.4.0",
29
+ "@livestore/utils": "^0.4.0"
30
+ },
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
+ ]
84
+ },
27
85
  "scripts": {
28
86
  "test": "echo 'No tests yet'"
29
87
  }
@@ -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,8 +15,10 @@ import {
14
15
  Schema,
15
16
  type Scope,
16
17
  } from '@livestore/utils/effect'
18
+
17
19
  import {
18
20
  type Env,
21
+ extractForwardedHeaders,
19
22
  type MakeDurableObjectClassOptions,
20
23
  matchSyncRequest,
21
24
  type SyncBackendRpcInterface,
@@ -33,7 +36,7 @@ declare class Response extends CfDeclare.Response {}
33
36
  declare class WebSocketPair extends CfDeclare.WebSocketPair {}
34
37
  declare class WebSocketRequestResponsePair extends CfDeclare.WebSocketRequestResponsePair {}
35
38
 
36
- const DurableObjectBase = DurableObject<Env> as any as new (
39
+ const DurableObjectBase = DurableObject as any as new (
37
40
  state: CfTypes.DurableObjectState,
38
41
  env: Env,
39
42
  ) => CfTypes.DurableObject & { ctx: CfTypes.DurableObjectState; env: Env }
@@ -48,7 +51,7 @@ export type MakeDurableObjectClass = (options?: MakeDurableObjectClassOptions) =
48
51
 
49
52
  /**
50
53
  * Creates a Durable Object class for handling WebSocket-based sync.
51
- * A sync durable object is uniquely scoped to a specific `storeId`.
54
+ * A sync Durable Object is uniquely scoped to a specific `storeId`.
52
55
  *
53
56
  * The sync DO supports 3 transport modes:
54
57
  * - HTTP JSON-RPC
@@ -87,14 +90,14 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
87
90
 
88
91
  const Logging = Logger.consoleWithThread('SyncDo')
89
92
 
90
- const Observability = options?.otel?.baseUrl
91
- ? Otlp.layer({
93
+ const Observability: Layer.Layer<never> = options?.otel?.baseUrl !== undefined
94
+ ? (Otlp.layer({
92
95
  baseUrl: options.otel.baseUrl,
93
96
  tracerExportInterval: 50,
94
97
  resource: {
95
98
  serviceName: options.otel.serviceName ?? 'sync-cf-do',
96
99
  },
97
- }).pipe(Layer.provide(FetchHttpClient.layer))
100
+ }).pipe(Layer.provide(FetchHttpClient.layer)) as Layer.Layer<never>)
98
101
  : Layer.empty
99
102
 
100
103
  return class SyncBackendDOBase extends DurableObjectBase implements SyncBackendRpcInterface {
@@ -106,7 +109,7 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
106
109
  const WebSocketRpcServerLive = makeRpcServer({ doSelf: this, doOptions: options })
107
110
 
108
111
  // This registers the `webSocketMessage` and `webSocketClose` handlers
109
- if (enabledTransports.has('ws')) {
112
+ if (enabledTransports.has('ws') === true) {
110
113
  setupDurableObjectWebSocketRpc({
111
114
  doSelf: this,
112
115
  rpcLayer: WebSocketRpcServerLive,
@@ -142,7 +145,7 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
142
145
  }
143
146
  }
144
147
 
145
- fetch = async (request: Request): Promise<Response> =>
148
+ override fetch = async (request: Request): Promise<Response> =>
146
149
  Effect.gen(this, function* () {
147
150
  const searchParams = matchSyncRequest(request)
148
151
  if (searchParams === undefined) {
@@ -155,16 +158,20 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
155
158
  throw new Error(`Transport ${transport} is not enabled (based on \`options.enabledTransports\`)`)
156
159
  }
157
160
 
161
+ // Extract headers to forward based on configuration (available for all transports)
162
+ const headers = extractForwardedHeaders(request, options?.forwardHeaders)
163
+
158
164
  if (transport === 'http') {
159
- return yield* this.handleHttp(request)
165
+ return yield* this.handleHttp(request, headers)
160
166
  }
161
167
 
162
168
  if (transport === 'ws') {
163
169
  const { 0: client, 1: server } = new WebSocketPair()
164
170
 
165
171
  // Since we're using websocket hibernation, we need to remember the storeId for subsequent `webSocketMessage` calls
172
+ // Also store forwarded headers so they're available after hibernation resume
166
173
  server.serializeAttachment(
167
- Schema.encodeSync(WebSocketAttachmentSchema)({ storeId, payload, pullRequestIds: [] }),
174
+ Schema.encodeSync(WebSocketAttachmentSchema)({ storeId, payload, pullRequestIds: [], headers }),
168
175
  )
169
176
 
170
177
  // See https://developers.cloudflare.com/durable-objects/examples/websocket-hibernation-server
@@ -220,9 +227,11 @@ export const makeDurableObject: MakeDurableObjectClass = (options) => {
220
227
  *
221
228
  * Requires the `enable_request_signal` compatibility flag to properly support `pull` streaming responses
222
229
  */
223
- private handleHttp = (request: CfTypes.Request) =>
230
+ private handleHttp = (request: CfTypes.Request, forwardedHeaders: Record<string, string> | undefined) =>
224
231
  createHttpRpcHandler({
225
232
  request,
233
+ ...(options?.http?.responseHeaders !== undefined ? { responseHeaders: options.http.responseHeaders } : {}),
234
+ ...(forwardedHeaders !== undefined ? { forwardedHeaders } : {}),
226
235
  }).pipe(Effect.withSpan('@livestore/sync-cf:durable-object:handleHttp'))
227
236
 
228
237
  private runEffectAsPromise = <T, E = never>(effect: Effect.Effect<T, E, Scope.Scope>): Promise<T> =>
@@ -1,9 +1,10 @@
1
- import { UnexpectedError } from '@livestore/common'
2
- import { EventSequenceNumber, State } from '@livestore/common/schema'
1
+ import { UnknownError } from '@livestore/common'
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`)
@@ -37,15 +38,36 @@ export class DoCtx extends Effect.Service<DoCtx>()('DoCtx', {
37
38
  }
38
39
 
39
40
  const storeId = getStoreId(from)
40
- const storage = makeStorage(doSelf.ctx, doSelf.env, storeId)
41
+ // Resolve storage engine
42
+ const makeEngine = Effect.gen(function* () {
43
+ const opt = doOptions?.storage
44
+ if (opt?._tag === 'd1') {
45
+ const db = (doSelf.env as any)[opt.binding]
46
+ if (db == null) {
47
+ return yield* UnknownError.make({ cause: new Error(`D1 binding '${opt.binding}' not found on env`) })
48
+ }
49
+ return { _tag: 'd1' as const, db }
50
+ } else if (opt?._tag === 'do-sqlite' || opt === undefined) {
51
+ return { _tag: 'do-sqlite' as const }
52
+ } else return shouldNeverHappen(`Invalid storage engine`, opt)
53
+ })
54
+
55
+ const engine = yield* makeEngine
56
+
57
+ const storage = makeStorage(doSelf.ctx, storeId, engine)
41
58
 
42
59
  // Initialize database tables
43
60
  {
44
61
  const colSpec = State.SQLite.makeColumnSpec(eventlogTable.sqliteDef.ast)
45
- // D1 database is async, so we need to use a promise
46
- yield* Effect.promise(() =>
47
- doSelf.env.DB.exec(`CREATE TABLE IF NOT EXISTS "${storage.dbName}" (${colSpec}) strict`),
48
- )
62
+ if (engine._tag === 'd1') {
63
+ // D1 database is async, so we need to use a promise
64
+ yield* Effect.promise(() =>
65
+ engine.db.exec(`CREATE TABLE IF NOT EXISTS "${storage.dbName}" (${colSpec}) strict`),
66
+ )
67
+ } else {
68
+ // DO SQLite table lives in Durable Object storage
69
+ doSelf.ctx.storage.sql.exec(`CREATE TABLE IF NOT EXISTS "${storage.dbName}" (${colSpec}) strict`)
70
+ }
49
71
  }
50
72
  {
51
73
  const colSpec = State.SQLite.makeColumnSpec(contextTable.sqliteDef.ast)
@@ -56,14 +78,14 @@ export class DoCtx extends Effect.Service<DoCtx>()('DoCtx', {
56
78
  .exec(`SELECT * FROM "${contextTable.sqliteDef.name}" WHERE storeId = ?`, storeId)
57
79
  .toArray()[0] as typeof contextTable.rowSchema.Type | undefined
58
80
 
59
- const currentHeadRef = { current: storageRow?.currentHead ?? EventSequenceNumber.ROOT.global }
81
+ const currentHeadRef = { current: storageRow?.currentHead ?? EventSequenceNumber.Client.ROOT.global }
60
82
 
61
83
  // TODO do concistency check with eventlog table to make sure the head is consistent
62
84
 
63
- // Should be the same backendId for lifetime of the durable object
85
+ // Should be the same backendId for lifetime of the Durable Object
64
86
  const backendId = storageRow?.backendId ?? nanoid()
65
87
 
66
- const updateCurrentHead = (currentHead: EventSequenceNumber.GlobalEventSequenceNumber) => {
88
+ const updateCurrentHead = (currentHead: EventSequenceNumber.Global.Type) => {
67
89
  doSelf.ctx.storage.sql.exec(
68
90
  `INSERT OR REPLACE INTO "${contextTable.sqliteDef.name}" (storeId, currentHead, backendId) VALUES (?, ?, ?)`,
69
91
  storeId,
@@ -96,12 +118,12 @@ export class DoCtx extends Effect.Service<DoCtx>()('DoCtx', {
96
118
 
97
119
  // Set initial current head to root
98
120
  if (storageRow === undefined) {
99
- updateCurrentHead(EventSequenceNumber.ROOT.global)
121
+ updateCurrentHead(EventSequenceNumber.Client.ROOT.global)
100
122
  }
101
123
 
102
124
  return storageCache
103
125
  },
104
- UnexpectedError.mapToUnexpectedError,
126
+ UnknownError.mapToUnknownError,
105
127
  Effect.withSpan('@livestore/sync-cf:durable-object:makeDoCtx'),
106
128
  ),
107
129
  }) {}
@@ -1,9 +1,11 @@
1
- import { BackendIdMismatchError, InvalidPullError, SyncBackend, UnexpectedError } from '@livestore/common'
1
+ import { BackendIdMismatchError, SyncBackend, UnknownError } from '@livestore/common'
2
+ import { splitChunkBySize } from '@livestore/common/sync'
2
3
  import { Chunk, Effect, Option, Schema, Stream } from '@livestore/utils/effect'
4
+
5
+ import { MAX_PULL_EVENTS_PER_MESSAGE, MAX_WS_MESSAGE_BYTES } from '../../common/constants.ts'
3
6
  import { SyncMessage } from '../../common/mod.ts'
4
- import { MAX_PULL_EVENTS_PER_MESSAGE, MAX_WS_MESSAGE_BYTES } from '../shared.ts'
7
+ import type { ForwardedHeaders } from '../shared.ts'
5
8
  import { DoCtx } from './layer.ts'
6
- import { splitChunkBySize } from './ws-chunking.ts'
7
9
 
8
10
  const encodePullResponse = Schema.encodeSync(SyncMessage.PullResponse)
9
11
 
@@ -16,16 +18,27 @@ const encodePullResponse = Schema.encodeSync(SyncMessage.PullResponse)
16
18
  // DO RPC:
17
19
  // - Further chunks will be emitted manually in `push.ts`
18
20
  // - If the client sends a `Interrupt` RPC message, TODO
19
- export const makeEndingPullStream = (
20
- req: SyncMessage.PullRequest,
21
- payload: Schema.JsonValue | undefined,
22
- ): Stream.Stream<SyncMessage.PullResponse, InvalidPullError, DoCtx> =>
21
+ export const makeEndingPullStream = ({
22
+ req,
23
+ payload,
24
+ headers,
25
+ }: {
26
+ req: SyncMessage.PullRequest
27
+ payload: Schema.JsonValue | undefined
28
+ headers: ForwardedHeaders | undefined
29
+ }): Stream.Stream<SyncMessage.PullResponse, UnknownError | BackendIdMismatchError, DoCtx> =>
23
30
  Effect.gen(function* () {
24
31
  const { doOptions, backendId, storeId, storage } = yield* DoCtx
25
32
 
26
- if (doOptions?.onPull) {
27
- yield* Effect.tryAll(() => doOptions!.onPull!(req, { storeId, payload })).pipe(
28
- UnexpectedError.mapToUnexpectedError,
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(
41
+ UnknownError.mapToUnknownError,
29
42
  )
30
43
  }
31
44
 
@@ -38,7 +51,7 @@ export const makeEndingPullStream = (
38
51
  )
39
52
 
40
53
  return storedEvents.pipe(
41
- Stream.mapChunks(
54
+ Stream.mapChunksEffect(
42
55
  splitChunkBySize({
43
56
  maxItems: MAX_PULL_EVENTS_PER_MESSAGE,
44
57
  maxBytes: MAX_WS_MESSAGE_BYTES,
@@ -63,8 +76,8 @@ export const makeEndingPullStream = (
63
76
  }),
64
77
  Stream.tap(
65
78
  Effect.fn(function* (res) {
66
- if (doOptions?.onPullRes) {
67
- yield* Effect.tryAll(() => doOptions.onPullRes!(res)).pipe(UnexpectedError.mapToUnexpectedError)
79
+ if (doOptions?.onPullRes !== undefined) {
80
+ yield* Effect.tryAll(() => doOptions.onPullRes!(res)).pipe(UnknownError.mapToUnknownError)
68
81
  }
69
82
  }),
70
83
  ),
@@ -72,6 +85,10 @@ export const makeEndingPullStream = (
72
85
  )
73
86
  }).pipe(
74
87
  Stream.unwrap,
75
- Stream.mapError((cause) => InvalidPullError.make({ cause })),
88
+ Stream.mapError((cause) =>
89
+ cause._tag === 'BackendIdMismatchError' || cause._tag === 'UnknownError'
90
+ ? cause
91
+ : new UnknownError({ cause }),
92
+ ),
76
93
  Stream.withSpan('cloudflare-provider:pull'),
77
94
  )