@nisli/core 0.54.1 → 0.55.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.
Files changed (47) hide show
  1. package/README.md +93 -3
  2. package/dist/component.js +146 -5
  3. package/dist/component.js.map +1 -1
  4. package/dist/diagnostics.d.ts +48 -0
  5. package/dist/diagnostics.js +118 -0
  6. package/dist/diagnostics.js.map +1 -0
  7. package/dist/disposable.d.ts +14 -0
  8. package/dist/disposable.js +8 -0
  9. package/dist/disposable.js.map +1 -0
  10. package/dist/emitter.d.ts +2 -1
  11. package/dist/emitter.js +2 -1
  12. package/dist/emitter.js.map +1 -1
  13. package/dist/hmr/registry.js +8 -1
  14. package/dist/hmr/registry.js.map +1 -1
  15. package/dist/index.d.ts +5 -3
  16. package/dist/index.js +6 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/injector.d.ts +9 -2
  19. package/dist/injector.js +18 -0
  20. package/dist/injector.js.map +1 -1
  21. package/dist/lifecycle.d.ts +9 -0
  22. package/dist/lifecycle.js +17 -7
  23. package/dist/lifecycle.js.map +1 -1
  24. package/dist/projection.js +24 -5
  25. package/dist/projection.js.map +1 -1
  26. package/dist/query.d.ts +134 -55
  27. package/dist/query.js +379 -188
  28. package/dist/query.js.map +1 -1
  29. package/dist/resource.d.ts +2 -1
  30. package/dist/resource.js +21 -4
  31. package/dist/resource.js.map +1 -1
  32. package/dist/settle.d.ts +61 -0
  33. package/dist/settle.js +106 -0
  34. package/dist/settle.js.map +1 -0
  35. package/dist/signal.d.ts +42 -7
  36. package/dist/signal.js +248 -68
  37. package/dist/signal.js.map +1 -1
  38. package/dist/template-audit.d.ts +64 -0
  39. package/dist/template-audit.js +246 -0
  40. package/dist/template-audit.js.map +1 -0
  41. package/dist/template.d.ts +70 -1
  42. package/dist/template.js +322 -65
  43. package/dist/template.js.map +1 -1
  44. package/dist/view-transition.d.ts +70 -0
  45. package/dist/view-transition.js +98 -0
  46. package/dist/view-transition.js.map +1 -0
  47. package/package.json +1 -1
package/dist/emitter.d.ts CHANGED
@@ -18,6 +18,7 @@
18
18
  * ```
19
19
  */
20
20
  import { type Signal } from './signal.js';
21
+ import { type Disposer } from './disposable.js';
21
22
  type EventMap = Record<string, unknown>;
22
23
  type Listener<T> = (payload: T) => void;
23
24
  export declare class Emitter<Events extends EventMap> {
@@ -33,7 +34,7 @@ export declare class Emitter<Events extends EventMap> {
33
34
  * If called during component setup, the subscription is automatically
34
35
  * disposed on disconnectedCallback.
35
36
  */
36
- on<K extends keyof Events>(event: K, fn: Listener<Events[K]>): () => void;
37
+ on<K extends keyof Events>(event: K, fn: Listener<Events[K]>): Disposer;
37
38
  /**
38
39
  * Bridge an event into the signal system.
39
40
  * Returns a signal that updates whenever the event fires.
package/dist/emitter.js CHANGED
@@ -19,6 +19,7 @@
19
19
  */
20
20
  import { signal } from './signal.js';
21
21
  import { hasContext, getCurrentComponent } from './context.js';
22
+ import { disposable } from './disposable.js';
22
23
  // ── Emitter base class ──────────────────────────────────────────────
23
24
  export class Emitter {
24
25
  listeners = new Map();
@@ -63,7 +64,7 @@ export class Emitter {
63
64
  if (hasContext()) {
64
65
  getCurrentComponent().addDisposer(unsubscribe);
65
66
  }
66
- return unsubscribe;
67
+ return disposable(unsubscribe, unsubscribe);
67
68
  }
68
69
  /**
69
70
  * Bridge an event into the signal system.
@@ -1 +1 @@
1
- {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAe,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAO/D,uEAAuE;AAEvE,MAAM,OAAO,OAAO;IACV,SAAS,GAAG,IAAI,GAAG,EAAoC,CAAC;IAEhE;;;OAGG;IACH,IAAI,CAAyB,KAAQ,EAAE,OAAkB;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,sDAAsD;QACtD,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,EAAE,CAAC,OAAO,CAAC,CAAC;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAyB,KAAQ,EAAE,EAAuB;QAC1D,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEZ,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,GAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChB,IAAI,GAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC,CAAC;QAEF,iDAAiD;QACjD,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,mBAAmB,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;;;;;;OAOG;IACH,QAAQ,CACN,KAAQ,EACR,QAAmC,EACnC,OAAU;QAEV,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE;YACzB,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,CAAC;IACX,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
1
+ {"version":3,"file":"emitter.js","sourceRoot":"","sources":["../src/emitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,MAAM,EAAe,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAO5D,uEAAuE;AAEvE,MAAM,OAAO,OAAO;IACV,SAAS,GAAG,IAAI,GAAG,EAAoC,CAAC;IAEhE;;;OAGG;IACH,IAAI,CAAyB,KAAQ,EAAE,OAAkB;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,sDAAsD;QACtD,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACH,EAAE,CAAC,OAAO,CAAC,CAAC;YACd,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAyB,KAAQ,EAAE,EAAuB;QAC1D,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEZ,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,GAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChB,IAAI,GAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC,CAAC;QAEF,iDAAiD;QACjD,IAAI,UAAU,EAAE,EAAE,CAAC;YACjB,mBAAmB,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,UAAU,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC9C,CAAC;IAED;;;;;;;OAOG;IACH,QAAQ,CACN,KAAQ,EACR,QAAmC,EACnC,OAAU;QAEV,MAAM,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE;YACzB,CAAC,CAAC,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,CAAC;IACX,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACzB,CAAC;CACF"}
@@ -57,12 +57,19 @@ export function __register(tag, setup) {
57
57
  if (!suppressAutoDrain)
58
58
  scheduleRemount();
59
59
  }
60
- return (props, host) => {
60
+ const thunk = (props, host) => {
61
61
  const current = registry.get(tag);
62
62
  if (!current)
63
63
  throw new Error(`[nisli-hmr] no setup registered for <${tag}>`);
64
64
  return current(props, host);
65
65
  };
66
+ // N201 exemption marker (ADR 0030.2 §3/§8): component() throws a coded dev
67
+ // error on duplicate `define`, EXCEPT when the incoming setup is a registry
68
+ // thunk — an HMR re-evaluation of the same module re-calling component() is
69
+ // the swap mechanism working, not a second definer. The marker rides the
70
+ // thunk itself so component.ts needs no import from this dev-only module.
71
+ thunk.__nisliHmr = true;
72
+ return thunk;
66
73
  }
67
74
  /** Number of tags awaiting a re-mount (for orchestration/tests). */
68
75
  export function pendingRemountCount() {
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/hmr/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/hmr/registry.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -13,15 +13,17 @@
13
13
  * } from './framework';
14
14
  * ```
15
15
  */
16
- export { signal, computed, effect, flush, tick, isSignal, flushEffects, untrack, SIGNAL_BRAND, type Signal, type ReadonlySignal, } from './signal.js';
16
+ export { signal, computed, effect, flush, tick, isSignal, flushEffects, untrack, SIGNAL_BRAND, type Signal, type ReadonlySignal, type Disposer, } from './signal.js';
17
17
  export { runWithContext, getCurrentComponent, hasContext, type ComponentHost, } from './context.js';
18
18
  export { Emitter } from './emitter.js';
19
19
  export { inject, provide, createToken, resetInjector, type Constructor, type InjectionToken, } from './injector.js';
20
20
  export { createContext, type Context, type Inject, } from './element-context.js';
21
21
  export { component, type ReactiveProps, type AttrValueType, type SetupFunction, type ComponentFactory, type ComponentOptions, type AttrDecl, type ComponentAttrs, type PropInput, type HostAttrs, } from './component.js';
22
- export { html, el, when, each, type TemplateResult, type TypedEventHandler, type ElProps, type ElChild, } from './template.js';
22
+ export { html, el, when, each, raw, sanitized, setSanitizerFallback, type RawHtml, type SanitizedHtml, type SanitizerFallback, type TemplateResult, type TypedEventHandler, type ElProps, type ElChild, } from './template.js';
23
23
  export { ref, isRef, type Ref, } from './ref.js';
24
24
  export { onMount, onCleanup, useHostEvent, } from './lifecycle.js';
25
25
  export { children, } from './projection.js';
26
- export { query, QueryClient, type QueryResult, type QueryOptions, } from './query.js';
26
+ export { query, QueryClient, type QueryResult, type QueryOptions, type QueryKey, type QueryKeyElement, type QueryStatus, type QueryFetcher, } from './query.js';
27
27
  export { resource, type ResourceResult, } from './resource.js';
28
+ export { settle } from './settle.js';
29
+ export { viewTransition, type ViewTransitionOptions, } from './view-transition.js';
package/dist/index.js CHANGED
@@ -26,15 +26,19 @@ export { createContext, } from './element-context.js';
26
26
  // ── Component model ─────────────────────────────────────────────────
27
27
  export { component, } from './component.js';
28
28
  // ── Template engine ─────────────────────────────────────────────────
29
- export { html, el, when, each, } from './template.js';
29
+ export { html, el, when, each, raw, sanitized, setSanitizerFallback, } from './template.js';
30
30
  // ── Element refs ────────────────────────────────────────────────────
31
31
  export { ref, isRef, } from './ref.js';
32
32
  // ── Lifecycle hooks ─────────────────────────────────────────────────
33
33
  export { onMount, onCleanup, useHostEvent, } from './lifecycle.js';
34
34
  // ── Content projection (ADR 0025 item 1) ────────────────
35
35
  export { children, } from './projection.js';
36
- // ── Declarative data loading ────────────────────────────────────────
36
+ // ── Declarative data loading (keyed logical-request store) ──────────
37
37
  export { query, QueryClient, } from './query.js';
38
38
  // ── Local async derivations ─────────────────────────────────────────
39
39
  export { resource, } from './resource.js';
40
+ // ── Async quiescence (test/verify + SSG pre-snapshot barrier) ───────
41
+ export { settle } from './settle.js';
42
+ // ── View Transitions (opt-in wrapper over the synchronous flush) ────
43
+ export { viewTransition, } from './view-transition.js';
40
44
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,uEAAuE;AACvE,OAAO,EACL,MAAM,EACN,QAAQ,EACR,MAAM,EACN,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,YAAY,GAGb,MAAM,aAAa,CAAC;AAErB,uEAAuE;AACvE,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,UAAU,GAEX,MAAM,cAAc,CAAC;AAEtB,uEAAuE;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,uEAAuE;AACvE,OAAO,EACL,MAAM,EACN,OAAO,EACP,WAAW,EACX,aAAa,GAGd,MAAM,eAAe,CAAC;AAEvB,uEAAuE;AACvE,OAAO,EACL,aAAa,GAGd,MAAM,sBAAsB,CAAC;AAE9B,uEAAuE;AACvE,OAAO,EACL,SAAS,GAUV,MAAM,gBAAgB,CAAC;AAExB,uEAAuE;AACvE,OAAO,EACL,IAAI,EACJ,EAAE,EACF,IAAI,EACJ,IAAI,GAKL,MAAM,eAAe,CAAC;AAEvB,uEAAuE;AACvE,OAAO,EACL,GAAG,EACH,KAAK,GAEN,MAAM,UAAU,CAAC;AAElB,uEAAuE;AACvE,OAAO,EACL,OAAO,EACP,SAAS,EACT,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,2DAA2D;AAC3D,OAAO,EACL,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAEzB,uEAAuE;AACvE,OAAO,EACL,KAAK,EACL,WAAW,GAGZ,MAAM,YAAY,CAAC;AAEpB,uEAAuE;AACvE,OAAO,EACL,QAAQ,GAET,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,uEAAuE;AACvE,OAAO,EACL,MAAM,EACN,QAAQ,EACR,MAAM,EACN,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,OAAO,EACP,YAAY,GAIb,MAAM,aAAa,CAAC;AAErB,uEAAuE;AACvE,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,UAAU,GAEX,MAAM,cAAc,CAAC;AAEtB,uEAAuE;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,uEAAuE;AACvE,OAAO,EACL,MAAM,EACN,OAAO,EACP,WAAW,EACX,aAAa,GAGd,MAAM,eAAe,CAAC;AAEvB,uEAAuE;AACvE,OAAO,EACL,aAAa,GAGd,MAAM,sBAAsB,CAAC;AAE9B,uEAAuE;AACvE,OAAO,EACL,SAAS,GAUV,MAAM,gBAAgB,CAAC;AAExB,uEAAuE;AACvE,OAAO,EACL,IAAI,EACJ,EAAE,EACF,IAAI,EACJ,IAAI,EACJ,GAAG,EACH,SAAS,EACT,oBAAoB,GAQrB,MAAM,eAAe,CAAC;AAEvB,uEAAuE;AACvE,OAAO,EACL,GAAG,EACH,KAAK,GAEN,MAAM,UAAU,CAAC;AAElB,uEAAuE;AACvE,OAAO,EACL,OAAO,EACP,SAAS,EACT,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,2DAA2D;AAC3D,OAAO,EACL,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAEzB,uEAAuE;AACvE,OAAO,EACL,KAAK,EACL,WAAW,GAOZ,MAAM,YAAY,CAAC;AAEpB,uEAAuE;AACvE,OAAO,EACL,QAAQ,GAET,MAAM,eAAe,CAAC;AAEvB,uEAAuE;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,uEAAuE;AACvE,OAAO,EACL,cAAc,GAEf,MAAM,sBAAsB,CAAC"}
@@ -42,8 +42,13 @@ export declare function inject<T>(token: InjectionToken<T>): T;
42
42
  * Register a factory override for a class or token.
43
43
  * The factory will be called on the next inject() if no cached instance exists.
44
44
  *
45
- * Call provide() before the first inject() of that token.
46
- * To override in tests, call resetInjector() first.
45
+ * Call provide() before the first inject() of that token. Once a token has
46
+ * been instantiated the injector is FROZEN for it (dev, coded error N501):
47
+ * everything that already injected holds the old instance while later
48
+ * inject() calls would get the new one — a silent mixed-instance split
49
+ * (ADR 0030.2 §3). `resetInjector()` is the escape hatch (tests use it).
50
+ * Production keeps the historical silent replace so a live page never breaks
51
+ * over an ordering issue that dev already surfaced.
47
52
  */
48
53
  export declare function provide<T>(token: Constructor<T>, factory: () => T): void;
49
54
  export declare function provide<T>(token: InjectionToken<T>, factory: () => T): void;
@@ -58,6 +63,8 @@ export declare function provide<T>(token: InjectionToken<T>, factory: () => T):
58
63
  * ```
59
64
  */
60
65
  export declare function createToken<T>(name: string, defaultFactory?: () => T): InjectionToken<T>;
66
+ /** @internal Register a hook run by every resetInjector() call. */
67
+ export declare function registerResetHook(hook: () => void): void;
61
68
  /**
62
69
  * Reset the injector — clears all singletons and factory overrides.
63
70
  * Used in tests to ensure isolation between test cases.
package/dist/injector.js CHANGED
@@ -18,6 +18,7 @@
18
18
  * ```
19
19
  */
20
20
  import { hasContext, getCurrentComponent } from './context.js';
21
+ import { formatDiag, isDev } from './diagnostics.js';
21
22
  // ── Global singleton registry ───────────────────────────────────────
22
23
  /** Stores singleton instances keyed by constructor or token. */
23
24
  const singletonCache = new Map();
@@ -67,6 +68,13 @@ export function inject(token) {
67
68
  }
68
69
  }
69
70
  export function provide(token, factory) {
71
+ if (isDev() && singletonCache.has(token)) {
72
+ const name = typeof token === 'function' ? token.name : token.name;
73
+ throw new Error(formatDiag('N501', `provide(${name}) after '${name}' was already instantiated — existing `
74
+ + `consumers keep the old instance while new inject() calls would get the `
75
+ + `new one (mixed-instance split). Call resetInjector() first (tests), or `
76
+ + `provide() before the first inject().`));
77
+ }
70
78
  factoryOverrides.set(token, factory);
71
79
  // Remove cached instance so next inject() uses the new factory
72
80
  singletonCache.delete(token);
@@ -88,6 +96,14 @@ export function createToken(name, defaultFactory) {
88
96
  _factory: defaultFactory,
89
97
  };
90
98
  }
99
+ // Hooks run by resetInjector() — module-level caches elsewhere (settle's
100
+ // pending registry) stay test-isolated without upside-down imports: those
101
+ // modules import the injector and self-register, never the reverse.
102
+ const resetHooks = new Set();
103
+ /** @internal Register a hook run by every resetInjector() call. */
104
+ export function registerResetHook(hook) {
105
+ resetHooks.add(hook);
106
+ }
91
107
  /**
92
108
  * Reset the injector — clears all singletons and factory overrides.
93
109
  * Used in tests to ensure isolation between test cases.
@@ -96,5 +112,7 @@ export function resetInjector() {
96
112
  singletonCache.clear();
97
113
  factoryOverrides.clear();
98
114
  instantiating.clear();
115
+ for (const hook of resetHooks)
116
+ hook();
99
117
  }
100
118
  //# sourceMappingURL=injector.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"injector.js","sourceRoot":"","sources":["../src/injector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAe/D,uEAAuE;AAEvE,gEAAgE;AAChE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkD,CAAC;AAEjF,+CAA+C;AAC/C,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAwD,CAAC;AAEzF,uFAAuF;AACvF,MAAM,aAAa,GAAG,IAAI,GAAG,EAAyC,CAAC;AAgBvE,MAAM,UAAU,MAAM,CAAI,KAAyC;IACjE,oBAAoB;IACpB,IAAI,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,cAAc,CAAC,GAAG,CAAC,KAAK,CAAM,CAAC;IACxC,CAAC;IAED,gCAAgC;IAChC,IAAI,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAE,KAA2B,CAAC,IAAI,CAAC;QAC1F,MAAM,IAAI,KAAK,CACb,oDAAoD,IAAI,KAAK;YAC7D,8DAA8D,CAC/D,CAAC;IACJ,CAAC;IAED,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,IAAI,CAAC;QACH,IAAI,QAAW,CAAC;QAEhB,6BAA6B;QAC7B,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAA8C,CAAC,CAAC;QACrF,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,GAAG,OAAO,EAAO,CAAC;QAC5B,CAAC;aAAM,IAAI,OAAO,KAAK,KAAK,UAAU,EAAE,CAAC;YACvC,4CAA4C;YAC5C,QAAQ,GAAG,IAAK,KAAwB,EAAE,CAAC;QAC7C,CAAC;aAAM,CAAC;YACN,sCAAsC;YACtC,MAAM,QAAQ,GAAG,KAA0B,CAAC;YAC5C,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACtB,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,CAAC,IAAI,KAAK;oBAClD,8DAA8D,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;QAED,cAAc,CAAC,GAAG,CAAC,KAA8C,EAAE,QAAQ,CAAC,CAAC;QAC7E,OAAO,QAAQ,CAAC;IAClB,CAAC;YAAS,CAAC;QACT,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC;AAWD,MAAM,UAAU,OAAO,CAAI,KAAyC,EAAE,OAAgB;IACpF,gBAAgB,CAAC,GAAG,CAAC,KAA8C,EAAE,OAAO,CAAC,CAAC;IAC9E,+DAA+D;IAC/D,cAAc,CAAC,MAAM,CAAC,KAA8C,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAAI,IAAY,EAAE,cAAwB;IACnE,OAAO;QACL,OAAO,EAAE,gBAAyB;QAClC,IAAI;QACJ,QAAQ,EAAE,cAAc;KACzB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,cAAc,CAAC,KAAK,EAAE,CAAC;IACvB,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACzB,aAAa,CAAC,KAAK,EAAE,CAAC;AACxB,CAAC"}
1
+ {"version":3,"file":"injector.js","sourceRoot":"","sources":["../src/injector.ts"],"names":[],"mappings":"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"}
@@ -52,6 +52,15 @@ export declare function useHostEvent<E extends Event = Event>(target: EventTarge
52
52
  /**
53
53
  * Run all registered mount callbacks for a component host.
54
54
  * Called by component.ts after the template is mounted to the DOM.
55
+ *
56
+ * A throw here PROPAGATES to component.ts's containment boundary — the SAME
57
+ * boundary as a setup throw (ADR 0030.2 T6, code N402): remaining callbacks
58
+ * are skipped, the partial scope (including cleanups already registered by
59
+ * earlier callbacks) is disposed, the error fallback renders, and the host is
60
+ * stamped `data-nisli-error`. The pre-T6 behavior (console-and-limp per
61
+ * callback) left a half-mounted component alive with no machine-readable
62
+ * trace and no teardown — the one containment semantics setup already had
63
+ * (issue 0010) now covers mount too.
55
64
  * @internal
56
65
  */
57
66
  export declare function runMountCallbacks(comp: object): void;
package/dist/lifecycle.js CHANGED
@@ -83,25 +83,35 @@ export function useHostEvent(target, eventName, handler) {
83
83
  /**
84
84
  * Run all registered mount callbacks for a component host.
85
85
  * Called by component.ts after the template is mounted to the DOM.
86
+ *
87
+ * A throw here PROPAGATES to component.ts's containment boundary — the SAME
88
+ * boundary as a setup throw (ADR 0030.2 T6, code N402): remaining callbacks
89
+ * are skipped, the partial scope (including cleanups already registered by
90
+ * earlier callbacks) is disposed, the error fallback renders, and the host is
91
+ * stamped `data-nisli-error`. The pre-T6 behavior (console-and-limp per
92
+ * callback) left a half-mounted component alive with no machine-readable
93
+ * trace and no teardown — the one containment semantics setup already had
94
+ * (issue 0010) now covers mount too.
86
95
  * @internal
87
96
  */
88
97
  export function runMountCallbacks(comp) {
89
98
  const callbacks = mountCallbacks.get(comp);
90
99
  if (!callbacks)
91
100
  return;
92
- for (const cb of callbacks) {
93
- try {
101
+ try {
102
+ for (const cb of callbacks) {
94
103
  const cleanup = cb();
95
104
  if (typeof cleanup === 'function') {
96
105
  // Register cleanup as a disposer on the component
97
106
  comp.addDisposer(cleanup);
98
107
  }
99
108
  }
100
- catch (err) {
101
- console.error('onMount callback error:', err);
102
- }
103
109
  }
104
- // Clear — mount callbacks run once
105
- mountCallbacks.delete(comp);
110
+ finally {
111
+ // Clear — mount callbacks run once (also when a throw contains the scope:
112
+ // the boundary re-runs setup from scratch on the next mount, which
113
+ // re-registers a fresh callback list).
114
+ mountCallbacks.delete(comp);
115
+ }
106
116
  }
107
117
  //# sourceMappingURL=lifecycle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE/D,uEAAuE;AAEvE,wFAAwF;AACxF,MAAM,cAAc,GAAG,IAAI,OAAO,EAAyC,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,QAAmC;IACzD,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,oCAAoC;YACpC,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;IACnC,IAAI,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,EAAE,CAAC;QACf,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACtC,CAAC;IACD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,QAAoB;IAC5C,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,sCAAsC;YACtC,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,mBAAmB,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAmB,EACnB,SAAiB,EACjB,OAA2B;IAE3B,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAwB,CAAC,CAAC;IAC7D,mBAAmB,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;QACrC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAwB,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,EAAE,CAAC;YACrB,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;gBAClC,kDAAkD;gBACjD,IAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,mCAAmC;IACnC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../src/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE/D,uEAAuE;AAEvE,wFAAwF;AACxF,MAAM,cAAc,GAAG,IAAI,OAAO,EAAyC,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CAAC,QAAmC;IACzD,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,oCAAoC;YACpC,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;IACnC,IAAI,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,EAAE,CAAC;QACf,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACtC,CAAC;IACD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,QAAoB;IAC5C,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,sCAAsC;YACtC,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,mBAAmB,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAmB,EACnB,SAAiB,EACjB,OAA2B;IAE3B,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,yCAAyC;YACzC,wDAAwD,CACzD,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAwB,CAAC,CAAC;IAC7D,mBAAmB,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE;QACrC,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAwB,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,IAAI,CAAC;QACH,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,MAAM,OAAO,GAAG,EAAE,EAAE,CAAC;YACrB,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;gBAClC,kDAAkD;gBACjD,IAAY,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,0EAA0E;QAC1E,mEAAmE;QACnE,uCAAuC;QACvC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}
@@ -34,7 +34,7 @@
34
34
  * has any, and only children() consumes them.
35
35
  */
36
36
  import { getCurrentComponent } from './context.js';
37
- import { onMount, onCleanup } from './lifecycle.js';
37
+ import { onCleanup } from './lifecycle.js';
38
38
  import { signal, computed, flush } from './signal.js';
39
39
  /** True if the nodes carry meaningful content (element or non-blank text). */
40
40
  function isMeaningful(nodes) {
@@ -98,18 +98,37 @@ export function children(fallback) {
98
98
  const childrenProp = host._propSignal ? host._propSignal('children') : undefined;
99
99
  // Projected light-DOM nodes; grows when the late-parser sweep finds more.
100
100
  const projectedNodes = signal(captured);
101
+ // True once this setup scope has been disposed (true disconnect, HMR
102
+ // teardown, OR the containment boundary tearing down a failed mount). The
103
+ // queued sweep below must then no-op: it would otherwise misread the
104
+ // post-teardown host children (restored light DOM, or the error fallback)
105
+ // as "late" and relocate them into a dead slot.
106
+ let disposed = false;
101
107
  // A true disconnect/HMR teardown clears the component-owned rendered tree
102
108
  // before setup runs again. Hand the plain light-DOM nodes back to component.ts
103
109
  // so it can restore them as direct host children for the next capture.
104
110
  onCleanup(() => {
111
+ disposed = true;
105
112
  const nodes = projectedNodes.value;
106
113
  host.__capturedChildren = nodes.length ? nodes : undefined;
107
114
  });
108
- onMount(() => {
109
- // The host's direct children right after mount are the rendered template
110
- // roots. Anything that appears later is a late parser/innerHTML child.
115
+ // LATE-CHILDREN SWEEP — scheduled by component.ts's dedicated projection
116
+ // phase (ADR 0030.2 §3), which runs after the template is committed and
117
+ // BEFORE any onMount callback. Pre-0030.2 this was registered via
118
+ // children()'s own onMount, so the rendered-roots snapshot depended on
119
+ // where children() sat relative to other onMount() registrations (the 0025
120
+ // batch-3B ordering trap). Hoisting the SCHEDULING makes the rule
121
+ // universal: the snapshot is exactly the rendered template roots, and
122
+ // anything appearing after it — late parser/innerHTML children AND onMount
123
+ // host-appends — classifies as projected content. Only scheduling moved;
124
+ // the prop READ path (the computed below) is unchanged.
125
+ host.__nisliProjectionSweep = () => {
126
+ // The host's direct children at phase time are the rendered template
127
+ // roots. Anything that appears later is late projected content.
111
128
  const renderedRoots = new Set(Array.from(host.childNodes));
112
129
  queueMicrotask(() => {
130
+ if (disposed)
131
+ return; // scope torn down before the sweep ran
113
132
  const late = Array.from(host.childNodes).filter((n) => !renderedRoots.has(n));
114
133
  if (late.length && isMeaningful(late)) {
115
134
  for (const node of late)
@@ -121,7 +140,7 @@ export function children(fallback) {
121
140
  flush();
122
141
  }
123
142
  });
124
- });
143
+ };
125
144
  // Stable, RE-MOUNTABLE fallback slot: the same slot object is returned on
126
145
  // every empty render, and it can be mounted → unmounted → mounted again
127
146
  // (empty → filled → empty) without crashing. A string wraps to a fresh text
@@ -1 +1 @@
1
- {"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"projection.js","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"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"}
package/dist/query.d.ts CHANGED
@@ -1,85 +1,164 @@
1
1
  /**
2
- * query.ts — Declarative async data loading with cache
2
+ * query.ts — Keyed logical-request store (ADR 0030.2 T1).
3
3
  *
4
- * `query()` absorbs the loading/error/cache/refetch boilerplate that
5
- * every data-fetching component would otherwise write manually.
6
- *
7
- * Inspired by TanStack Query / React Query, but built on signals.
4
+ * The cache unit is a per-key RECORD living in `QueryClient`:
5
+ * `{data, error, status, fetchedAt}` as signals, plus exactly one `run()`
6
+ * owning the retry loop, a per-run `AbortController` handed to the fetcher,
7
+ * and the cache commit. `query()` is a thin OBSERVER: an effect keeps it
8
+ * registered on the record its current key points at, and its outputs are
9
+ * `computed()` views over that record. Dedup unit = logical request, by
10
+ * construction (issues 0005–0009 close as a class).
8
11
  *
9
12
  * ```ts
10
13
  * const tasks = query(
11
14
  * () => ['tasks', scopeId.value],
12
- * () => api.getTasks(scopeId.value),
15
+ * (signal) => api.getTasks(scopeId.value, { signal }),
13
16
  * );
14
- * tasks.data // Signal<Task[] | undefined>
15
- * tasks.loading // Signal<boolean>
16
- * tasks.error // Signal<Error | null>
17
- * tasks.refetch() // manual refetch
17
+ * tasks.data // ReadonlySignal<Task[] | undefined>
18
+ * tasks.loading // ReadonlySignal<boolean>
19
+ * tasks.error // ReadonlySignal<Error | null>
20
+ * tasks.status // ReadonlySignal<'idle' | 'loading' | 'success' | 'error'>
21
+ * tasks.refetch() // force a refetch (joins an in-flight run)
22
+ * tasks.dispose() // standalone callers; component setup auto-disposes
18
23
  * ```
24
+ *
25
+ * Ownership rules (ADR 0030.2 §8, binding):
26
+ * - The most-recently-mounted enabled observer's fetcher/options own the
27
+ * next run for a shared key; `staleTime` freshness is per-observer POLICY
28
+ * (it decides whether *that* observer triggers a run), while the record
29
+ * state is shared truth.
30
+ * - `invalidate()` marks records stale and reruns only records with ≥1
31
+ * enabled observer; disabled observers revalidate on re-enable.
32
+ * - A zero-observer record's in-flight run completes and commits.
33
+ * - Records are NEVER garbage-collected: the cache is unbounded for the
34
+ * life of the client (restates today's unbounded-cache bound). Bound it
35
+ * operationally with `clear()` or a fresh client per app lifetime.
36
+ *
37
+ * Key contract: keys are FLAT — `readonly (string|number|boolean|null)[]`.
38
+ * Objects and `undefined` are rejected with coded error N602 (`null` is
39
+ * the optional sentinel). Flat keys are order-sensitive: prefer
40
+ * per-endpoint key-builder helpers — a reordered key is a silent cache
41
+ * *miss*, benign relative to a collision, but a miss.
42
+ *
43
+ * SSG stance (documented, not built): under core-render, records fetch
44
+ * into the build-lifetime client and must TERMINATE before snapshot —
45
+ * `await settle()` is the barrier. Otherwise queries must be statically
46
+ * disabled for the build.
19
47
  */
20
48
  import { type Signal, type ReadonlySignal } from './signal.js';
21
- export interface QueryResult<T> {
22
- /** The resolved data, or undefined if not yet loaded */
23
- data: Signal<T | undefined>;
24
- /** True while fetching */
49
+ import { type DisposableResource } from './disposable.js';
50
+ /** A single query-key element. `null` is the optional sentinel. */
51
+ export type QueryKeyElement = string | number | boolean | null;
52
+ /** The supported key contract: a flat, order-sensitive tuple. */
53
+ export type QueryKey = readonly QueryKeyElement[];
54
+ export type QueryStatus = 'idle' | 'loading' | 'success' | 'error';
55
+ /** Fetcher contract: receives the run's AbortSignal. Zero-arg fetchers
56
+ * remain assignable. */
57
+ export type QueryFetcher<T> = (signal: AbortSignal) => Promise<T>;
58
+ export interface QueryResult<T> extends DisposableResource {
59
+ /** The record's data, or `initialData`/undefined before first commit. */
60
+ data: ReadonlySignal<T | undefined>;
61
+ /** True while this observer is enabled and its record is fetching. */
25
62
  loading: ReadonlySignal<boolean>;
26
- /** The error if the fetch failed, null otherwise */
27
- error: Signal<Error | null>;
28
- /** Manually trigger a refetch. Bypasses staleTime's fresh-cache
29
- * suppression — a manual refetch inside the freshness window is never a
30
- * silent no-op (react-query semantics). It does not bypass in-flight
31
- * deduplication: if a request for the same key is already running, this
32
- * joins it rather than starting a second fetch. */
63
+ /** The record's terminal error, or null. Cleared when a run starts. */
64
+ error: ReadonlySignal<Error | null>;
65
+ /** The record's lifecycle status. */
66
+ status: ReadonlySignal<QueryStatus>;
67
+ /** Force a refetch: bypasses staleTime freshness, but JOINS an in-flight
68
+ * logical request rather than starting a second one (issue 0005). No-op
69
+ * while disabled. */
33
70
  refetch(): void;
71
+ /** Unregister this observer. Component setup calls this automatically at
72
+ * teardown; standalone callers (tests, scripts) call it explicitly. The
73
+ * record — and any in-flight run — survives: zero-observer runs complete
74
+ * and commit (ADR 0030.2 §8). */
75
+ dispose(): void;
34
76
  }
35
77
  export interface QueryOptions<T> {
36
- /** Cache freshness duration in ms. Default: 0 (always refetch) */
78
+ /** Cache freshness duration in ms for THIS observer. Default: 0 (a
79
+ * registration/re-enable always revalidates). */
37
80
  staleTime?: number;
38
- /** Number of retries on failure. Default: 0 */
81
+ /** Number of retries the run performs when this observer owns it. Default: 0 */
39
82
  retry?: number;
40
- /** Skip fetch when returns false. Signal reads are tracked. */
83
+ /** Skip fetching while this returns false. Signal reads are tracked. */
41
84
  enabled?: () => boolean;
42
- /** Synchronous initial value before first fetch */
85
+ /** Synchronous seed committed into an untouched (idle) record. */
43
86
  initialData?: T;
44
- /** Callback after successful fetch */
45
- onSuccess?: (data: T) => void;
46
- /** Callback after failed fetch */
47
- onError?: (error: Error) => void;
87
+ }
88
+ interface QueryRecord {
89
+ readonly key: QueryKey;
90
+ readonly serialized: string;
91
+ readonly data: Signal<unknown>;
92
+ readonly error: Signal<Error | null>;
93
+ readonly status: Signal<QueryStatus>;
94
+ /** Epoch ms of the last successful commit; 0 = never. */
95
+ readonly fetchedAt: Signal<number>;
96
+ /** Marked by invalidate(); cleared when a run starts. */
97
+ stale: boolean;
98
+ /** True while a run is in flight (status mirrors it reactively). */
99
+ running: boolean;
100
+ /** Increments per run start; a superseded run may never commit. */
101
+ generation: number;
102
+ controller: AbortController | null;
103
+ /** The in-flight run (joinable by prefetch). */
104
+ runPromise: Promise<void> | null;
105
+ /** settle() terminator for the in-flight run. */
106
+ terminate: (() => void) | null;
107
+ readonly observers: Set<QueryObserver>;
108
+ }
109
+ interface QueryObserver {
110
+ readonly mountIndex: number;
111
+ readonly fetcher: QueryFetcher<unknown>;
112
+ readonly staleTime: number;
113
+ readonly retry: number;
114
+ enabled: boolean;
115
+ record: QueryRecord | null;
48
116
  }
49
117
  /**
50
- * Global query cache. Managed as an auto-singleton via inject().
51
- * Components use query() which accesses the client internally.
118
+ * Global keyed logical-request store. One per app: resolved via
119
+ * `inject(QueryClient)` (auto-singleton; override with
120
+ * `provide(QueryClient, ...)` BEFORE the first query() call).
121
+ *
122
+ * Records are never GC'd — see the module doc for the bound.
52
123
  */
53
124
  export declare class QueryClient {
54
- private cache;
55
- private inFlight;
56
- /** Check if a cache entry is fresh */
57
- isFresh(key: string, staleTime: number): boolean;
58
- /** Get cached data */
59
- getCached<T>(key: string): T | undefined;
60
- /** Store data in cache */
61
- set(key: string, data: unknown, staleTime: number): void;
62
- /** Get in-flight promise for deduplication */
63
- getInFlight(key: string): Promise<unknown> | undefined;
64
- /** Register an in-flight request */
65
- setInFlight(key: string, promise: Promise<unknown>): void;
125
+ /** @internal */ _records: Map<string, QueryRecord>;
126
+ /** @internal clear() bumps this; observer effects track it and re-resolve. */
127
+ _version: Signal<number>;
128
+ /** @internal live observer count (N601 mixed-client diagnostic). */
129
+ _observers: number;
66
130
  /**
67
- * Invalidate cached entries whose key array starts with the given prefix elements.
68
- * Returns the number of entries invalidated.
131
+ * Mark records matching the key prefix stale and rerun those with ≥1
132
+ * enabled observer (using the owning observer's fetcher/options).
133
+ * Disabled observers revalidate on re-enable; a record with only
134
+ * disabled/no observers stays stale until one arrives. Returns the
135
+ * number of records invalidated.
69
136
  *
70
- * invalidate(['tasks']) matches ['tasks'], ['tasks', '1'], ['tasks', '2', 'x']
137
+ * invalidate(['tasks']) matches ['tasks'], ['tasks', '1'], ['tasks', '2', 'x'].
138
+ */
139
+ invalidate(keyPrefix: QueryKey): number;
140
+ /**
141
+ * Drop every record. In-flight runs are aborted (a settle() termination).
142
+ * Live observers re-resolve fresh records on the version bump — enabled
143
+ * ones revalidate immediately.
71
144
  */
72
- invalidate(keyPrefix: unknown[]): number;
73
- /** Prefetch and cache data */
74
- prefetch(key: unknown[], fetcher: () => Promise<unknown>, staleTime?: number): Promise<void>;
75
- /** Clear all cache */
76
145
  clear(): void;
146
+ /**
147
+ * Imperatively warm a record. Joins an in-flight run; a fresh record
148
+ * (per the given staleTime) is a no-op. Otherwise starts a run with THE
149
+ * GIVEN fetcher — an explicit imperative is its own owner. The run
150
+ * commits even with zero observers. Resolves at run termination.
151
+ */
152
+ prefetch<T>(key: QueryKey, fetcher: QueryFetcher<T>, staleTime?: number): Promise<void>;
77
153
  }
78
154
  /**
79
- * Declarative async data loading with caching and auto-refetch.
155
+ * Observe the record the reactive key points at.
80
156
  *
81
- * @param keyFn - Returns a cache key array. Signal reads are auto-tracked for refetch.
82
- * @param fetcher - Async function that fetches the data.
83
- * @param options - Optional configuration (staleTime, retry, enabled, etc.)
157
+ * @param keyFn - Returns the flat cache key. Signal reads are tracked; a
158
+ * key change re-registers the observer on the new record.
159
+ * @param fetcher - Fetches the data; receives the run's AbortSignal.
160
+ * @param options - staleTime / retry / enabled / initialData.
161
+ * @throws N602 synchronously when the initial key violates the contract.
84
162
  */
85
- export declare function query<T>(keyFn: () => unknown[], fetcher: () => Promise<T>, options?: QueryOptions<T>): QueryResult<T>;
163
+ export declare function query<T>(keyFn: () => QueryKey, fetcher: QueryFetcher<T>, options?: QueryOptions<T>): QueryResult<T>;
164
+ export {};