@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 +9 -3
- package/dist/async-result.d.ts +10 -0
- package/dist/async-result.d.ts.map +1 -0
- package/dist/bridge.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +174 -146
- package/dist/observe.d.ts +6 -5
- package/dist/observe.d.ts.map +1 -1
- package/dist/protocol.d.ts +2 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/signals.d.ts +3 -2
- package/dist/signals.d.ts.map +1 -1
- package/package.json +3 -4
- package/runtime/abort-listener.mjs +27 -0
- package/dist/synchronous-result.d.ts +0 -3
- package/dist/synchronous-result.d.ts.map +0 -1
- package/runtime/abort-listener.node.mjs +0 -26
- package/runtime/abort-listener.web.mjs +0 -7
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[
|
|
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
|
-
|
|
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"}
|
package/dist/bridge.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
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
|
|
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
|
|
53
|
+
function f(e) {
|
|
39
54
|
let t = e?.[r];
|
|
40
|
-
return typeof t != "function" &&
|
|
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
|
|
57
|
+
function p(e, t) {
|
|
43
58
|
let n = e?.[i];
|
|
44
|
-
return typeof n != "function" &&
|
|
59
|
+
return typeof n != "function" && m(e, t), () => Reflect.apply(n, e, []);
|
|
45
60
|
}
|
|
46
|
-
function
|
|
47
|
-
throw
|
|
61
|
+
function m(e, t) {
|
|
62
|
+
throw c(e, t), TypeError(t);
|
|
48
63
|
}
|
|
49
|
-
function
|
|
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
|
|
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
|
|
64
|
-
if (
|
|
78
|
+
function T() {
|
|
79
|
+
if (v) return;
|
|
65
80
|
let e = [];
|
|
66
|
-
|
|
81
|
+
v = !0;
|
|
67
82
|
try {
|
|
68
|
-
for (;
|
|
69
|
-
let t =
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
94
|
+
b.clear(), v = !1;
|
|
80
95
|
}
|
|
81
|
-
|
|
96
|
+
O(e);
|
|
82
97
|
}
|
|
83
|
-
function
|
|
84
|
-
for (let t of e) (t.kind === "dependency" ?
|
|
85
|
-
if (!
|
|
86
|
-
|
|
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 (;
|
|
89
|
-
let e =
|
|
90
|
-
|
|
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
|
-
|
|
110
|
+
y = !1, x.clear();
|
|
96
111
|
}
|
|
97
|
-
|
|
112
|
+
_ || T();
|
|
98
113
|
}
|
|
99
114
|
}
|
|
100
|
-
function
|
|
101
|
-
|
|
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
|
|
121
|
+
return e.add(r), new w(() => {
|
|
107
122
|
r.listener = void 0, e.delete(r);
|
|
108
123
|
});
|
|
109
124
|
}
|
|
110
|
-
function
|
|
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
|
|
129
|
+
function k(e) {
|
|
115
130
|
if (typeof e != "function") throw TypeError("batch() expects a function");
|
|
116
|
-
|
|
131
|
+
_++;
|
|
117
132
|
let t;
|
|
118
133
|
try {
|
|
119
134
|
let n = e();
|
|
120
|
-
|
|
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
|
-
|
|
145
|
+
_--;
|
|
131
146
|
}
|
|
132
|
-
if (!
|
|
133
|
-
|
|
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
|
|
147
|
-
return new
|
|
161
|
+
function A(e) {
|
|
162
|
+
return new M(e).view;
|
|
148
163
|
}
|
|
149
|
-
function
|
|
164
|
+
function j(e) {
|
|
150
165
|
if (typeof e != "function") throw TypeError("computed() expects a function");
|
|
151
|
-
return new
|
|
166
|
+
return new N(e).view;
|
|
152
167
|
}
|
|
153
|
-
var
|
|
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: () => (
|
|
175
|
+
get: () => (S?.add(this), this.#t),
|
|
161
176
|
set: (e) => this.#r(e),
|
|
162
|
-
subscribe: (e) =>
|
|
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
|
|
185
|
+
return D(this.#e, e, "dependency");
|
|
171
186
|
}
|
|
172
187
|
#r(e) {
|
|
173
|
-
if (
|
|
174
|
-
Object.is(this.#t, e) || (this.#t = 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
|
-
},
|
|
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 =
|
|
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
|
|
198
|
-
this.#a =
|
|
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
|
-
|
|
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
|
|
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(),
|
|
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
|
-
|
|
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
|
|
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
|
|
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 &&
|
|
249
|
-
this.#i =
|
|
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 =
|
|
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 =
|
|
262
|
-
this.#o = e,
|
|
275
|
+
let t = S;
|
|
276
|
+
this.#o = e, S = e;
|
|
263
277
|
try {
|
|
264
278
|
let e = this.#e, t = e();
|
|
265
|
-
return
|
|
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
|
-
|
|
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
|
-
},
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
420
|
+
function I(e) {
|
|
406
421
|
return Reflect.get(AbortSignal.prototype, "aborted", e);
|
|
407
422
|
}
|
|
408
|
-
function
|
|
423
|
+
function L(e) {
|
|
409
424
|
return Reflect.get(AbortSignal.prototype, "reason", e);
|
|
410
425
|
}
|
|
411
|
-
function
|
|
426
|
+
function R(t, n) {
|
|
412
427
|
if (typeof n != "function") throw TypeError("Abort listener must be a function");
|
|
413
|
-
if (
|
|
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 || !
|
|
423
|
-
let { signal: e, callback: t } = r, n =
|
|
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
|
|
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.#
|
|
470
|
+
this.#f();
|
|
455
471
|
} finally {
|
|
456
472
|
this.#i = !1;
|
|
457
473
|
}
|
|
458
474
|
}
|
|
459
|
-
#
|
|
460
|
-
let {
|
|
461
|
-
this.#t =
|
|
462
|
-
let n =
|
|
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 =
|
|
480
|
+
let i = l(n.result);
|
|
465
481
|
if (!i) throw TypeError("ObservationOwner.spawn() must return an ObservationTask");
|
|
466
|
-
i.then(() => this.#
|
|
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.#
|
|
502
|
+
if (this.#d) return this.#d;
|
|
473
503
|
let e = Promise.withResolvers();
|
|
474
|
-
return this.#
|
|
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 #
|
|
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
|
|
513
|
+
await V(this.#x(), e);
|
|
484
514
|
try {
|
|
485
|
-
await this.#
|
|
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
|
-
#
|
|
493
|
-
this.#e.phase === "active" && (this.#o = !0, this.#
|
|
522
|
+
#h() {
|
|
523
|
+
this.#e.phase === "active" && (this.#o = !0, this.#u?.());
|
|
494
524
|
}
|
|
495
|
-
async #
|
|
496
|
-
let t =
|
|
525
|
+
async #g(e) {
|
|
526
|
+
let t = R(e, () => this.#u?.());
|
|
497
527
|
try {
|
|
498
|
-
for (; this.#e.phase === "active" && !
|
|
528
|
+
for (; this.#e.phase === "active" && !I(e);) {
|
|
499
529
|
if (!this.#o) {
|
|
500
530
|
let e = Promise.withResolvers();
|
|
501
|
-
this.#
|
|
531
|
+
this.#u = e.resolve, await e.promise, this.#u = void 0;
|
|
502
532
|
}
|
|
503
|
-
for (; this.#e.phase === "active" && !
|
|
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.#
|
|
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 #
|
|
518
|
-
if (this.#e.phase !== "active" ||
|
|
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.#
|
|
552
|
+
await this.#b();
|
|
523
553
|
} catch (e) {
|
|
524
|
-
throw this.#e.phase === "active" && await this.#
|
|
554
|
+
throw this.#e.phase === "active" && await this.#C(), e;
|
|
525
555
|
}
|
|
526
|
-
this.#a = { present: !1 }, !(this.#e.phase !== "active" ||
|
|
556
|
+
this.#a = { present: !1 }, !(this.#e.phase !== "active" || I(e)) && this.#v(e);
|
|
527
557
|
}
|
|
528
558
|
}
|
|
529
|
-
#
|
|
530
|
-
let { owner: t } = this.#
|
|
531
|
-
if (this.#n =
|
|
532
|
-
let r = this.#
|
|
533
|
-
e &&
|
|
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
|
-
#
|
|
539
|
-
let { observer: n } = this.#
|
|
540
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
578
|
+
#x() {
|
|
549
579
|
let e = this.#s;
|
|
550
580
|
return this.#s = void 0, e;
|
|
551
581
|
}
|
|
552
|
-
#
|
|
582
|
+
#S(e) {
|
|
553
583
|
this.#s === e && (this.#s = void 0);
|
|
554
584
|
}
|
|
555
|
-
async #
|
|
556
|
-
this.#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
593
|
+
#T(e) {
|
|
566
594
|
this.#e = { phase: e }, this.#a = { present: !1 }, this.#o = !1;
|
|
567
595
|
}
|
|
568
596
|
};
|
|
569
|
-
function
|
|
570
|
-
let r =
|
|
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
|
|
573
|
-
if (typeof
|
|
574
|
-
let
|
|
575
|
-
defer: (t) => Reflect.apply(
|
|
576
|
-
child: (t) => Reflect.apply(
|
|
577
|
-
spawn: (t) => Reflect.apply(
|
|
578
|
-
},
|
|
579
|
-
|
|
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
|
|
609
|
+
return l.start(), l.handle;
|
|
582
610
|
} catch (e) {
|
|
583
611
|
try {
|
|
584
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
3
|
-
|
|
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:
|
|
9
|
+
readonly spawn: (task: (signal: AbortSignal) => void | PromiseLike<void>) => ObservationTask;
|
|
9
10
|
}
|
|
10
|
-
export type Observer<T, Child extends AsyncDisposable> = (value: T, lifetime: Child) =>
|
|
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
|
package/dist/observe.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/protocol.d.ts
CHANGED
|
@@ -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: () =>
|
|
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;
|
package/dist/protocol.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"
|
|
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
|
package/dist/signals.d.ts.map
CHANGED
|
@@ -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;
|
|
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.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
|
-
"node": ">=
|
|
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
|
-
"
|
|
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 +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
|
-
}
|