@dougongjs/reactive 0.8.3 → 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/dist/observe.d.ts CHANGED
@@ -1,12 +1,13 @@
1
- import { AsyncDisposable, Readable } from './protocol';
2
- export interface ObservationTask<T = void> extends AsyncDisposable {
3
- readonly result: Promise<T>;
1
+ import { AsyncDisposable, Readable } from './protocol.js';
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
- readonly cleanup: (dispose: () => unknown) => AsyncDisposable;
7
- readonly lifetime: (label: string) => Child;
8
- readonly spawn: <T>(task: (signal: AbortSignal) => T | PromiseLike<T>) => ObservationTask<T>;
7
+ readonly defer: (dispose: () => unknown) => AsyncDisposable;
8
+ readonly child: (label: string) => Child;
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":"AAAA,OAAO,EAGL,KAAK,eAAe,EAEpB,KAAK,QAAQ,EACd,MAAM,YAAY,CAAC;AAKpB,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,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,OAAO,KAAK,eAAe,CAAC;IAC9D,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IAC5C,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;AAgN7F,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,CAyBjB"}
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,14 +1,17 @@
1
- export { assertPromiseRuntime, resolveDisposalSymbol, asyncDisposeSymbol, disposeSymbol, } from './disposal-runtime';
1
+ import { SynchronousResult } from './async-result.js';
2
+ export { assertPromiseRuntime, resolveDisposalSymbol, asyncDisposeSymbol, disposeSymbol, } from './disposal-runtime.js';
2
3
  export interface Disposable {
3
- dispose(): void;
4
4
  [Symbol.dispose](): void;
5
5
  }
6
6
  export interface AsyncDisposable {
7
- dispose(): Promise<void>;
8
- [Symbol.asyncDispose](): Promise<void>;
7
+ [Symbol.asyncDispose](): PromiseLike<void>;
9
8
  }
10
9
  export interface Readable<T> {
11
10
  get(): T;
12
- subscribe(listener: () => void): Disposable;
11
+ subscribe<Result>(listener: () => SynchronousResult<Result>): Disposable;
13
12
  }
13
+ export declare function captureReadable<T>(source: Readable<T>, operation: string): Readable<T>;
14
+ export declare function captureUnsubscribe(subscription: Disposable): () => void;
15
+ export declare function captureRelease(value: AsyncDisposable, message: string): () => PromiseLike<void>;
16
+ export declare function assertListener(listener: unknown): asserts listener is () => void;
14
17
  //# sourceMappingURL=protocol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,GAAG,IAAI,CAAC,CAAC;IACT,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,UAAU,CAAC;CAC7C"}
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
- import { Readable } from './protocol';
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,EAAkC,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3E,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;AA0GD,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CA4B7C;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,19 +1,20 @@
1
1
  {
2
2
  "name": "@dougongjs/reactive",
3
- "version": "0.8.3",
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",
10
10
  "Edge >= 119",
11
- "Firefox >= 121",
11
+ "Firefox >= 124",
12
12
  "Safari >= 17.4"
13
13
  ],
14
14
  "sideEffects": false,
15
15
  "files": [
16
16
  "dist",
17
+ "runtime",
17
18
  "README.md",
18
19
  "LICENSE"
19
20
  ],
@@ -23,6 +24,12 @@
23
24
  "import": "./dist/index.js"
24
25
  }
25
26
  },
27
+ "imports": {
28
+ "#abort-listener": {
29
+ "types": "./runtime/abort-listener.d.mts",
30
+ "default": "./runtime/abort-listener.mjs"
31
+ }
32
+ },
26
33
  "description": "Zero-dependency signal, computed, batch and observe primitives.",
27
34
  "license": "MIT",
28
35
  "author": "Dougong contributors",
@@ -47,6 +54,6 @@
47
54
  "access": "public"
48
55
  },
49
56
  "scripts": {
50
- "build": "node ../../scripts/generate-internal.mjs && vite build"
57
+ "build": "node ../../tooling/generate-internal.mjs && vite build"
51
58
  }
52
59
  }
@@ -0,0 +1,2 @@
1
+ // Generated from tooling/internal/abort-listener.d.mts. Run pnpm generate:internal.
2
+ export function listenForAbort(signal: AbortSignal, notify: () => void): () => void;
@@ -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=sync-result.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync-result.d.ts","sourceRoot":"","sources":["../src/sync-result.ts"],"names":[],"mappings":"AACA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAOvE;AAGD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,CAO5E"}