@praxisjs/core 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @praxisjs/core
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9affc5c: Add `syncedSignal` primitive and fix internal dead-code branches.
8
+
9
+ `syncedSignal(channelName, initialValue)` creates a signal that stays in sync across browser tabs in real-time via `BroadcastChannel`. Writes in any tab are broadcast to all other open tabs automatically.
10
+
11
+ `batch()` — simplified the flush path by replacing the unreachable `batchQueue ?? new Set()` fallback with a direct `if (isOuter && batchQueue)` guard.
12
+
13
+ `@praxisjs/composables` — removed no-op class field initializers (`_handler = () => {}`) that were immediately overwritten in `setup()`. Fields are now declared with `!` or typed as optional to reflect their real lifecycle.
14
+
3
15
  ## 1.4.1
4
16
 
5
17
  ### Patch Changes
@@ -91,6 +91,41 @@ describe("createResource", () => {
91
91
  expect(fetcher).toHaveBeenCalledTimes(2);
92
92
  });
93
93
  });
94
+ describe("resource — execute() sync throw via refetch()", () => {
95
+ it("refetch() captures a synchronous throw from the fetcher", async () => {
96
+ const r = resource(() => Promise.resolve(1), { immediate: false });
97
+ let calls = 0;
98
+ const r2 = resource(() => {
99
+ calls++;
100
+ if (calls >= 2)
101
+ throw new Error("sync in refetch");
102
+ return Promise.resolve(1);
103
+ }, { immediate: false });
104
+ r2.refetch(); // first call succeeds
105
+ await vi.waitFor(() => r2.status() === "success");
106
+ r2.refetch(); // second call throws synchronously
107
+ await vi.waitFor(() => r2.status() === "error");
108
+ expect(r2.error().message).toBe("sync in refetch");
109
+ void r;
110
+ });
111
+ it("refetch() wraps non-Error sync throws in Error", async () => {
112
+ let calls = 0;
113
+ const r = resource(() => {
114
+ calls++;
115
+ if (calls >= 2) {
116
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
117
+ throw "plain string sync";
118
+ }
119
+ return Promise.resolve(1);
120
+ }, { immediate: false });
121
+ r.refetch();
122
+ await vi.waitFor(() => r.status() === "success");
123
+ r.refetch();
124
+ await vi.waitFor(() => r.status() === "error");
125
+ expect(r.error()).toBeInstanceOf(Error);
126
+ expect(r.error().message).toBe("plain string sync");
127
+ });
128
+ });
94
129
  describe("resource — additional cases", () => {
95
130
  it("two concurrent refetch() calls — last result wins, stale result is discarded", async () => {
96
131
  let resolveFirst;
@@ -1 +1 @@
1
- {"version":3,"file":"resource.test.js","sourceRoot":"","sources":["../../src/__tests__/resource.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resource.test.js","sourceRoot":"","sources":["../../src/__tests__/resource.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=synced.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synced.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/synced.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,143 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ import { syncedSignal } from "../signal/synced";
3
+ import { effect } from "../signal/effect";
4
+ // BroadcastChannel mock
5
+ class MockBroadcastChannel {
6
+ static { this.instances = []; }
7
+ static { this.byChannel = new Map(); }
8
+ constructor(name) {
9
+ this.onmessage = null;
10
+ this.closed = false;
11
+ this.name = name;
12
+ MockBroadcastChannel.instances.push(this);
13
+ if (!MockBroadcastChannel.byChannel.has(name)) {
14
+ MockBroadcastChannel.byChannel.set(name, []);
15
+ }
16
+ MockBroadcastChannel.byChannel.get(name).push(this);
17
+ }
18
+ postMessage(data) {
19
+ // Deliver to all OTHER instances on same channel
20
+ MockBroadcastChannel.byChannel.get(this.name)?.forEach((ch) => {
21
+ if (ch !== this && ch.onmessage) {
22
+ ch.onmessage(new MessageEvent("message", { data }));
23
+ }
24
+ });
25
+ }
26
+ close() {
27
+ this.closed = true;
28
+ const list = MockBroadcastChannel.byChannel.get(this.name);
29
+ if (list) {
30
+ const idx = list.indexOf(this);
31
+ if (idx !== -1)
32
+ list.splice(idx, 1);
33
+ }
34
+ MockBroadcastChannel.instances.splice(MockBroadcastChannel.instances.indexOf(this), 1);
35
+ }
36
+ }
37
+ beforeEach(() => {
38
+ MockBroadcastChannel.instances = [];
39
+ MockBroadcastChannel.byChannel = new Map();
40
+ vi.stubGlobal("BroadcastChannel", MockBroadcastChannel);
41
+ });
42
+ describe("syncedSignal", () => {
43
+ it("reads initial value", () => {
44
+ const s = syncedSignal("ch", 42);
45
+ expect(s()).toBe(42);
46
+ s.close();
47
+ });
48
+ it("set() updates the signal value", () => {
49
+ const s = syncedSignal("ch", 0);
50
+ s.set(10);
51
+ expect(s()).toBe(10);
52
+ s.close();
53
+ });
54
+ it("update() applies a transform", () => {
55
+ const s = syncedSignal("ch", 5);
56
+ s.update((v) => v * 2);
57
+ expect(s()).toBe(10);
58
+ s.close();
59
+ });
60
+ it("set() posts a JSON message to the channel", () => {
61
+ const s = syncedSignal("ch", 0);
62
+ const postSpy = vi.spyOn(MockBroadcastChannel.instances[0], "postMessage");
63
+ s.set(99);
64
+ expect(postSpy).toHaveBeenCalledWith(JSON.stringify(99));
65
+ s.close();
66
+ });
67
+ it("receiving a message from another tab updates the signal", () => {
68
+ const s = syncedSignal("ch", 0);
69
+ const channel = MockBroadcastChannel.instances[0];
70
+ channel.onmessage(new MessageEvent("message", { data: JSON.stringify(7) }));
71
+ expect(s()).toBe(7);
72
+ s.close();
73
+ });
74
+ it("does not echo own set() back to itself", () => {
75
+ const s = syncedSignal("ch", 0);
76
+ // Simulate two instances on the same channel
77
+ const s2 = syncedSignal("ch", 0);
78
+ const received = [];
79
+ effect(() => { received.push(s2()); });
80
+ s.set(5);
81
+ // s2 should receive the message because it came from a different instance
82
+ expect(s2()).toBe(5);
83
+ // s itself should NOT trigger its own onmessage handler (no echo)
84
+ const channel = MockBroadcastChannel.instances[0];
85
+ const receivedBySelf = [];
86
+ effect(() => { receivedBySelf.push(s()); });
87
+ const beforeCount = receivedBySelf.length;
88
+ // Manually simulate echo — should be ignored because posting=false after set
89
+ channel.onmessage(new MessageEvent("message", { data: JSON.stringify(5) }));
90
+ // The value stays 5 (no spurious extra notification tested via subscribe count)
91
+ expect(s()).toBe(5);
92
+ expect(receivedBySelf.length).toBe(beforeCount); // no extra effect run (Object.is equality)
93
+ s.close();
94
+ s2.close();
95
+ });
96
+ it("subscribe fires immediately then on each remote change", () => {
97
+ const s = syncedSignal("ch", 0);
98
+ const channel = MockBroadcastChannel.instances[0];
99
+ const received = [];
100
+ s.subscribe((v) => received.push(v));
101
+ expect(received).toEqual([0]);
102
+ channel.onmessage(new MessageEvent("message", { data: JSON.stringify(3) }));
103
+ expect(received).toEqual([0, 3]);
104
+ s.close();
105
+ });
106
+ it("close() shuts down the BroadcastChannel", () => {
107
+ const s = syncedSignal("ch", 0);
108
+ const channel = MockBroadcastChannel.instances[0];
109
+ expect(channel.closed).toBe(false);
110
+ s.close();
111
+ expect(channel.closed).toBe(true);
112
+ });
113
+ it("has __isSignal marker", () => {
114
+ const s = syncedSignal("ch", 0);
115
+ expect(s.__isSignal).toBe(true);
116
+ s.close();
117
+ });
118
+ it("does not update value when onmessage fires while posting (posting guard)", () => {
119
+ // Use a self-delivering channel that echoes to itself during postMessage.
120
+ // This covers the `if (posting) return;` branch in synced.ts.
121
+ class SelfEchoChannel {
122
+ constructor() {
123
+ this.onmessage = null;
124
+ }
125
+ postMessage(data) {
126
+ this.onmessage?.(new MessageEvent("message", { data }));
127
+ }
128
+ close() { }
129
+ }
130
+ vi.stubGlobal("BroadcastChannel", SelfEchoChannel);
131
+ const s = syncedSignal("echo-ch", 0);
132
+ const received = [];
133
+ s.subscribe((v) => received.push(v));
134
+ // set() triggers postMessage → onmessage fires → posting=true → early return
135
+ // Inner value should not be double-set
136
+ s.set(42);
137
+ expect(s()).toBe(42);
138
+ // Only two notifications: initial (0) + the set (42), no echo re-set
139
+ expect(received).toEqual([0, 42]);
140
+ s.close();
141
+ });
142
+ });
143
+ //# sourceMappingURL=synced.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synced.test.js","sourceRoot":"","sources":["../../src/__tests__/synced.test.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  export { debounced, until, when, history, type HistoryElement, } from "./reactive";
2
- export { signal, persistedSignal, peek, computed, batch, effect, untrack, type PersistedSignalOptions, } from "./signal";
2
+ export { signal, persistedSignal, syncedSignal, peek, computed, batch, effect, untrack, type PersistedSignalOptions, type SyncedSignal, } from "./signal";
3
3
  export { RootComponent } from "./component";
4
4
  export { resource, createResource, type ResourceStatus, type Resource, type ResourceOptions, } from "./async/resource";
5
5
  //# sourceMappingURL=internal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,EACP,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,EACP,KAAK,sBAAsB,GAC5B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,EACP,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,EACP,KAAK,sBAAsB,EAC3B,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,EACd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,GACrB,MAAM,kBAAkB,CAAC"}
package/dist/internal.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { debounced, until, when, history, } from "./reactive";
2
- export { signal, persistedSignal, peek, computed, batch, effect, untrack, } from "./signal";
2
+ export { signal, persistedSignal, syncedSignal, peek, computed, batch, effect, untrack, } from "./signal";
3
3
  export { RootComponent } from "./component";
4
4
  export { resource, createResource, } from "./async/resource";
5
5
  //# sourceMappingURL=internal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,GAER,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,GAER,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,GAIf,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,KAAK,EACL,IAAI,EACJ,OAAO,GAER,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,MAAM,EACN,eAAe,EACf,YAAY,EACZ,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,MAAM,EACN,OAAO,GAGR,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EACL,QAAQ,EACR,cAAc,GAIf,MAAM,kBAAkB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/signal/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIvC,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,QAcnC"}
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/signal/batch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAIvC,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,QAgBnC"}
@@ -14,10 +14,12 @@ export function batch(fn) {
14
14
  fn();
15
15
  }
16
16
  finally {
17
- if (isOuter) {
18
- const effectsToRun = batchQueue ?? new Set();
17
+ if (isOuter && batchQueue) {
18
+ const effectsToRun = batchQueue;
19
19
  batchQueue = null;
20
- effectsToRun.forEach((eff) => { eff(); });
20
+ effectsToRun.forEach((eff) => {
21
+ eff();
22
+ });
21
23
  }
22
24
  }
23
25
  }
@@ -1 +1 @@
1
- {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/signal/batch.ts"],"names":[],"mappings":"AAEA,IAAI,UAAU,GAAuB,IAAI,CAAC;AAE1C,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,KAAK,IAAI,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAc;IAClC,MAAM,OAAO,GAAG,UAAU,KAAK,IAAI,CAAC;IACpC,IAAI,OAAO,EAAE,CAAC;QACZ,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,CAAC;QACH,EAAE,EAAE,CAAC;IACP,CAAC;YAAS,CAAC;QACT,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,YAAY,GAAG,UAAU,IAAI,IAAI,GAAG,EAAU,CAAC;YACrD,UAAU,GAAG,IAAI,CAAC;YAClB,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/signal/batch.ts"],"names":[],"mappings":"AAEA,IAAI,UAAU,GAAuB,IAAI,CAAC;AAE1C,MAAM,UAAU,UAAU;IACxB,OAAO,UAAU,KAAK,IAAI,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,EAAc;IAClC,MAAM,OAAO,GAAG,UAAU,KAAK,IAAI,CAAC;IACpC,IAAI,OAAO,EAAE,CAAC;QACZ,UAAU,GAAG,IAAI,GAAG,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,CAAC;QACH,EAAE,EAAE,CAAC;IACP,CAAC;YAAS,CAAC;QACT,IAAI,OAAO,IAAI,UAAU,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,UAAU,CAAC;YAChC,UAAU,GAAG,IAAI,CAAC;YAClB,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC3B,GAAG,EAAE,CAAC;YACR,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -3,5 +3,6 @@ export { peek } from "./peek";
3
3
  export { signal } from "./signal";
4
4
  export { computed } from "./computed";
5
5
  export { type PersistedSignalOptions, persistedSignal } from "./persisted";
6
+ export { type SyncedSignal, syncedSignal } from "./synced";
6
7
  export { effect, untrack } from "./effect";
7
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/signal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/signal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,sBAAsB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,KAAK,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
@@ -3,5 +3,6 @@ export { peek } from "./peek";
3
3
  export { signal } from "./signal";
4
4
  export { computed } from "./computed";
5
5
  export { persistedSignal } from "./persisted";
6
+ export { syncedSignal } from "./synced";
6
7
  export { effect, untrack } from "./effect";
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/signal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAA+B,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/signal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAA+B,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAqB,YAAY,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Signal } from "@praxisjs/shared";
2
+ export interface SyncedSignal<T> extends Signal<T> {
3
+ close(): void;
4
+ }
5
+ export declare function syncedSignal<T>(channelName: string, initialValue: T): SyncedSignal<T>;
6
+ //# sourceMappingURL=synced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synced.d.ts","sourceRoot":"","sources":["../../src/signal/synced.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAI/C,MAAM,WAAW,YAAY,CAAC,CAAC,CAAE,SAAQ,MAAM,CAAC,CAAC,CAAC;IAChD,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,CAAC,GACd,YAAY,CAAC,CAAC,CAAC,CA4CjB"}
@@ -0,0 +1,43 @@
1
+ import { signal } from "./signal";
2
+ export function syncedSignal(channelName, initialValue) {
3
+ const inner = signal(initialValue);
4
+ const channel = new BroadcastChannel(channelName);
5
+ let posting = false;
6
+ channel.onmessage = (event) => {
7
+ if (posting)
8
+ return;
9
+ try {
10
+ inner.set(JSON.parse(String(event.data)));
11
+ }
12
+ catch {
13
+ // ignore malformed messages
14
+ }
15
+ };
16
+ function read() {
17
+ return inner();
18
+ }
19
+ function set(value) {
20
+ posting = true;
21
+ try {
22
+ inner.set(value);
23
+ channel.postMessage(JSON.stringify(value));
24
+ }
25
+ finally {
26
+ posting = false;
27
+ }
28
+ }
29
+ function update(fn) {
30
+ set(fn(inner()));
31
+ }
32
+ function close() {
33
+ channel.close();
34
+ }
35
+ const source = read;
36
+ source.set = set;
37
+ source.update = update;
38
+ source.subscribe = inner.subscribe.bind(inner);
39
+ source.__isSignal = true;
40
+ source.close = close;
41
+ return source;
42
+ }
43
+ //# sourceMappingURL=synced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synced.js","sourceRoot":"","sources":["../../src/signal/synced.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAMlC,MAAM,UAAU,YAAY,CAC1B,WAAmB,EACnB,YAAe;IAEf,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAClD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,OAAO,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;QAC1C,IAAI,OAAO;YAAE,OAAO;QACpB,IAAI,CAAC;YACH,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAM,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,4BAA4B;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF,SAAS,IAAI;QACX,OAAO,KAAK,EAAE,CAAC;IACjB,CAAC;IAED,SAAS,GAAG,CAAC,KAAQ;QACnB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC;YACH,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACjB,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,CAAC;gBAAS,CAAC;YACT,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;IACH,CAAC;IAED,SAAS,MAAM,CAAC,EAAkB;QAChC,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACnB,CAAC;IAED,SAAS,KAAK;QACZ,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,IAAuB,CAAC;IACvC,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IAErB,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisjs/core",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -109,6 +109,48 @@ describe("createResource", () => {
109
109
  });
110
110
  });
111
111
 
112
+ describe("resource — execute() sync throw via refetch()", () => {
113
+ it("refetch() captures a synchronous throw from the fetcher", async () => {
114
+ const r = resource(() => Promise.resolve(1), { immediate: false });
115
+ let calls = 0;
116
+ const r2 = resource(
117
+ () => {
118
+ calls++;
119
+ if (calls >= 2) throw new Error("sync in refetch");
120
+ return Promise.resolve(1);
121
+ },
122
+ { immediate: false },
123
+ );
124
+ r2.refetch(); // first call succeeds
125
+ await vi.waitFor(() => r2.status() === "success");
126
+ r2.refetch(); // second call throws synchronously
127
+ await vi.waitFor(() => r2.status() === "error");
128
+ expect((r2.error() as Error).message).toBe("sync in refetch");
129
+ void r;
130
+ });
131
+
132
+ it("refetch() wraps non-Error sync throws in Error", async () => {
133
+ let calls = 0;
134
+ const r = resource(
135
+ () => {
136
+ calls++;
137
+ if (calls >= 2) {
138
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
139
+ throw "plain string sync";
140
+ }
141
+ return Promise.resolve(1);
142
+ },
143
+ { immediate: false },
144
+ );
145
+ r.refetch();
146
+ await vi.waitFor(() => r.status() === "success");
147
+ r.refetch();
148
+ await vi.waitFor(() => r.status() === "error");
149
+ expect(r.error()).toBeInstanceOf(Error);
150
+ expect((r.error() as Error).message).toBe("plain string sync");
151
+ });
152
+ });
153
+
112
154
  describe("resource — additional cases", () => {
113
155
  it("two concurrent refetch() calls — last result wins, stale result is discarded", async () => {
114
156
  let resolveFirst!: (v: string) => void;
@@ -0,0 +1,173 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+
3
+ import { syncedSignal } from "../signal/synced";
4
+ import { effect } from "../signal/effect";
5
+
6
+ // BroadcastChannel mock
7
+ class MockBroadcastChannel {
8
+ static instances: MockBroadcastChannel[] = [];
9
+ static byChannel: Map<string, MockBroadcastChannel[]> = new Map();
10
+
11
+ onmessage: ((event: MessageEvent) => void) | null = null;
12
+ readonly name: string;
13
+ closed = false;
14
+
15
+ constructor(name: string) {
16
+ this.name = name;
17
+ MockBroadcastChannel.instances.push(this);
18
+ if (!MockBroadcastChannel.byChannel.has(name)) {
19
+ MockBroadcastChannel.byChannel.set(name, []);
20
+ }
21
+ MockBroadcastChannel.byChannel.get(name)!.push(this);
22
+ }
23
+
24
+ postMessage(data: unknown) {
25
+ // Deliver to all OTHER instances on same channel
26
+ MockBroadcastChannel.byChannel.get(this.name)?.forEach((ch) => {
27
+ if (ch !== this && ch.onmessage) {
28
+ ch.onmessage(new MessageEvent("message", { data }));
29
+ }
30
+ });
31
+ }
32
+
33
+ close() {
34
+ this.closed = true;
35
+ const list = MockBroadcastChannel.byChannel.get(this.name);
36
+ if (list) {
37
+ const idx = list.indexOf(this);
38
+ if (idx !== -1) list.splice(idx, 1);
39
+ }
40
+ MockBroadcastChannel.instances.splice(
41
+ MockBroadcastChannel.instances.indexOf(this),
42
+ 1,
43
+ );
44
+ }
45
+ }
46
+
47
+ beforeEach(() => {
48
+ MockBroadcastChannel.instances = [];
49
+ MockBroadcastChannel.byChannel = new Map();
50
+ vi.stubGlobal("BroadcastChannel", MockBroadcastChannel);
51
+ });
52
+
53
+ describe("syncedSignal", () => {
54
+ it("reads initial value", () => {
55
+ const s = syncedSignal("ch", 42);
56
+ expect(s()).toBe(42);
57
+ s.close();
58
+ });
59
+
60
+ it("set() updates the signal value", () => {
61
+ const s = syncedSignal("ch", 0);
62
+ s.set(10);
63
+ expect(s()).toBe(10);
64
+ s.close();
65
+ });
66
+
67
+ it("update() applies a transform", () => {
68
+ const s = syncedSignal("ch", 5);
69
+ s.update((v) => v * 2);
70
+ expect(s()).toBe(10);
71
+ s.close();
72
+ });
73
+
74
+ it("set() posts a JSON message to the channel", () => {
75
+ const s = syncedSignal("ch", 0);
76
+ const postSpy = vi.spyOn(
77
+ MockBroadcastChannel.instances[0],
78
+ "postMessage",
79
+ );
80
+ s.set(99);
81
+ expect(postSpy).toHaveBeenCalledWith(JSON.stringify(99));
82
+ s.close();
83
+ });
84
+
85
+ it("receiving a message from another tab updates the signal", () => {
86
+ const s = syncedSignal("ch", 0);
87
+ const channel = MockBroadcastChannel.instances[0];
88
+
89
+ channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(7) }));
90
+ expect(s()).toBe(7);
91
+ s.close();
92
+ });
93
+
94
+ it("does not echo own set() back to itself", () => {
95
+ const s = syncedSignal("ch", 0);
96
+
97
+ // Simulate two instances on the same channel
98
+ const s2 = syncedSignal("ch", 0);
99
+ const received: number[] = [];
100
+ effect(() => { received.push(s2()); });
101
+
102
+ s.set(5);
103
+ // s2 should receive the message because it came from a different instance
104
+ expect(s2()).toBe(5);
105
+
106
+ // s itself should NOT trigger its own onmessage handler (no echo)
107
+ const channel = MockBroadcastChannel.instances[0];
108
+ const receivedBySelf: number[] = [];
109
+ effect(() => { receivedBySelf.push(s()); });
110
+ const beforeCount = receivedBySelf.length;
111
+ // Manually simulate echo — should be ignored because posting=false after set
112
+ channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(5) }));
113
+ // The value stays 5 (no spurious extra notification tested via subscribe count)
114
+ expect(s()).toBe(5);
115
+ expect(receivedBySelf.length).toBe(beforeCount); // no extra effect run (Object.is equality)
116
+
117
+ s.close();
118
+ s2.close();
119
+ });
120
+
121
+ it("subscribe fires immediately then on each remote change", () => {
122
+ const s = syncedSignal("ch", 0);
123
+ const channel = MockBroadcastChannel.instances[0];
124
+ const received: number[] = [];
125
+ s.subscribe((v) => received.push(v));
126
+
127
+ expect(received).toEqual([0]);
128
+
129
+ channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(3) }));
130
+ expect(received).toEqual([0, 3]);
131
+ s.close();
132
+ });
133
+
134
+ it("close() shuts down the BroadcastChannel", () => {
135
+ const s = syncedSignal("ch", 0);
136
+ const channel = MockBroadcastChannel.instances[0];
137
+ expect(channel.closed).toBe(false);
138
+ s.close();
139
+ expect(channel.closed).toBe(true);
140
+ });
141
+
142
+ it("has __isSignal marker", () => {
143
+ const s = syncedSignal("ch", 0);
144
+ expect(s.__isSignal).toBe(true);
145
+ s.close();
146
+ });
147
+
148
+ it("does not update value when onmessage fires while posting (posting guard)", () => {
149
+ // Use a self-delivering channel that echoes to itself during postMessage.
150
+ // This covers the `if (posting) return;` branch in synced.ts.
151
+ class SelfEchoChannel {
152
+ onmessage: ((e: MessageEvent) => void) | null = null;
153
+ postMessage(data: unknown) {
154
+ this.onmessage?.(new MessageEvent("message", { data }));
155
+ }
156
+ close() {}
157
+ }
158
+ vi.stubGlobal("BroadcastChannel", SelfEchoChannel);
159
+
160
+ const s = syncedSignal("echo-ch", 0);
161
+ const received: number[] = [];
162
+ s.subscribe((v) => received.push(v));
163
+
164
+ // set() triggers postMessage → onmessage fires → posting=true → early return
165
+ // Inner value should not be double-set
166
+ s.set(42);
167
+ expect(s()).toBe(42);
168
+ // Only two notifications: initial (0) + the set (42), no echo re-set
169
+ expect(received).toEqual([0, 42]);
170
+
171
+ s.close();
172
+ });
173
+ });
package/src/internal.ts CHANGED
@@ -8,12 +8,14 @@ export {
8
8
  export {
9
9
  signal,
10
10
  persistedSignal,
11
+ syncedSignal,
11
12
  peek,
12
13
  computed,
13
14
  batch,
14
15
  effect,
15
16
  untrack,
16
17
  type PersistedSignalOptions,
18
+ type SyncedSignal,
17
19
  } from "./signal";
18
20
  export { RootComponent } from "./component";
19
21
  export {
@@ -18,10 +18,12 @@ export function batch(fn: () => void) {
18
18
  try {
19
19
  fn();
20
20
  } finally {
21
- if (isOuter) {
22
- const effectsToRun = batchQueue ?? new Set<Effect>();
21
+ if (isOuter && batchQueue) {
22
+ const effectsToRun = batchQueue;
23
23
  batchQueue = null;
24
- effectsToRun.forEach((eff) => { eff(); });
24
+ effectsToRun.forEach((eff) => {
25
+ eff();
26
+ });
25
27
  }
26
28
  }
27
29
  }
@@ -3,4 +3,5 @@ export { peek } from "./peek";
3
3
  export { signal } from "./signal";
4
4
  export { computed } from "./computed";
5
5
  export { type PersistedSignalOptions, persistedSignal } from "./persisted";
6
+ export { type SyncedSignal, syncedSignal } from "./synced";
6
7
  export { effect, untrack } from "./effect";
@@ -0,0 +1,56 @@
1
+ import type { Signal } from "@praxisjs/shared";
2
+
3
+ import { signal } from "./signal";
4
+
5
+ export interface SyncedSignal<T> extends Signal<T> {
6
+ close(): void;
7
+ }
8
+
9
+ export function syncedSignal<T>(
10
+ channelName: string,
11
+ initialValue: T,
12
+ ): SyncedSignal<T> {
13
+ const inner = signal(initialValue);
14
+ const channel = new BroadcastChannel(channelName);
15
+ let posting = false;
16
+
17
+ channel.onmessage = (event: MessageEvent) => {
18
+ if (posting) return;
19
+ try {
20
+ inner.set(JSON.parse(String(event.data)) as T);
21
+ } catch {
22
+ // ignore malformed messages
23
+ }
24
+ };
25
+
26
+ function read() {
27
+ return inner();
28
+ }
29
+
30
+ function set(value: T) {
31
+ posting = true;
32
+ try {
33
+ inner.set(value);
34
+ channel.postMessage(JSON.stringify(value));
35
+ } finally {
36
+ posting = false;
37
+ }
38
+ }
39
+
40
+ function update(fn: (prev: T) => T) {
41
+ set(fn(inner()));
42
+ }
43
+
44
+ function close() {
45
+ channel.close();
46
+ }
47
+
48
+ const source = read as SyncedSignal<T>;
49
+ source.set = set;
50
+ source.update = update;
51
+ source.subscribe = inner.subscribe.bind(inner);
52
+ source.__isSignal = true;
53
+ source.close = close;
54
+
55
+ return source;
56
+ }