rwsdk 1.0.0-beta.30-test.20251119220440 → 1.0.0-beta.30-test.20251120213828

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 (34) hide show
  1. package/dist/lib/e2e/testHarness.mjs +6 -1
  2. package/dist/runtime/entries/no-react-server-ssr-bridge.d.ts +0 -0
  3. package/dist/runtime/entries/no-react-server-ssr-bridge.js +2 -0
  4. package/dist/use-synced-state/SyncedStateServer.d.mts +21 -0
  5. package/dist/use-synced-state/{SyncStateServer.mjs → SyncedStateServer.mjs} +38 -34
  6. package/dist/use-synced-state/__tests__/SyncStateServer.test.mjs +19 -19
  7. package/dist/use-synced-state/__tests__/useSyncState.test.js +9 -9
  8. package/dist/use-synced-state/__tests__/useSyncedState.test.js +9 -9
  9. package/dist/use-synced-state/__tests__/worker.test.mjs +11 -11
  10. package/dist/use-synced-state/client-core.d.ts +26 -0
  11. package/dist/use-synced-state/client-core.js +39 -0
  12. package/dist/use-synced-state/client.d.ts +3 -28
  13. package/dist/use-synced-state/client.js +4 -39
  14. package/dist/use-synced-state/constants.d.mts +1 -1
  15. package/dist/use-synced-state/constants.mjs +1 -1
  16. package/dist/use-synced-state/useSyncedState.d.ts +3 -3
  17. package/dist/use-synced-state/useSyncedState.js +7 -7
  18. package/dist/use-synced-state/worker.d.mts +6 -7
  19. package/dist/use-synced-state/worker.mjs +25 -29
  20. package/dist/vite/cloudflarePreInitPlugin.d.mts +11 -0
  21. package/dist/vite/cloudflarePreInitPlugin.mjs +40 -0
  22. package/dist/vite/createDirectiveLookupPlugin.mjs +6 -7
  23. package/dist/vite/directivesPlugin.mjs +0 -4
  24. package/dist/vite/injectVitePreamblePlugin.mjs +0 -4
  25. package/dist/vite/knownDepsResolverPlugin.mjs +6 -16
  26. package/dist/vite/redwoodPlugin.mjs +2 -0
  27. package/dist/vite/runDirectivesScan.mjs +13 -4
  28. package/dist/vite/ssrBridgePlugin.mjs +10 -7
  29. package/dist/vite/transformJsxScriptTagsPlugin.mjs +0 -4
  30. package/dist/vite/virtualPlugin.mjs +6 -7
  31. package/package.json +5 -4
  32. package/dist/use-synced-state/SyncStateServer.d.mts +0 -20
  33. package/dist/use-synced-state/useSyncState.d.ts +0 -20
  34. package/dist/use-synced-state/useSyncState.js +0 -58
@@ -413,7 +413,12 @@ function createSDKTestRunner() {
413
413
  console.warn("Failed to connect to existing browser instance. " +
414
414
  "This might happen if you are running a single test file. " +
415
415
  "Launching a new browser instance instead.");
416
- browser = await launchBrowser();
416
+ // Check for RWSDK_HEADLESS environment variable (default to true if not set)
417
+ // Set RWSDK_HEADLESS=0 or RWSDK_HEADLESS=false to run in headed mode
418
+ const headless = process.env.RWSDK_HEADLESS === undefined ||
419
+ process.env.RWSDK_HEADLESS === "1" ||
420
+ process.env.RWSDK_HEADLESS === "true";
421
+ browser = await launchBrowser(undefined, headless);
417
422
  }
418
423
  }, SETUP_WAIT_TIMEOUT);
419
424
  afterAll(async () => {
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ throw new Error("rwsdk: SSR bridge was resolved with 'react-server' condition. This is a bug - the SSR bridge should be intercepted by the esbuild plugin before reaching package.json exports. Please report this issue.");
@@ -0,0 +1,21 @@
1
+ import { RpcStub } from "capnweb";
2
+ import { DurableObject } from "cloudflare:workers";
3
+ export type SyncedStateValue = unknown;
4
+ type OnSetHandler = (key: string, value: SyncedStateValue) => void;
5
+ type OnGetHandler = (key: string, value: SyncedStateValue | undefined) => void;
6
+ /**
7
+ * Durable Object that keeps shared state for multiple clients and notifies subscribers.
8
+ */
9
+ export declare class SyncedStateServer extends DurableObject {
10
+ #private;
11
+ static registerKeyHandler(handler: (key: string) => Promise<string>): void;
12
+ static getKeyHandler(): ((key: string) => Promise<string>) | null;
13
+ static registerSetStateHandler(handler: OnSetHandler | null): void;
14
+ static registerGetStateHandler(handler: OnGetHandler | null): void;
15
+ getState(key: string): SyncedStateValue;
16
+ setState(value: SyncedStateValue, key: string): void;
17
+ subscribe(key: string, client: RpcStub<(value: SyncedStateValue) => void>): void;
18
+ unsubscribe(key: string, client: RpcStub<(value: SyncedStateValue) => void>): void;
19
+ fetch(request: Request): Promise<Response>;
20
+ }
21
+ export {};
@@ -9,51 +9,51 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _a, _SyncStateServer_keyHandler, _SyncStateServer_setStateHandler, _SyncStateServer_getStateHandler, _SyncStateServer_stateStore, _SyncStateServer_subscriptions, _SyncStateServer_subscriptionRefs, _CoordinatorApi_coordinator;
13
- import { RpcTarget } from "capnweb";
12
+ var _a, _SyncedStateServer_keyHandler, _SyncedStateServer_setStateHandler, _SyncedStateServer_getStateHandler, _SyncedStateServer_stateStore, _SyncedStateServer_subscriptions, _SyncedStateServer_subscriptionRefs, _CoordinatorApi_coordinator;
13
+ import { RpcTarget, newWorkersRpcResponse } from "capnweb";
14
14
  import { DurableObject } from "cloudflare:workers";
15
15
  /**
16
16
  * Durable Object that keeps shared state for multiple clients and notifies subscribers.
17
17
  */
18
- export class SyncStateServer extends DurableObject {
18
+ export class SyncedStateServer extends DurableObject {
19
19
  constructor() {
20
20
  super(...arguments);
21
- _SyncStateServer_stateStore.set(this, new Map());
22
- _SyncStateServer_subscriptions.set(this, new Map());
23
- _SyncStateServer_subscriptionRefs.set(this, new Map());
21
+ _SyncedStateServer_stateStore.set(this, new Map());
22
+ _SyncedStateServer_subscriptions.set(this, new Map());
23
+ _SyncedStateServer_subscriptionRefs.set(this, new Map());
24
24
  }
25
25
  static registerKeyHandler(handler) {
26
- __classPrivateFieldSet(_a, _a, handler, "f", _SyncStateServer_keyHandler);
26
+ __classPrivateFieldSet(_a, _a, handler, "f", _SyncedStateServer_keyHandler);
27
27
  }
28
28
  static getKeyHandler() {
29
- return __classPrivateFieldGet(_a, _a, "f", _SyncStateServer_keyHandler);
29
+ return __classPrivateFieldGet(_a, _a, "f", _SyncedStateServer_keyHandler);
30
30
  }
31
31
  static registerSetStateHandler(handler) {
32
- __classPrivateFieldSet(_a, _a, handler, "f", _SyncStateServer_setStateHandler);
32
+ __classPrivateFieldSet(_a, _a, handler, "f", _SyncedStateServer_setStateHandler);
33
33
  }
34
34
  static registerGetStateHandler(handler) {
35
- __classPrivateFieldSet(_a, _a, handler, "f", _SyncStateServer_getStateHandler);
35
+ __classPrivateFieldSet(_a, _a, handler, "f", _SyncedStateServer_getStateHandler);
36
36
  }
37
37
  getState(key) {
38
- const value = __classPrivateFieldGet(this, _SyncStateServer_stateStore, "f").get(key);
39
- if (__classPrivateFieldGet(_a, _a, "f", _SyncStateServer_getStateHandler)) {
40
- __classPrivateFieldGet(_a, _a, "f", _SyncStateServer_getStateHandler).call(_a, key, value);
38
+ const value = __classPrivateFieldGet(this, _SyncedStateServer_stateStore, "f").get(key);
39
+ if (__classPrivateFieldGet(_a, _a, "f", _SyncedStateServer_getStateHandler)) {
40
+ __classPrivateFieldGet(_a, _a, "f", _SyncedStateServer_getStateHandler).call(_a, key, value);
41
41
  }
42
42
  return value;
43
43
  }
44
44
  setState(value, key) {
45
- __classPrivateFieldGet(this, _SyncStateServer_stateStore, "f").set(key, value);
46
- if (__classPrivateFieldGet(_a, _a, "f", _SyncStateServer_setStateHandler)) {
47
- __classPrivateFieldGet(_a, _a, "f", _SyncStateServer_setStateHandler).call(_a, key, value);
45
+ __classPrivateFieldGet(this, _SyncedStateServer_stateStore, "f").set(key, value);
46
+ if (__classPrivateFieldGet(_a, _a, "f", _SyncedStateServer_setStateHandler)) {
47
+ __classPrivateFieldGet(_a, _a, "f", _SyncedStateServer_setStateHandler).call(_a, key, value);
48
48
  }
49
- const subscribers = __classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").get(key);
49
+ const subscribers = __classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").get(key);
50
50
  if (!subscribers) {
51
51
  return;
52
52
  }
53
53
  for (const subscriber of subscribers) {
54
54
  subscriber(value).catch(() => {
55
55
  subscribers.delete(subscriber);
56
- const refs = __classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").get(key);
56
+ const refs = __classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").get(key);
57
57
  if (refs) {
58
58
  for (const [original, duplicate] of refs) {
59
59
  if (duplicate === subscriber) {
@@ -62,46 +62,50 @@ export class SyncStateServer extends DurableObject {
62
62
  }
63
63
  }
64
64
  if (refs.size === 0) {
65
- __classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").delete(key);
65
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").delete(key);
66
66
  }
67
67
  }
68
68
  });
69
69
  }
70
70
  if (subscribers.size === 0) {
71
- __classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").delete(key);
71
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").delete(key);
72
72
  }
73
73
  }
74
74
  subscribe(key, client) {
75
- if (!__classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").has(key)) {
76
- __classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").set(key, new Set());
75
+ if (!__classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").has(key)) {
76
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").set(key, new Set());
77
77
  }
78
- if (!__classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").has(key)) {
79
- __classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").set(key, new Map());
78
+ if (!__classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").has(key)) {
79
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").set(key, new Map());
80
80
  }
81
81
  const duplicate = client.dup();
82
- __classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").get(key).add(duplicate);
83
- __classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").get(key).set(client, duplicate);
82
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").get(key).add(duplicate);
83
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").get(key).set(client, duplicate);
84
84
  }
85
85
  unsubscribe(key, client) {
86
- const duplicates = __classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").get(key);
86
+ const duplicates = __classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").get(key);
87
87
  const duplicate = duplicates?.get(client);
88
- const subscribers = __classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").get(key);
88
+ const subscribers = __classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").get(key);
89
89
  if (duplicate && subscribers) {
90
90
  subscribers.delete(duplicate);
91
91
  duplicates.delete(client);
92
92
  if (subscribers.size === 0) {
93
- __classPrivateFieldGet(this, _SyncStateServer_subscriptions, "f").delete(key);
93
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptions, "f").delete(key);
94
94
  }
95
95
  if (duplicates.size === 0) {
96
- __classPrivateFieldGet(this, _SyncStateServer_subscriptionRefs, "f").delete(key);
96
+ __classPrivateFieldGet(this, _SyncedStateServer_subscriptionRefs, "f").delete(key);
97
97
  }
98
98
  }
99
99
  }
100
+ async fetch(request) {
101
+ const api = new CoordinatorApi(this);
102
+ return newWorkersRpcResponse(request, api);
103
+ }
100
104
  }
101
- _a = SyncStateServer, _SyncStateServer_stateStore = new WeakMap(), _SyncStateServer_subscriptions = new WeakMap(), _SyncStateServer_subscriptionRefs = new WeakMap();
102
- _SyncStateServer_keyHandler = { value: null };
103
- _SyncStateServer_setStateHandler = { value: null };
104
- _SyncStateServer_getStateHandler = { value: null };
105
+ _a = SyncedStateServer, _SyncedStateServer_stateStore = new WeakMap(), _SyncedStateServer_subscriptions = new WeakMap(), _SyncedStateServer_subscriptionRefs = new WeakMap();
106
+ _SyncedStateServer_keyHandler = { value: null };
107
+ _SyncedStateServer_setStateHandler = { value: null };
108
+ _SyncedStateServer_getStateHandler = { value: null };
105
109
  class CoordinatorApi extends RpcTarget {
106
110
  constructor(coordinator) {
107
111
  super();
@@ -4,7 +4,7 @@ vi.mock("cloudflare:workers", () => {
4
4
  }
5
5
  return { DurableObject };
6
6
  });
7
- import { SyncStateServer } from "../SyncStateServer.mjs";
7
+ import { SyncedStateServer } from "../SyncedStateServer.mjs";
8
8
  const createStub = (onInvoke) => {
9
9
  const fn = Object.assign(async (value) => {
10
10
  await onInvoke(value);
@@ -13,9 +13,9 @@ const createStub = (onInvoke) => {
13
13
  });
14
14
  return fn;
15
15
  };
16
- describe("SyncStateServer", () => {
16
+ describe("SyncedStateServer", () => {
17
17
  it("notifies subscribers when state changes", async () => {
18
- const coordinator = new SyncStateServer({}, {});
18
+ const coordinator = new SyncedStateServer({}, {});
19
19
  const received = [];
20
20
  const stub = createStub((value) => {
21
21
  received.push(value);
@@ -26,7 +26,7 @@ describe("SyncStateServer", () => {
26
26
  expect(received).toEqual([5]);
27
27
  });
28
28
  it("removes subscriptions on unsubscribe", () => {
29
- const coordinator = new SyncStateServer({}, {});
29
+ const coordinator = new SyncedStateServer({}, {});
30
30
  const stub = createStub(() => { });
31
31
  coordinator.subscribe("counter", stub);
32
32
  coordinator.unsubscribe("counter", stub);
@@ -34,7 +34,7 @@ describe("SyncStateServer", () => {
34
34
  expect(coordinator.getState("counter")).toBe(1);
35
35
  });
36
36
  it("drops failing subscribers", async () => {
37
- const coordinator = new SyncStateServer({}, {});
37
+ const coordinator = new SyncedStateServer({}, {});
38
38
  const stub = createStub(async () => {
39
39
  throw new Error("fail");
40
40
  });
@@ -45,45 +45,45 @@ describe("SyncStateServer", () => {
45
45
  expect(coordinator.getState("counter")).toBe(4);
46
46
  });
47
47
  it("invokes registered onSet handler", () => {
48
- const coordinator = new SyncStateServer({}, {});
48
+ const coordinator = new SyncedStateServer({}, {});
49
49
  const calls = [];
50
- SyncStateServer.registerSetStateHandler((key, value) => {
50
+ SyncedStateServer.registerSetStateHandler((key, value) => {
51
51
  calls.push({ key, value });
52
52
  });
53
53
  coordinator.setState(2, "counter");
54
54
  expect(calls).toEqual([{ key: "counter", value: 2 }]);
55
- SyncStateServer.registerSetStateHandler(null);
55
+ SyncedStateServer.registerSetStateHandler(null);
56
56
  });
57
57
  it("invokes registered onGet handler", () => {
58
- const coordinator = new SyncStateServer({}, {});
58
+ const coordinator = new SyncedStateServer({}, {});
59
59
  const calls = [];
60
- SyncStateServer.registerGetStateHandler((key, value) => {
60
+ SyncedStateServer.registerGetStateHandler((key, value) => {
61
61
  calls.push({ key, value });
62
62
  });
63
63
  coordinator.setState(4, "counter");
64
64
  expect(coordinator.getState("counter")).toBe(4);
65
65
  expect(calls).toEqual([{ key: "counter", value: 4 }]);
66
- SyncStateServer.registerGetStateHandler(null);
66
+ SyncedStateServer.registerGetStateHandler(null);
67
67
  });
68
68
  describe("registerKeyHandler", () => {
69
69
  afterEach(() => {
70
- SyncStateServer.registerKeyHandler(async (key) => key);
70
+ SyncedStateServer.registerKeyHandler(async (key) => key);
71
71
  });
72
72
  it("stores and retrieves the registered handler", async () => {
73
73
  const handler = async (key) => `transformed:${key}`;
74
- SyncStateServer.registerKeyHandler(handler);
75
- const retrievedHandler = SyncStateServer.getKeyHandler();
74
+ SyncedStateServer.registerKeyHandler(handler);
75
+ const retrievedHandler = SyncedStateServer.getKeyHandler();
76
76
  expect(retrievedHandler).toBe(handler);
77
77
  });
78
78
  it("transforms keys using the registered handler", async () => {
79
79
  const handler = async (key) => `user:123:${key}`;
80
- SyncStateServer.registerKeyHandler(handler);
80
+ SyncedStateServer.registerKeyHandler(handler);
81
81
  const result = await handler("counter");
82
82
  expect(result).toBe("user:123:counter");
83
83
  });
84
84
  it("returns null when no handler is registered", () => {
85
- SyncStateServer.registerKeyHandler(async (key) => key);
86
- const handler = SyncStateServer.getKeyHandler();
85
+ SyncedStateServer.registerKeyHandler(async (key) => key);
86
+ const handler = SyncedStateServer.getKeyHandler();
87
87
  expect(handler).not.toBeNull();
88
88
  });
89
89
  it("allows handler to be async", async () => {
@@ -91,7 +91,7 @@ describe("SyncStateServer", () => {
91
91
  await new Promise((resolve) => setTimeout(resolve, 10));
92
92
  return `async:${key}`;
93
93
  };
94
- SyncStateServer.registerKeyHandler(handler);
94
+ SyncedStateServer.registerKeyHandler(handler);
95
95
  const result = await handler("test");
96
96
  expect(result).toBe("async:test");
97
97
  });
@@ -101,7 +101,7 @@ describe("SyncStateServer", () => {
101
101
  receivedKey = key;
102
102
  return key;
103
103
  };
104
- SyncStateServer.registerKeyHandler(handler);
104
+ SyncedStateServer.registerKeyHandler(handler);
105
105
  await handler("myKey");
106
106
  expect(receivedKey).toBe("myKey");
107
107
  });
@@ -1,6 +1,6 @@
1
1
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
- import { setSyncStateClientForTesting } from "../client";
3
- import { createSyncStateHook, } from "../useSyncedState";
2
+ import { setSyncedStateClientForTesting, } from "../client";
3
+ import { createSyncedStateHook, } from "../useSyncedState";
4
4
  const createStateHarness = () => {
5
5
  let currentState;
6
6
  const cleanups = [];
@@ -39,7 +39,7 @@ const createStateHarness = () => {
39
39
  runCleanups: () => cleanups.forEach((fn) => fn()),
40
40
  };
41
41
  };
42
- describe("createSyncStateHook", () => {
42
+ describe("createSyncedStateHook", () => {
43
43
  const subscribeHandlers = new Map();
44
44
  const client = {
45
45
  async getState() {
@@ -65,15 +65,15 @@ describe("createSyncStateHook", () => {
65
65
  };
66
66
  beforeEach(() => {
67
67
  resetClient();
68
- setSyncStateClientForTesting(client);
68
+ setSyncedStateClientForTesting(client);
69
69
  subscribeHandlers.clear();
70
70
  });
71
71
  afterEach(() => {
72
- setSyncStateClientForTesting(null);
72
+ setSyncedStateClientForTesting(null);
73
73
  });
74
74
  it("loads remote state and updates local value", async () => {
75
75
  const harness = createStateHarness();
76
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
76
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
77
77
  const [value] = useSyncedState(0, "counter");
78
78
  expect(value).toBe(0);
79
79
  await Promise.resolve();
@@ -85,7 +85,7 @@ describe("createSyncStateHook", () => {
85
85
  client.setState = async (value, key) => {
86
86
  setCalls.push({ key, value });
87
87
  };
88
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
88
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
89
89
  const [, setSyncValue] = useSyncedState(0, "counter");
90
90
  setSyncValue(9);
91
91
  expect(harness.getState()).toBe(9);
@@ -93,7 +93,7 @@ describe("createSyncStateHook", () => {
93
93
  });
94
94
  it("applies remote updates from the subscription handler", async () => {
95
95
  const harness = createStateHarness();
96
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
96
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
97
97
  useSyncedState(0, "counter");
98
98
  await Promise.resolve();
99
99
  const handler = subscribeHandlers.get("counter");
@@ -107,7 +107,7 @@ describe("createSyncStateHook", () => {
107
107
  unsubscribed.push({ key });
108
108
  subscribeHandlers.delete(key);
109
109
  };
110
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
110
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
111
111
  useSyncedState(0, "counter");
112
112
  harness.runCleanups();
113
113
  expect(unsubscribed).toEqual([{ key: "counter" }]);
@@ -1,6 +1,6 @@
1
1
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
- import { setSyncStateClientForTesting, } from "../client";
3
- import { createSyncStateHook, } from "../useSyncedState";
2
+ import { setSyncedStateClientForTesting, } from "../client";
3
+ import { createSyncedStateHook, } from "../useSyncedState";
4
4
  const createStateHarness = () => {
5
5
  let currentState;
6
6
  const cleanups = [];
@@ -39,7 +39,7 @@ const createStateHarness = () => {
39
39
  runCleanups: () => cleanups.forEach((fn) => fn()),
40
40
  };
41
41
  };
42
- describe("createSyncStateHook", () => {
42
+ describe("createSyncedStateHook", () => {
43
43
  const subscribeHandlers = new Map();
44
44
  const client = {
45
45
  async getState() {
@@ -65,15 +65,15 @@ describe("createSyncStateHook", () => {
65
65
  };
66
66
  beforeEach(() => {
67
67
  resetClient();
68
- setSyncStateClientForTesting(client);
68
+ setSyncedStateClientForTesting(client);
69
69
  subscribeHandlers.clear();
70
70
  });
71
71
  afterEach(() => {
72
- setSyncStateClientForTesting(null);
72
+ setSyncedStateClientForTesting(null);
73
73
  });
74
74
  it("loads remote state and updates local value", async () => {
75
75
  const harness = createStateHarness();
76
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
76
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
77
77
  const [value] = useSyncedState(0, "counter");
78
78
  expect(value).toBe(0);
79
79
  await Promise.resolve();
@@ -85,7 +85,7 @@ describe("createSyncStateHook", () => {
85
85
  client.setState = async (value, key) => {
86
86
  setCalls.push({ key, value });
87
87
  };
88
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
88
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
89
89
  const [, setSyncValue] = useSyncedState(0, "counter");
90
90
  setSyncValue(9);
91
91
  expect(harness.getState()).toBe(9);
@@ -93,7 +93,7 @@ describe("createSyncStateHook", () => {
93
93
  });
94
94
  it("applies remote updates from the subscription handler", async () => {
95
95
  const harness = createStateHarness();
96
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
96
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
97
97
  useSyncedState(0, "counter");
98
98
  await Promise.resolve();
99
99
  const handler = subscribeHandlers.get("counter");
@@ -107,7 +107,7 @@ describe("createSyncStateHook", () => {
107
107
  unsubscribed.push({ key });
108
108
  subscribeHandlers.delete(key);
109
109
  };
110
- const useSyncedState = createSyncStateHook({ hooks: harness.deps });
110
+ const useSyncedState = createSyncedStateHook({ hooks: harness.deps });
111
111
  useSyncedState(0, "counter");
112
112
  harness.runCleanups();
113
113
  expect(unsubscribed).toEqual([{ key: "counter" }]);
@@ -12,18 +12,18 @@ vi.mock("capnweb", () => ({
12
12
  vi.mock("../runtime/entries/router", () => ({
13
13
  route: vi.fn((path, handler) => ({ path, handler })),
14
14
  }));
15
- import { SyncStateServer } from "../SyncStateServer.mjs";
16
- describe("SyncStateProxy", () => {
15
+ import { SyncedStateServer } from "../SyncedStateServer.mjs";
16
+ describe("SyncedStateProxy", () => {
17
17
  let mockCoordinator;
18
18
  beforeEach(() => {
19
- mockCoordinator = new SyncStateServer({}, {});
19
+ mockCoordinator = new SyncedStateServer({}, {});
20
20
  });
21
21
  afterEach(() => {
22
- SyncStateServer.registerKeyHandler(async (key) => key);
22
+ SyncedStateServer.registerKeyHandler(async (key) => key);
23
23
  });
24
24
  it("transforms keys before calling coordinator methods when handler is registered", async () => {
25
25
  const handler = async (key) => `transformed:${key}`;
26
- SyncStateServer.registerKeyHandler(handler);
26
+ SyncedStateServer.registerKeyHandler(handler);
27
27
  const transformedKey = await handler("counter");
28
28
  expect(transformedKey).toBe("transformed:counter");
29
29
  mockCoordinator.setState(5, transformedKey);
@@ -31,13 +31,13 @@ describe("SyncStateProxy", () => {
31
31
  expect(value).toBe(5);
32
32
  });
33
33
  it("does not transform keys when no handler is registered", () => {
34
- SyncStateServer.registerKeyHandler(async (key) => key);
35
- const handler = SyncStateServer.getKeyHandler();
34
+ SyncedStateServer.registerKeyHandler(async (key) => key);
35
+ const handler = SyncedStateServer.getKeyHandler();
36
36
  expect(handler).not.toBeNull();
37
37
  });
38
38
  it("passes through original key when handler returns it unchanged", async () => {
39
39
  const handler = async (key) => key;
40
- SyncStateServer.registerKeyHandler(handler);
40
+ SyncedStateServer.registerKeyHandler(handler);
41
41
  const result = await handler("counter");
42
42
  expect(result).toBe("counter");
43
43
  });
@@ -46,7 +46,7 @@ describe("SyncStateProxy", () => {
46
46
  const userId = "user123";
47
47
  return `user:${userId}:${key}`;
48
48
  };
49
- SyncStateServer.registerKeyHandler(handler);
49
+ SyncedStateServer.registerKeyHandler(handler);
50
50
  const result = await handler("settings");
51
51
  expect(result).toBe("user:user123:settings");
52
52
  });
@@ -54,7 +54,7 @@ describe("SyncStateProxy", () => {
54
54
  const handler = async (_key) => {
55
55
  throw new Error("Handler error");
56
56
  };
57
- SyncStateServer.registerKeyHandler(handler);
57
+ SyncedStateServer.registerKeyHandler(handler);
58
58
  await expect(handler("test")).rejects.toThrow("Handler error");
59
59
  });
60
60
  it("handles async operations in handler", async () => {
@@ -62,7 +62,7 @@ describe("SyncStateProxy", () => {
62
62
  await new Promise((resolve) => setTimeout(resolve, 5));
63
63
  return `async:${key}`;
64
64
  };
65
- SyncStateServer.registerKeyHandler(handler);
65
+ SyncedStateServer.registerKeyHandler(handler);
66
66
  const result = await handler("data");
67
67
  expect(result).toBe("async:data");
68
68
  });
@@ -0,0 +1,26 @@
1
+ export type SyncedStateClient = {
2
+ getState(key: string): Promise<unknown>;
3
+ setState(value: unknown, key: string): Promise<void>;
4
+ subscribe(key: string, handler: (value: unknown) => void): Promise<void>;
5
+ unsubscribe(key: string, handler: (value: unknown) => void): Promise<void>;
6
+ };
7
+ /**
8
+ * Returns a cached client for the provided endpoint, creating it when necessary.
9
+ * @param endpoint Endpoint to connect to.
10
+ * @returns RPC client instance.
11
+ */
12
+ export declare const getSyncedStateClient: (endpoint?: string) => SyncedStateClient;
13
+ /**
14
+ * Initializes and caches an RPC client instance for the sync state endpoint.
15
+ * @param options Optional endpoint override.
16
+ * @returns Cached client instance or `null` when running without `window`.
17
+ */
18
+ export declare const initSyncedStateClient: (options?: {
19
+ endpoint?: string;
20
+ }) => SyncedStateClient | null;
21
+ /**
22
+ * Injects a client instance for tests and updates the cached endpoint.
23
+ * @param client Stub client instance or `null` to clear the cache.
24
+ * @param endpoint Endpoint associated with the injected client.
25
+ */
26
+ export declare const setSyncedStateClientForTesting: (client: SyncedStateClient | null, endpoint?: string) => void;
@@ -0,0 +1,39 @@
1
+ import { newWebSocketRpcSession } from "capnweb";
2
+ import { DEFAULT_SYNCED_STATE_PATH } from "./constants.mjs";
3
+ let cachedClient = null;
4
+ let cachedEndpoint = DEFAULT_SYNCED_STATE_PATH;
5
+ /**
6
+ * Returns a cached client for the provided endpoint, creating it when necessary.
7
+ * @param endpoint Endpoint to connect to.
8
+ * @returns RPC client instance.
9
+ */
10
+ export const getSyncedStateClient = (endpoint = cachedEndpoint) => {
11
+ if (cachedClient && endpoint === cachedEndpoint) {
12
+ return cachedClient;
13
+ }
14
+ cachedEndpoint = endpoint;
15
+ cachedClient = newWebSocketRpcSession(cachedEndpoint);
16
+ return cachedClient;
17
+ };
18
+ /**
19
+ * Initializes and caches an RPC client instance for the sync state endpoint.
20
+ * @param options Optional endpoint override.
21
+ * @returns Cached client instance or `null` when running without `window`.
22
+ */
23
+ export const initSyncedStateClient = (options = {}) => {
24
+ cachedEndpoint = options.endpoint ?? DEFAULT_SYNCED_STATE_PATH;
25
+ if (typeof window === "undefined") {
26
+ return null;
27
+ }
28
+ cachedClient = newWebSocketRpcSession(cachedEndpoint);
29
+ return cachedClient;
30
+ };
31
+ /**
32
+ * Injects a client instance for tests and updates the cached endpoint.
33
+ * @param client Stub client instance or `null` to clear the cache.
34
+ * @param endpoint Endpoint associated with the injected client.
35
+ */
36
+ export const setSyncedStateClientForTesting = (client, endpoint = DEFAULT_SYNCED_STATE_PATH) => {
37
+ cachedClient = client;
38
+ cachedEndpoint = endpoint;
39
+ };
@@ -1,28 +1,3 @@
1
- export type SyncStateClient = {
2
- getState(key: string): Promise<unknown>;
3
- setState(value: unknown, key: string): Promise<void>;
4
- subscribe(key: string, handler: (value: unknown) => void): Promise<void>;
5
- unsubscribe(key: string, handler: (value: unknown) => void): Promise<void>;
6
- };
7
- type InitOptions = {
8
- endpoint?: string;
9
- };
10
- /**
11
- * Initializes and caches an RPC client instance for the sync state endpoint.
12
- * @param options Optional endpoint override.
13
- * @returns Cached client instance or `null` when running without `window`.
14
- */
15
- export declare const initSyncStateClient: (options?: InitOptions) => SyncStateClient | null;
16
- /**
17
- * Returns a cached client for the provided endpoint, creating it when necessary.
18
- * @param endpoint Endpoint to connect to.
19
- * @returns RPC client instance.
20
- */
21
- export declare const getSyncStateClient: (endpoint?: string) => SyncStateClient;
22
- /**
23
- * Injects a client instance for tests and updates the cached endpoint.
24
- * @param client Stub client instance or `null` to clear the cache.
25
- * @param endpoint Endpoint associated with the injected client.
26
- */
27
- export declare const setSyncStateClientForTesting: (client: SyncStateClient | null, endpoint?: string) => void;
28
- export {};
1
+ export { getSyncedStateClient, initSyncedStateClient, setSyncedStateClientForTesting, } from "./client-core.js";
2
+ export type { SyncedStateClient } from "./client-core.js";
3
+ export { useSyncedState } from "./useSyncedState.js";
@@ -1,39 +1,4 @@
1
- import { newWebSocketRpcSession } from "capnweb";
2
- import { DEFAULT_SYNC_STATE_PATH } from "./constants.mjs";
3
- let cachedClient = null;
4
- let cachedEndpoint = DEFAULT_SYNC_STATE_PATH;
5
- /**
6
- * Initializes and caches an RPC client instance for the sync state endpoint.
7
- * @param options Optional endpoint override.
8
- * @returns Cached client instance or `null` when running without `window`.
9
- */
10
- export const initSyncStateClient = (options = {}) => {
11
- cachedEndpoint = options.endpoint ?? DEFAULT_SYNC_STATE_PATH;
12
- if (typeof window === "undefined") {
13
- return null;
14
- }
15
- cachedClient = newWebSocketRpcSession(cachedEndpoint);
16
- return cachedClient;
17
- };
18
- /**
19
- * Returns a cached client for the provided endpoint, creating it when necessary.
20
- * @param endpoint Endpoint to connect to.
21
- * @returns RPC client instance.
22
- */
23
- export const getSyncStateClient = (endpoint = cachedEndpoint) => {
24
- if (cachedClient && endpoint === cachedEndpoint) {
25
- return cachedClient;
26
- }
27
- cachedEndpoint = endpoint;
28
- cachedClient = newWebSocketRpcSession(cachedEndpoint);
29
- return cachedClient;
30
- };
31
- /**
32
- * Injects a client instance for tests and updates the cached endpoint.
33
- * @param client Stub client instance or `null` to clear the cache.
34
- * @param endpoint Endpoint associated with the injected client.
35
- */
36
- export const setSyncStateClientForTesting = (client, endpoint = DEFAULT_SYNC_STATE_PATH) => {
37
- cachedClient = client;
38
- cachedEndpoint = endpoint;
39
- };
1
+ // Re-export everything from client-core to maintain the public API
2
+ export { getSyncedStateClient, initSyncedStateClient, setSyncedStateClientForTesting, } from "./client-core.js";
3
+ // Re-export useSyncedState (no circular dependency since useSyncedState imports from client-core, not client)
4
+ export { useSyncedState } from "./useSyncedState.js";
@@ -1 +1 @@
1
- export declare const DEFAULT_SYNC_STATE_PATH = "/__sync-state";
1
+ export declare const DEFAULT_SYNCED_STATE_PATH = "/__synced-state";
@@ -1 +1 @@
1
- export const DEFAULT_SYNC_STATE_PATH = "/__sync-state";
1
+ export const DEFAULT_SYNCED_STATE_PATH = "/__synced-state";