@dougongjs/reactive 0.9.0 → 0.10.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/README.md CHANGED
@@ -5,7 +5,7 @@ Independent synchronous signals and structurally owned reactive generations. No
5
5
  Upgrading from 0.8.3? Read the [migration guide](https://tangerg.github.io/dougong/en/guide/migrating-to-0.9) and [0.9.0 release notes](https://tangerg.github.io/dougong/en/reference/release-0.9.0).
6
6
 
7
7
  ```ts
8
- import { batch, computed, signal } from "@dougongjs/reactive";
8
+ import { batch, computed, disposeSymbol, signal } from "@dougongjs/reactive";
9
9
 
10
10
  const first = signal("Dougong");
11
11
  const last = signal("Plugins");
@@ -15,13 +15,19 @@ batch(() => {
15
15
  first.set("Typed");
16
16
  last.set("Composition");
17
17
  });
18
- subscription[Symbol.dispose]();
18
+ subscription[disposeSymbol]();
19
19
  ```
20
20
 
21
21
  `Readable<T>` exposes `get()` and `subscribe()`. The subscription implements standard `Symbol.dispose`; callbacks notify changes without replay. `bridge(owner, readable)` adapts another module copy or implementation into the local dependency graph. Its subscription and terminal detachment belong to the supplied owner through `defer`.
22
22
 
23
+ `batch`, `computed`, `subscribe` and `observe` require synchronous callbacks in both their types and runtime checks. Direct Promise results, PromiseLike results and mixed asynchronous branches are rejected, including when a caller explicitly supplies `void`. Ordinary synchronous return values remain inferred; `Observer<T, Child, Result>` can describe an explicit non-void result. Values whose type was already erased still receive the runtime check.
24
+
23
25
  `observe(owner, readable, observer)` disposes the previous child before building the next one. The structural owner supplies `child`, `defer` and `spawn`; only the returned child needs `Symbol.asyncDispose`; no framework base class is required. Use `generation.spawn` for asynchronous observer work.
24
26
 
25
- ESM; Node.js 22+, Chrome/Edge 119+, Firefox 124+, Safari 17.4+.
27
+ `ObservationTask` describes completion only: it is not generic, and its `result` is `PromiseLike<unknown>`. The required `spawn` accepts a task returning `void | PromiseLike<void>`. Owners may provide a richer generic task API without coupling observation to their result payloads.
28
+
29
+ Results inheriting this module's realm's `Promise.prototype` select the intrinsic native protocol, including decorated local Promises and subclasses. Other results use one captured structural `then`; display tags do not select a protocol. Foreign Promises must expose a conforming public `then`. Adapt decorated foreign results in their origin realm, and box payloads there when another assimilation would change them. See the guide for the precise boundary and disposal guarantees.
30
+
31
+ ESM; <!-- runtime-baseline:start -->Node.js `^24.22.0 || >=26.10.0`, Chrome ≥ 119, Edge ≥ 119, Firefox ≥ 124, Safari ≥ 17.4<!-- runtime-baseline:end -->.
26
32
 
27
33
  [Guide](https://tangerg.github.io/dougong/en/guide/reactive)
@@ -0,0 +1,10 @@
1
+ type WithoutCallableThen<T> = T extends object ? "then" extends keyof T ? Extract<T["then"], (...arguments_: never[]) => unknown> extends never ? T : never : T : T;
2
+ export type SynchronousResult<T> = (T & NoInfer<WithoutCallableThen<T>>) | (T & undefined);
3
+ export interface ResolvedValue<T> {
4
+ readonly value: T;
5
+ }
6
+ export declare function resolveValue<T>(value: T | PromiseLike<T>): Promise<ResolvedValue<Awaited<T>>>;
7
+ export declare function assertSynchronous(value: unknown, message: string): void;
8
+ export declare function captureThenable(value: unknown): Promise<ResolvedValue<unknown>> | undefined;
9
+ export {};
10
+ //# sourceMappingURL=async-result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-result.d.ts","sourceRoot":"","sources":["../src/async-result.ts"],"names":[],"mappings":"AAIA,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC1C,MAAM,SAAS,MAAM,CAAC,GACpB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,KAAK,EAAE,KAAK,OAAO,CAAC,SAAS,KAAK,GACnE,CAAC,GACD,KAAK,GACP,CAAC,GACH,CAAC,CAAC;AAIN,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;AAE3F,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED,wBAAsB,YAAY,CAAC,CAAC,EAClC,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAGpC;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAUvE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,CA0B3F"}
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAU,KAAK,cAAc,EAAe,MAAM,cAAc,CAAC;AAExE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,KAAK,eAAe,CAAC;CAC7D;AA2ID,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAmBpF"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAU,KAAK,cAAc,EAAe,MAAM,cAAc,CAAC;AAGxE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,KAAK,eAAe,CAAC;CAC7D;AA4ID,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAmBpF"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { batch, computed, signal, type ReadonlySignal, type Signal } from './signals.js';
2
2
  export { bridge, type BridgeOwner } from './bridge.js';
3
- export type { AsyncDisposable, Disposable, Readable } from './protocol.js';
3
+ export { asyncDisposeSymbol, disposeSymbol, type AsyncDisposable, type Disposable, type Readable, } from './protocol.js';
4
4
  export { observe, type ObservationOwner, type ObservationTask, type Observer } from './observe.js';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AACzF,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,QAAQ,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -7,14 +7,20 @@ function n(e, t) {
7
7
  return e ?? Symbol.for(t);
8
8
  }
9
9
  t(Promise.withResolvers);
10
- var r = n(Symbol.dispose, "Symbol.dispose"), i = n(Symbol.asyncDispose, "Symbol.asyncDispose");
11
- // src/synchronous-result.ts
12
- function a(e, t) {
13
- let n = o(e);
10
+ var r = n(Symbol.dispose, "Symbol.dispose"), i = n(Symbol.asyncDispose, "Symbol.asyncDispose"), a = Promise.prototype, o = a.then;
11
+ async function s(e) {
12
+ return l(e) ?? Object.freeze({ value: e });
13
+ }
14
+ function c(e, t) {
15
+ let n = l(e);
14
16
  if (n) throw n.then(() => void 0, () => void 0), TypeError(t);
15
17
  }
16
- function o(e) {
18
+ function l(e) {
17
19
  if (e === null || typeof e != "object" && typeof e != "function") return;
20
+ if (u(e)) {
21
+ let t = Promise.withResolvers();
22
+ return Reflect.apply(o, e, [(e) => t.resolve(Object.freeze({ value: e })), t.reject]), t.promise;
23
+ }
18
24
  let t = e.then;
19
25
  if (typeof t != "function") return;
20
26
  let n = Promise.withResolvers();
@@ -24,10 +30,19 @@ function o(e) {
24
30
  } catch (e) {
25
31
  n.reject(e);
26
32
  }
27
- }), n.promise;
33
+ }), n.promise.then((e) => Object.freeze({ value: e }));
34
+ }
35
+ function u(e) {
36
+ let t = /* @__PURE__ */ new Set();
37
+ for (let n = Object.getPrototypeOf(e); n !== null; n = Object.getPrototypeOf(n)) {
38
+ if (n === a) return !0;
39
+ if (t.has(n)) throw TypeError("Result has a cyclic prototype chain");
40
+ t.add(n);
41
+ }
42
+ return !1;
28
43
  }
29
44
  // src/protocol.ts
30
- function s(e, t) {
45
+ function d(e, t) {
31
46
  let n = e?.get, r = e?.subscribe;
32
47
  if (typeof n != "function" || typeof r != "function") throw TypeError(`${t} expects a readable source`);
33
48
  return Object.freeze({
@@ -35,22 +50,22 @@ function s(e, t) {
35
50
  subscribe: (t) => Reflect.apply(r, e, [t])
36
51
  });
37
52
  }
38
- function c(e) {
53
+ function f(e) {
39
54
  let t = e?.[r];
40
- return typeof t != "function" && u(e, "Readable.subscribe() must return a Disposable"), () => a(Reflect.apply(t, e, []), "Readable subscriptions must dispose synchronously");
55
+ return typeof t != "function" && m(e, "Readable.subscribe() must return a Disposable"), () => c(Reflect.apply(t, e, []), "Readable subscriptions must dispose synchronously");
41
56
  }
42
- function l(e, t) {
57
+ function p(e, t) {
43
58
  let n = e?.[i];
44
- return typeof n != "function" && u(e, t), () => Reflect.apply(n, e, []);
59
+ return typeof n != "function" && m(e, t), () => Reflect.apply(n, e, []);
45
60
  }
46
- function u(e, t) {
47
- throw a(e, t), TypeError(t);
61
+ function m(e, t) {
62
+ throw c(e, t), TypeError(t);
48
63
  }
49
- function d(e) {
64
+ function h(e) {
50
65
  if (typeof e != "function") throw TypeError("Signal subscriber must be a function");
51
66
  }
52
67
  // src/signals.ts
53
- var f = 0, p = 0, m = !1, h = !1, g = /* @__PURE__ */ new Set(), _ = /* @__PURE__ */ new Set(), v, y = [], b = class {
68
+ var g = 0, _ = 0, v = !1, y = !1, b = /* @__PURE__ */ new Set(), x = /* @__PURE__ */ new Set(), S, C = [], w = class {
54
69
  #e;
55
70
  constructor(e) {
56
71
  this.#e = e, Object.freeze(this);
@@ -60,64 +75,64 @@ var f = 0, p = 0, m = !1, h = !1, g = /* @__PURE__ */ new Set(), _ = /* @__PURE_
60
75
  this.#e = void 0, e?.();
61
76
  }
62
77
  };
63
- function x() {
64
- if (m) return;
78
+ function T() {
79
+ if (v) return;
65
80
  let e = [];
66
- m = !0;
81
+ v = !0;
67
82
  try {
68
- for (; g.size;) {
69
- let t = g.values().next().value;
70
- g.delete(t);
83
+ for (; b.size;) {
84
+ let t = b.values().next().value;
85
+ b.delete(t);
71
86
  let n = t.listener;
72
87
  if (n) try {
73
- a(n(), "Signal subscribers must be synchronous");
88
+ c(n(), "Signal subscribers must be synchronous");
74
89
  } catch (t) {
75
90
  e.push(t);
76
91
  }
77
92
  }
78
93
  } finally {
79
- g.clear(), m = !1;
94
+ b.clear(), v = !1;
80
95
  }
81
- w(e);
96
+ O(e);
82
97
  }
83
- function S(e) {
84
- for (let t of e) (t.kind === "dependency" ? _ : g).add(t);
85
- if (!h) {
86
- h = !0;
98
+ function E(e) {
99
+ for (let t of e) (t.kind === "dependency" ? x : b).add(t);
100
+ if (!y) {
101
+ y = !0;
87
102
  try {
88
- for (; _.size;) {
89
- let e = _.values().next().value;
90
- _.delete(e);
103
+ for (; x.size;) {
104
+ let e = x.values().next().value;
105
+ x.delete(e);
91
106
  let t = e.listener;
92
107
  t?.();
93
108
  }
94
109
  } finally {
95
- h = !1, _.clear();
110
+ y = !1, x.clear();
96
111
  }
97
- p || x();
112
+ _ || T();
98
113
  }
99
114
  }
100
- function C(e, t, n) {
101
- d(t);
115
+ function D(e, t, n) {
116
+ h(t);
102
117
  let r = {
103
118
  kind: n,
104
119
  listener: t
105
120
  };
106
- return e.add(r), new b(() => {
121
+ return e.add(r), new w(() => {
107
122
  r.listener = void 0, e.delete(r);
108
123
  });
109
124
  }
110
- function w(e) {
125
+ function O(e) {
111
126
  if (e.length === 1) throw e[0];
112
127
  if (e.length > 1) throw AggregateError(e, "Reactive subscribers failed");
113
128
  }
114
- function T(e) {
129
+ function k(e) {
115
130
  if (typeof e != "function") throw TypeError("batch() expects a function");
116
- p++;
131
+ _++;
117
132
  let t;
118
133
  try {
119
134
  let n = e();
120
- a(n, "Reactive batches must be synchronous"), t = {
135
+ c(n, "Reactive batches must be synchronous"), t = {
121
136
  succeeded: !0,
122
137
  value: n
123
138
  };
@@ -127,10 +142,10 @@ function T(e) {
127
142
  error: e
128
143
  };
129
144
  } finally {
130
- p--;
145
+ _--;
131
146
  }
132
- if (!p) try {
133
- x();
147
+ if (!_) try {
148
+ T();
134
149
  } catch (e) {
135
150
  t = t.succeeded ? {
136
151
  succeeded: !1,
@@ -143,23 +158,23 @@ function T(e) {
143
158
  if (!t.succeeded) throw t.error;
144
159
  return t.value;
145
160
  }
146
- function E(e) {
147
- return new O(e).view;
161
+ function A(e) {
162
+ return new M(e).view;
148
163
  }
149
- function D(e) {
164
+ function j(e) {
150
165
  if (typeof e != "function") throw TypeError("computed() expects a function");
151
- return new k(e).view;
166
+ return new N(e).view;
152
167
  }
153
- var O = class {
168
+ var M = class {
154
169
  #e = /* @__PURE__ */ new Set();
155
170
  #t;
156
171
  #n = 0;
157
172
  view;
158
173
  constructor(e) {
159
174
  this.#t = e, this.view = Object.freeze({
160
- get: () => (v?.add(this), this.#t),
175
+ get: () => (S?.add(this), this.#t),
161
176
  set: (e) => this.#r(e),
162
- subscribe: (e) => C(this.#e, e, "observer")
177
+ subscribe: (e) => D(this.#e, e, "observer")
163
178
  });
164
179
  }
165
180
  get version() {
@@ -167,13 +182,13 @@ var O = class {
167
182
  }
168
183
  refresh() {}
169
184
  subscribeInvalidation(e) {
170
- return C(this.#e, e, "dependency");
185
+ return D(this.#e, e, "dependency");
171
186
  }
172
187
  #r(e) {
173
- if (v) throw TypeError("Computed signal calculations cannot write signals");
174
- Object.is(this.#t, e) || (this.#t = e, f++, this.#n++, S(this.#e));
188
+ if (S) throw TypeError("Computed signal calculations cannot write signals");
189
+ Object.is(this.#t, e) || (this.#t = e, g++, this.#n++, E(this.#e));
175
190
  }
176
- }, k = class e {
191
+ }, N = class e {
177
192
  #e;
178
193
  #t = /* @__PURE__ */ new Set();
179
194
  #n = /* @__PURE__ */ new Map();
@@ -181,7 +196,7 @@ var O = class {
181
196
  #i = -1;
182
197
  #a;
183
198
  #o;
184
- #s = !0;
199
+ #s = -1;
185
200
  #c = 0;
186
201
  view;
187
202
  constructor(e) {
@@ -194,22 +209,22 @@ var O = class {
194
209
  return this.#c;
195
210
  }
196
211
  refresh() {
197
- if (this.#a !== void 0) throw v && this.#l(this.#a, v), TypeError("Circular computed signal");
198
- this.#a = y.length, y.push(this);
212
+ if (this.#a !== void 0) throw S && this.#l(this.#a, S), TypeError("Circular computed signal");
213
+ this.#a = C.length, C.push(this);
199
214
  try {
200
215
  this.#g();
201
216
  } finally {
202
- y.pop(), this.#a = void 0;
217
+ C.pop(), this.#a = void 0;
203
218
  }
204
219
  }
205
220
  #l(t, n) {
206
221
  let r = /* @__PURE__ */ new Set();
207
- for (let e of y.slice(t)) for (let t of e.#o ?? e.#n.keys()) r.add(t);
222
+ for (let e of C.slice(t)) for (let t of e.#o ?? e.#n.keys()) r.add(t);
208
223
  for (let t of r) if (t instanceof e) for (let e of t.#n.keys()) r.add(e);
209
224
  else n.add(t);
210
225
  }
211
226
  #u() {
212
- return this.refresh(), v?.add(this), this.#d();
227
+ return this.refresh(), S?.add(this), this.#d();
213
228
  }
214
229
  #d() {
215
230
  let e = this.#r;
@@ -220,7 +235,7 @@ var O = class {
220
235
  return this.#f(e, "dependency");
221
236
  }
222
237
  #f(e, t = "observer") {
223
- d(e);
238
+ h(e);
224
239
  let n = {
225
240
  kind: t,
226
241
  listener: e
@@ -230,12 +245,12 @@ var O = class {
230
245
  } catch (e) {
231
246
  throw this.#t.delete(n), this.#t.size || this.#m(), e;
232
247
  }
233
- return new b(() => {
248
+ return new w(() => {
234
249
  n.listener = void 0, this.#t.delete(n), this.#t.size || this.#m();
235
250
  });
236
251
  }
237
252
  #p = () => {
238
- this.#s || (this.#s = !0, S(this.#t));
253
+ this.#s !== g && (this.#s = g, E(this.#t));
239
254
  };
240
255
  #m() {
241
256
  for (let e of this.#n.values()) e.subscription?.[r](), e.subscription = void 0;
@@ -245,24 +260,23 @@ var O = class {
245
260
  }
246
261
  #g() {
247
262
  let e = this.#r;
248
- if (e && !this.#s && (this.#i === f || !this.#_())) {
249
- this.#i = f;
263
+ if (e && this.#s <= this.#i && (this.#i === g || !this.#_())) {
264
+ this.#i = g;
250
265
  return;
251
266
  }
252
- this.#s = !0;
253
267
  let t = /* @__PURE__ */ new Set(), n = this.#v(t);
254
- this.#y(t), (!e || (n.phase === "value" ? e.phase !== "value" || !Object.is(e.value, n.value) : e.phase !== "error" || !Object.is(e.error, n.error))) && this.#c++, this.#r = n, this.#i = f, this.#s = !1, this.#t.size && this.#h();
268
+ this.#y(t), (!e || (n.phase === "value" ? e.phase !== "value" || !Object.is(e.value, n.value) : e.phase !== "error" || !Object.is(e.error, n.error))) && this.#c++, this.#r = n, this.#i = g, this.#t.size && this.#h();
255
269
  }
256
270
  #_() {
257
271
  for (let [t, n] of this.#n) if (t instanceof e && t.#a !== void 0 || (t.refresh(), n.version !== t.version)) return !0;
258
- return this.#s;
272
+ return this.#s > this.#i;
259
273
  }
260
274
  #v(e) {
261
- let t = v;
262
- this.#o = e, v = e;
275
+ let t = S;
276
+ this.#o = e, S = e;
263
277
  try {
264
278
  let e = this.#e, t = e();
265
- return a(t, "Computed signal calculations must be synchronous"), {
279
+ return c(t, "Computed signal calculations must be synchronous"), {
266
280
  phase: "value",
267
281
  value: t
268
282
  };
@@ -272,7 +286,7 @@ var O = class {
272
286
  error: e
273
287
  };
274
288
  } finally {
275
- v = t, this.#o = void 0;
289
+ S = t, this.#o = void 0;
276
290
  }
277
291
  }
278
292
  #y(e) {
@@ -285,14 +299,14 @@ var O = class {
285
299
  });
286
300
  }
287
301
  }
288
- }, A = class {
302
+ }, P = class {
289
303
  #e;
290
304
  #t;
291
305
  #n;
292
306
  #r;
293
307
  view;
294
308
  constructor(e) {
295
- this.#e = E({
309
+ this.#e = A({
296
310
  phase: "value",
297
311
  source: e,
298
312
  value: e.get()
@@ -309,10 +323,10 @@ var O = class {
309
323
  start(e) {
310
324
  let t = !0, n;
311
325
  try {
312
- n = l(e.defer(() => (this[r](), t ? Promise.resolve().then(() => this.#i()) : void 0)), "BridgeOwner.defer() must return an AsyncDisposable");
326
+ n = p(e.defer(() => (this[r](), t ? Promise.resolve().then(() => this.#i()) : void 0)), "BridgeOwner.defer() must return an AsyncDisposable");
313
327
  let i = this.#e?.get();
314
328
  if (!i) throw Error("Readable bridge has been disposed");
315
- let a = c(i.source.subscribe(() => this.#a()));
329
+ let a = f(i.source.subscribe(() => this.#a()));
316
330
  if (this.#t = a, !this.#e?.get()) {
317
331
  try {
318
332
  a(), this.#t = void 0;
@@ -323,7 +337,8 @@ var O = class {
323
337
  }
324
338
  this.#a(), this.view.get();
325
339
  } catch (e) {
326
- throw n && Promise.resolve().then(n).catch(() => void 0), e;
340
+ let t = n;
341
+ throw t && Promise.resolve().then(() => s(t())).catch(() => void 0), e;
327
342
  } finally {
328
343
  t = !1;
329
344
  }
@@ -360,7 +375,7 @@ var O = class {
360
375
  #o(e) {
361
376
  let t = this.#e;
362
377
  if (!t?.get()) throw Error("Readable bridge has been disposed");
363
- d(e);
378
+ h(e);
364
379
  let n = t.subscribe(() => (this.#e?.get() || n[r](), e()));
365
380
  return n;
366
381
  }
@@ -386,10 +401,10 @@ var O = class {
386
401
  }
387
402
  }
388
403
  };
389
- function j(e, t) {
404
+ function F(e, t) {
390
405
  let n = e?.defer;
391
406
  if (typeof n != "function") throw TypeError("bridge() expects a resource owner");
392
- let i = s(t, "bridge()"), a = { defer: (t) => Reflect.apply(n, e, [t]) }, o = new A(i);
407
+ let i = d(t, "bridge()"), a = { defer: (t) => Reflect.apply(n, e, [t]) }, o = new P(i);
393
408
  try {
394
409
  return o.start(a), o.view;
395
410
  } catch (e) {
@@ -402,15 +417,15 @@ function j(e, t) {
402
417
  }
403
418
  }
404
419
  // src/abort.ts
405
- function M(e) {
420
+ function I(e) {
406
421
  return Reflect.get(AbortSignal.prototype, "aborted", e);
407
422
  }
408
- function N(e) {
423
+ function L(e) {
409
424
  return Reflect.get(AbortSignal.prototype, "reason", e);
410
425
  }
411
- function P(t, n) {
426
+ function R(t, n) {
412
427
  if (typeof n != "function") throw TypeError("Abort listener must be a function");
413
- if (M(t)) return n(N(t)), () => {};
428
+ if (I(t)) return n(L(t)), () => {};
414
429
  let r = {
415
430
  signal: t,
416
431
  callback: n
@@ -419,14 +434,14 @@ function P(t, n) {
419
434
  r = void 0, i?.(), i = void 0;
420
435
  }
421
436
  function o() {
422
- if (!r || !M(r.signal)) return;
423
- let { signal: e, callback: t } = r, n = N(e);
437
+ if (!r || !I(r.signal)) return;
438
+ let { signal: e, callback: t } = r, n = L(e);
424
439
  a(), t(n);
425
440
  }
426
441
  return i = e(t, o), r ? o() : a(), a;
427
442
  }
428
443
  // src/observe.ts
429
- var F = class {
444
+ var z = class {
430
445
  #e;
431
446
  #t;
432
447
  #n;
@@ -438,6 +453,7 @@ var F = class {
438
453
  #c;
439
454
  #l;
440
455
  #u;
456
+ #d;
441
457
  constructor(e, t, n) {
442
458
  this.#e = {
443
459
  phase: "active",
@@ -451,61 +467,75 @@ var F = class {
451
467
  start() {
452
468
  this.#i = !0;
453
469
  try {
454
- this.#d();
470
+ this.#f();
455
471
  } finally {
456
472
  this.#i = !1;
457
473
  }
458
474
  }
459
- #d() {
460
- let { owner: e, source: t } = this.#S();
461
- this.#t = c(t.subscribe(() => this.#p())), this.#g();
462
- let n = e.spawn((e) => this.#m(e)), r = l(n, "ObservationOwner.spawn() must return an ObservationTask");
475
+ #f() {
476
+ let { source: e } = this.#w();
477
+ this.#t = f(e.subscribe(() => this.#h())), this.#v();
478
+ let { owner: t } = this.#w(), n = t.spawn((e) => this.#g(e)), r = p(n, "ObservationOwner.spawn() must return an ObservationTask");
463
479
  this.#s = r;
464
- let i = o(n.result);
480
+ let i = l(n.result);
465
481
  if (!i) throw TypeError("ObservationOwner.spawn() must return an ObservationTask");
466
- i.then(() => this.#b(r), () => this.#b(r));
482
+ i.then(() => this.#S(r), () => this.#S(r));
467
483
  }
468
484
  attachOwnerCleanup(e) {
469
- this.#c = e;
485
+ this.#d || (this.#c = e);
486
+ }
487
+ handle = Object.freeze({ [i]: () => this.#p() });
488
+ #p() {
489
+ if (this.#l) return this.#l;
490
+ let e = this.#c;
491
+ if (!e) return this.dispose();
492
+ let t = Promise.withResolvers();
493
+ this.#l = t.promise;
494
+ try {
495
+ s(e()).then(() => t.resolve(), t.reject);
496
+ } catch (e) {
497
+ t.reject(e);
498
+ }
499
+ return t.promise;
470
500
  }
471
501
  dispose() {
472
- if (this.#u) return this.#u;
502
+ if (this.#d) return this.#d;
473
503
  let e = Promise.withResolvers();
474
- return this.#u = e.promise, this.#c = void 0, this.#C("disposed"), this.#l?.(), (this.#i ? Promise.resolve().then(() => this.#f()) : this.#f()).then(e.resolve, e.reject), e.promise;
504
+ return this.#d = e.promise, this.#c = void 0, this.#T("disposed"), this.#u?.(), (this.#i ? Promise.resolve().then(() => this.#m()) : this.#m()).then(e.resolve, e.reject), e.promise;
475
505
  }
476
- async #f() {
506
+ async #m() {
477
507
  let e = [];
478
508
  try {
479
509
  this.#t?.(), this.#t = void 0;
480
510
  } catch (t) {
481
511
  e.push(t);
482
512
  }
483
- await L(this.#y(), e);
513
+ await V(this.#x(), e);
484
514
  try {
485
- await this.#v();
515
+ await this.#b();
486
516
  } catch (t) {
487
517
  e.push(t);
488
518
  }
489
519
  if (e.length === 1) throw e[0];
490
520
  if (e.length > 1) throw AggregateError(e, "Observation cleanup failed");
491
521
  }
492
- #p() {
493
- this.#e.phase === "active" && (this.#o = !0, this.#l?.());
522
+ #h() {
523
+ this.#e.phase === "active" && (this.#o = !0, this.#u?.());
494
524
  }
495
- async #m(e) {
496
- let t = P(e, () => this.#l?.());
525
+ async #g(e) {
526
+ let t = R(e, () => this.#u?.());
497
527
  try {
498
- for (; this.#e.phase === "active" && !M(e);) {
528
+ for (; this.#e.phase === "active" && !I(e);) {
499
529
  if (!this.#o) {
500
530
  let e = Promise.withResolvers();
501
- this.#l = e.resolve, await e.promise, this.#l = void 0;
531
+ this.#u = e.resolve, await e.promise, this.#u = void 0;
502
532
  }
503
- for (; this.#e.phase === "active" && !M(e) && this.#o;) this.#o = !1, await this.#h(e);
533
+ for (; this.#e.phase === "active" && !I(e) && this.#o;) this.#o = !1, await this.#_(e);
504
534
  }
505
535
  } catch (e) {
506
536
  if (this.#e.phase !== "active") throw e;
507
537
  try {
508
- await this.#x();
538
+ await this.#C();
509
539
  } catch (t) {
510
540
  throw AggregateError([e, t], "Observation stopped after a replacement failed");
511
541
  }
@@ -514,85 +544,83 @@ var F = class {
514
544
  t();
515
545
  }
516
546
  }
517
- async #h(e) {
518
- if (this.#e.phase !== "active" || M(e)) return;
547
+ async #_(e) {
548
+ if (this.#e.phase !== "active" || I(e)) return;
519
549
  let t = this.#e.binding.source.get();
520
550
  if (!(this.#a.present && Object.is(t, this.#a.value))) {
521
551
  try {
522
- await this.#v();
552
+ await this.#b();
523
553
  } catch (e) {
524
- throw this.#e.phase === "active" && await this.#x(), e;
554
+ throw this.#e.phase === "active" && await this.#C(), e;
525
555
  }
526
- this.#a = { present: !1 }, !(this.#e.phase !== "active" || M(e)) && this.#g(e);
556
+ this.#a = { present: !1 }, !(this.#e.phase !== "active" || I(e)) && this.#v(e);
527
557
  }
528
558
  }
529
- #g(e) {
530
- let { owner: t } = this.#S(), n = t.child("observation");
531
- if (this.#n = l(n, "ObservationOwner.child() must return an AsyncDisposable"), e && M(e)) return;
532
- let r = this.#S().source.get();
533
- e && M(e) || (this.#_(r, n), this.#e.phase === "active" && (this.#a = {
559
+ #v(e) {
560
+ let { owner: t } = this.#w(), n = t.child("observation");
561
+ if (this.#n = p(n, "ObservationOwner.child() must return an AsyncDisposable"), e && I(e)) return;
562
+ let r = this.#w().source.get();
563
+ e && I(e) || (this.#y(r, n), this.#e.phase === "active" && (this.#a = {
534
564
  present: !0,
535
565
  value: r
536
566
  }));
537
567
  }
538
- #_(e, t) {
539
- let { observer: n } = this.#S();
540
- a(n(e, t), "Observers must be synchronous; use owner.spawn() for async work");
568
+ #y(e, t) {
569
+ let { observer: n } = this.#w();
570
+ c(n(e, t), "Observers must be synchronous; use owner.spawn() for async work");
541
571
  }
542
- #v() {
572
+ #b() {
543
573
  let e = this.#n;
544
- if (e) return this.#r ??= Promise.resolve().then(e).then(() => {
574
+ if (e) return this.#r ??= Promise.resolve().then(() => s(e())).then(() => {
545
575
  this.#n = void 0, this.#r = void 0;
546
576
  });
547
577
  }
548
- #y() {
578
+ #x() {
549
579
  let e = this.#s;
550
580
  return this.#s = void 0, e;
551
581
  }
552
- #b(e) {
582
+ #S(e) {
553
583
  this.#s === e && (this.#s = void 0);
554
584
  }
555
- async #x() {
556
- this.#C("stopped"), this.#s = void 0;
557
- let e = this.#c;
558
- e ? await e() : await this.dispose();
585
+ async #C() {
586
+ this.#T("stopped"), this.#s = void 0, await this.#p();
559
587
  }
560
- #S() {
588
+ #w() {
561
589
  let e = this.#e;
562
590
  if (e.phase !== "active") throw Error("Observation is not active");
563
591
  return e.binding;
564
592
  }
565
- #C(e) {
593
+ #T(e) {
566
594
  this.#e = { phase: e }, this.#a = { present: !1 }, this.#o = !1;
567
595
  }
568
596
  };
569
- function I(e, t, n) {
570
- let r = s(t, "observe()");
597
+ function B(e, t, n) {
598
+ let r = d(t, "observe()");
571
599
  if (typeof n != "function") throw TypeError("Observer must be a function");
572
- let a = e?.defer, o = e?.child, c = e?.spawn;
573
- if (typeof a != "function" || typeof o != "function" || typeof c != "function") throw TypeError("observe() expects an observation owner");
574
- let u = {
575
- defer: (t) => Reflect.apply(a, e, [t]),
576
- child: (t) => Reflect.apply(o, e, [t]),
577
- spawn: (t) => Reflect.apply(c, e, [t])
578
- }, d = new F(u, r, n), f = l(u.defer(() => d.dispose()), "ObservationOwner.defer() must return an AsyncDisposable");
579
- d.attachOwnerCleanup(f);
600
+ let i = e?.defer, a = e?.child, o = e?.spawn;
601
+ if (typeof i != "function" || typeof a != "function" || typeof o != "function") throw TypeError("observe() expects an observation owner");
602
+ let c = {
603
+ defer: (t) => Reflect.apply(i, e, [t]),
604
+ child: (t) => Reflect.apply(a, e, [t]),
605
+ spawn: (t) => Reflect.apply(o, e, [t])
606
+ }, l = new z(c, r, n), u = p(c.defer(() => l.dispose()), "ObservationOwner.defer() must return an AsyncDisposable");
607
+ l.attachOwnerCleanup(u);
580
608
  try {
581
- return d.start(), Object.freeze({ [i]: f });
609
+ return l.start(), l.handle;
582
610
  } catch (e) {
583
611
  try {
584
- Promise.resolve(f()).catch(() => void 0);
612
+ s(u()).catch(() => void 0);
585
613
  } catch (t) {
586
614
  throw AggregateError([e, t], "Observation construction failed");
587
615
  }
588
616
  throw e;
589
617
  }
590
618
  }
591
- async function L(e, t) {
619
+ async function V(e, t) {
592
620
  if (e) try {
593
- await e();
621
+ await s(e());
594
622
  } catch (e) {
595
623
  t.push(e);
596
624
  }
597
625
  }
598
- export { T as batch, j as bridge, D as computed, I as observe, E as signal };
626
+ export { i as asyncDisposeSymbol, k as batch, F as bridge, j as computed, r as disposeSymbol, B as observe, A as signal };
package/dist/observe.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  import { AsyncDisposable, Readable } from './protocol.js';
2
- export interface ObservationTask<T = void> extends AsyncDisposable {
3
- readonly result: Promise<T>;
2
+ import { SynchronousResult } from './async-result.js';
3
+ export interface ObservationTask extends AsyncDisposable {
4
+ readonly result: PromiseLike<unknown>;
4
5
  }
5
6
  export interface ObservationOwner<Child extends AsyncDisposable = AsyncDisposable> {
6
7
  readonly defer: (dispose: () => unknown) => AsyncDisposable;
7
8
  readonly child: (label: string) => Child;
8
- readonly spawn: <T>(task: (signal: AbortSignal) => T | PromiseLike<T>) => ObservationTask<T>;
9
+ readonly spawn: (task: (signal: AbortSignal) => void | PromiseLike<void>) => ObservationTask;
9
10
  }
10
- export type Observer<T, Child extends AsyncDisposable> = (value: T, lifetime: Child) => void;
11
- export declare function observe<T, Child extends AsyncDisposable>(owner: ObservationOwner<Child>, source: Readable<T>, observer: Observer<T, Child>): AsyncDisposable;
11
+ export type Observer<T, Child extends AsyncDisposable, Result = void> = (value: T, lifetime: Child) => SynchronousResult<Result>;
12
+ export declare function observe<T, Child extends AsyncDisposable, Result = void>(owner: ObservationOwner<Child>, source: Readable<T>, observer: Observer<T, Child, Result>): AsyncDisposable;
12
13
  //# sourceMappingURL=observe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AAKvB,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,IAAI,CAAE,SAAQ,eAAe;IAChE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,eAAe,GAAG,eAAe;IAC/E,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,KAAK,eAAe,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,CAAC,CAAC;CAC9F;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,SAAS,eAAe,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,KAAK,IAAI,CAAC;AAoO7F,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,SAAS,eAAe,EACtD,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,GAC3B,eAAe,CAiCjB"}
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../src/observe.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,eAAe,EACpB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,eAAe,GAAG,eAAe;IAC/E,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,KAAK,eAAe,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,eAAe,CAAC;CAC9F;AAED,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,KAAK,SAAS,eAAe,EAAE,MAAM,GAAG,IAAI,IAAI,CACtE,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,KAAK,KACZ,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAyP/B,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,SAAS,eAAe,EAAE,MAAM,GAAG,IAAI,EACrE,KAAK,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAC9B,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EACnB,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,GACnC,eAAe,CAgCjB"}
@@ -1,3 +1,4 @@
1
+ import { SynchronousResult } from './async-result.js';
1
2
  export { assertPromiseRuntime, resolveDisposalSymbol, asyncDisposeSymbol, disposeSymbol, } from './disposal-runtime.js';
2
3
  export interface Disposable {
3
4
  [Symbol.dispose](): void;
@@ -7,7 +8,7 @@ export interface AsyncDisposable {
7
8
  }
8
9
  export interface Readable<T> {
9
10
  get(): T;
10
- subscribe(listener: () => void): Disposable;
11
+ subscribe<Result>(listener: () => SynchronousResult<Result>): Disposable;
11
12
  }
12
13
  export declare function captureReadable<T>(source: Readable<T>, operation: string): Readable<T>;
13
14
  export declare function captureUnsubscribe(subscription: Disposable): () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,UAAU;IACzB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,CAAC;IACT,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,UAAU,CAAC;CAC7C;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAStF;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,UAAU,GAAG,MAAM,IAAI,CASvE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAI/F;AAQD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,IAAI,CAIhF"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,UAAU;IACzB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,CAAC;IACT,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;CAC1E;AAED,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAStF;AAED,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,UAAU,GAAG,MAAM,IAAI,CASvE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,CAI/F;AAQD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,IAAI,MAAM,IAAI,CAIhF"}
package/dist/signals.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Readable } from './protocol.js';
2
+ import { SynchronousResult } from './async-result.js';
2
3
  declare const dougongSignal: unique symbol;
3
4
  export interface ReadonlySignal<T> extends Readable<T> {
4
5
  readonly [dougongSignal]: true;
@@ -6,8 +7,8 @@ export interface ReadonlySignal<T> extends Readable<T> {
6
7
  export interface Signal<T> extends ReadonlySignal<T> {
7
8
  readonly set: (value: T) => void;
8
9
  }
9
- export declare function batch<T>(callback: () => T): T;
10
+ export declare function batch<T>(callback: () => SynchronousResult<T>): T;
10
11
  export declare function signal<T>(initialValue: T): Signal<T>;
11
- export declare function computed<T>(calculate: () => T): ReadonlySignal<T>;
12
+ export declare function computed<T>(calculate: () => SynchronousResult<T>): ReadonlySignal<T>;
12
13
  export {};
13
14
  //# sourceMappingURL=signals.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAG9F,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAE3C,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,MAAM,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAClC;AAgHD,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAgC7C;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAEpD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAGjE"}
1
+ {"version":3,"file":"signals.d.ts","sourceRoot":"","sources":["../src/signals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9F,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,CAAC,MAAM,aAAa,EAAE,OAAO,MAAM,CAAC;AAE3C,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,MAAM,CAAC,CAAC,CAAE,SAAQ,cAAc,CAAC,CAAC,CAAC;IAClD,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;CAClC;AAgHD,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAC,CAgChE;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAEpD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,CAGpF"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@dougongjs/reactive",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "engines": {
6
- "node": ">=22"
6
+ "node": "^24.22.0 || >=26.10.0"
7
7
  },
8
8
  "browserslist": [
9
9
  "Chrome >= 119",
@@ -27,8 +27,7 @@
27
27
  "imports": {
28
28
  "#abort-listener": {
29
29
  "types": "./runtime/abort-listener.d.mts",
30
- "node": "./runtime/abort-listener.node.mjs",
31
- "default": "./runtime/abort-listener.web.mjs"
30
+ "default": "./runtime/abort-listener.mjs"
32
31
  }
33
32
  },
34
33
  "description": "Zero-dependency signal, computed, batch and observe primitives.",
@@ -0,0 +1,27 @@
1
+ // Generated from tooling/internal/abort-listener.mjs. Run pnpm generate:internal.
2
+ // A separate closure prevents the dependent from retaining the source through its registration.
3
+ function weakAbortListener(reference) {
4
+ return () => reference.deref()?.();
5
+ }
6
+
7
+ export function listenForAbort(signal, notify) {
8
+ const dependent = AbortSignal.any([signal]);
9
+ const listener = weakAbortListener(new WeakRef(notify));
10
+ let registration = { signal, notify, dependent, listener };
11
+ function detach() {
12
+ if (!registration) return;
13
+ const attached = registration;
14
+ registration = undefined;
15
+ EventTarget.prototype.removeEventListener.call(attached.signal, "abort", attached.notify);
16
+ attached.dependent.removeEventListener("abort", attached.listener);
17
+ }
18
+ try {
19
+ // Source listeners preserve native composite lifetimes; the private dependent bypasses stopped events.
20
+ EventTarget.prototype.addEventListener.call(signal, "abort", notify);
21
+ dependent.addEventListener("abort", listener);
22
+ } catch (error) {
23
+ detach();
24
+ throw error;
25
+ }
26
+ return detach;
27
+ }
@@ -1,3 +0,0 @@
1
- export declare function assertSynchronous(value: unknown, message: string): void;
2
- export declare function captureThenable(value: unknown): Promise<unknown> | undefined;
3
- //# sourceMappingURL=synchronous-result.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"synchronous-result.d.ts","sourceRoot":"","sources":["../src/synchronous-result.ts"],"names":[],"mappings":"AACA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAUvE;AAGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,CAa5E"}
@@ -1,26 +0,0 @@
1
- // Generated from tooling/internal/abort-listener.node.mjs. Run pnpm generate:internal.
2
- import { addAbortListener } from "node:events";
3
-
4
- export function listenForAbort(signal, notify) {
5
- // Node supplies stop-resistant listener options to this private registration signal.
6
- // The caller's genuine EventTarget owns the actual listener and its native GC bookkeeping.
7
- const registration = new AbortController().signal;
8
- let detach;
9
- registration.addEventListener = (type, listener, options) => {
10
- detach = () => EventTarget.prototype.removeEventListener.call(signal, type, listener);
11
- try {
12
- // Only native cancellation may consume the listener. Synthetic abort events can arrive first.
13
- EventTarget.prototype.addEventListener.call(signal, type, listener, {
14
- ...options,
15
- once: false,
16
- });
17
- } catch (error) {
18
- // A native listener hook may throw before or after insertion.
19
- detach();
20
- throw error;
21
- }
22
- };
23
- addAbortListener(registration, notify);
24
- if (!detach) throw new Error("Node did not attach the protected abort listener");
25
- return detach;
26
- }
@@ -1,7 +0,0 @@
1
- // Generated from tooling/internal/abort-listener.web.mjs. Run pnpm generate:internal.
2
- // Only the controller can abort this private dependent; other listeners can stop propagation on the source.
3
- export function listenForAbort(signal, notify) {
4
- const dependent = AbortSignal.any([signal]);
5
- dependent.addEventListener("abort", notify);
6
- return () => dependent.removeEventListener("abort", notify);
7
- }