@llui/dom 0.0.18 → 0.0.19

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 (71) hide show
  1. package/dist/binding.d.ts.map +1 -1
  2. package/dist/binding.js +5 -0
  3. package/dist/binding.js.map +1 -1
  4. package/dist/devtools.d.ts +109 -0
  5. package/dist/devtools.d.ts.map +1 -1
  6. package/dist/devtools.js +401 -1
  7. package/dist/devtools.js.map +1 -1
  8. package/dist/hmr.d.ts.map +1 -1
  9. package/dist/hmr.js +2 -0
  10. package/dist/hmr.js.map +1 -1
  11. package/dist/index.d.ts +6 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/mount.d.ts.map +1 -1
  15. package/dist/mount.js +18 -2
  16. package/dist/mount.js.map +1 -1
  17. package/dist/primitives/branch.d.ts.map +1 -1
  18. package/dist/primitives/branch.js +10 -1
  19. package/dist/primitives/branch.js.map +1 -1
  20. package/dist/primitives/child.d.ts.map +1 -1
  21. package/dist/primitives/child.js +25 -5
  22. package/dist/primitives/child.js.map +1 -1
  23. package/dist/primitives/each.d.ts.map +1 -1
  24. package/dist/primitives/each.js +79 -6
  25. package/dist/primitives/each.js.map +1 -1
  26. package/dist/primitives/foreign.d.ts.map +1 -1
  27. package/dist/primitives/foreign.js +1 -0
  28. package/dist/primitives/foreign.js.map +1 -1
  29. package/dist/primitives/lazy.d.ts.map +1 -1
  30. package/dist/primitives/lazy.js +1 -0
  31. package/dist/primitives/lazy.js.map +1 -1
  32. package/dist/primitives/portal.d.ts.map +1 -1
  33. package/dist/primitives/portal.js +1 -0
  34. package/dist/primitives/portal.js.map +1 -1
  35. package/dist/primitives/show.d.ts.map +1 -1
  36. package/dist/primitives/show.js +4 -0
  37. package/dist/primitives/show.js.map +1 -1
  38. package/dist/primitives/virtual-each.d.ts.map +1 -1
  39. package/dist/primitives/virtual-each.js +3 -0
  40. package/dist/primitives/virtual-each.js.map +1 -1
  41. package/dist/render-context.d.ts.map +1 -1
  42. package/dist/render-context.js.map +1 -1
  43. package/dist/scope.d.ts.map +1 -1
  44. package/dist/scope.js +68 -1
  45. package/dist/scope.js.map +1 -1
  46. package/dist/ssr.d.ts.map +1 -1
  47. package/dist/ssr.js +5 -1
  48. package/dist/ssr.js.map +1 -1
  49. package/dist/tracking/coverage.d.ts +27 -0
  50. package/dist/tracking/coverage.d.ts.map +1 -0
  51. package/dist/tracking/coverage.js +39 -0
  52. package/dist/tracking/coverage.js.map +1 -0
  53. package/dist/tracking/disposer-log.d.ts +22 -0
  54. package/dist/tracking/disposer-log.d.ts.map +1 -0
  55. package/dist/tracking/disposer-log.js +3 -0
  56. package/dist/tracking/disposer-log.js.map +1 -0
  57. package/dist/tracking/each-diff.d.ts +62 -0
  58. package/dist/tracking/each-diff.d.ts.map +1 -0
  59. package/dist/tracking/each-diff.js +26 -0
  60. package/dist/tracking/each-diff.js.map +1 -0
  61. package/dist/tracking/effect-timeline.d.ts +73 -0
  62. package/dist/tracking/effect-timeline.d.ts.map +1 -0
  63. package/dist/tracking/effect-timeline.js +89 -0
  64. package/dist/tracking/effect-timeline.js.map +1 -0
  65. package/dist/types.d.ts +18 -1
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/types.js.map +1 -1
  68. package/dist/update-loop.d.ts.map +1 -1
  69. package/dist/update-loop.js +78 -0
  70. package/dist/update-loop.js.map +1 -1
  71. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/tracking/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,MAAM,UAAU,qBAAqB;IACnC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAgD,CAAA;IACrE,OAAO;QACL,MAAM,CAAC,OAAO,EAAE,YAAY;YAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YACnC,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,KAAK,EAAE,CAAA;gBAChB,QAAQ,CAAC,SAAS,GAAG,YAAY,CAAA;YACnC,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAA;YAC3D,CAAC;QACH,CAAC;QACD,QAAQ,CAAC,aAAa;YACpB,MAAM,QAAQ,GAAyD,EAAE,CAAA;YACzE,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK;gBAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAA;YAClD,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;YAClF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAA;QACxC,CAAC;QACD,KAAK;YACH,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["/**\n * Per-variant Msg coverage tracker — dev-only.\n *\n * Records each dispatched message's discriminant (or `<non-discriminant>`\n * for objects missing a `type` field) along with the message index it\n * fired at. Consumed by the `llui_coverage` MCP tool to surface untested\n * Msg variants: any variant declared in the compiled `__msgSchema` that\n * never fired in the current session shows up in `neverFired`.\n *\n * Zero cost in production: `installDevTools` is the only caller, and it\n * never runs in prod builds. Hot path is one optional-chain read per\n * dispatched message (`ci._coverage?.record(...)`).\n */\n\nexport interface CoverageSnapshot {\n fired: Record<string, { count: number; lastIndex: number }>\n neverFired: string[]\n}\n\nexport interface CoverageTracker {\n record(variant: string, messageIndex: number): void\n snapshot(knownVariants?: string[]): CoverageSnapshot\n clear(): void\n}\n\nexport function createCoverageTracker(): CoverageTracker {\n const fired = new Map<string, { count: number; lastIndex: number }>()\n return {\n record(variant, messageIndex) {\n const existing = fired.get(variant)\n if (existing) {\n existing.count++\n existing.lastIndex = messageIndex\n } else {\n fired.set(variant, { count: 1, lastIndex: messageIndex })\n }\n },\n snapshot(knownVariants) {\n const firedObj: Record<string, { count: number; lastIndex: number }> = {}\n for (const [k, v] of fired) firedObj[k] = { ...v }\n const neverFired = knownVariants ? knownVariants.filter((v) => !fired.has(v)) : []\n return { fired: firedObj, neverFired }\n },\n clear() {\n fired.clear()\n },\n }\n}\n"]}
@@ -0,0 +1,22 @@
1
+ import { createRingBuffer, type RingBuffer } from './each-diff.js';
2
+ /**
3
+ * Dev-only disposer log entry, emitted once per `disposeScope` call
4
+ * when the owning component instance has an `_disposerLog` ring buffer
5
+ * installed by `installDevTools`.
6
+ *
7
+ * `cause` is set by the structural primitive (each / branch / child)
8
+ * immediately before calling `disposeScope`. When no cause was
9
+ * explicitly set, `disposeScope` falls back to `'component-unmount'`.
10
+ * `'app-unmount'` is reserved for the top-level `mountApp` teardown.
11
+ *
12
+ * Used by the `llui_disposer_log` MCP tool to diagnose leaks on
13
+ * structural transitions (e.g., branch swap that fails to release a
14
+ * subscription registered in the old arm).
15
+ */
16
+ export interface DisposerEvent {
17
+ scopeId: string;
18
+ cause: 'branch-swap' | 'each-remove' | 'show-hide' | 'child-unmount' | 'app-unmount' | 'component-unmount';
19
+ timestamp: number;
20
+ }
21
+ export { createRingBuffer, type RingBuffer };
22
+ //# sourceMappingURL=disposer-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposer-log.d.ts","sourceRoot":"","sources":["../../src/tracking/disposer-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAElE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EACD,aAAa,GACb,aAAa,GACb,WAAW,GACX,eAAe,GACf,aAAa,GACb,mBAAmB,CAAA;IACvB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { createRingBuffer } from './each-diff.js';
2
+ export { createRingBuffer };
3
+ //# sourceMappingURL=disposer-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disposer-log.js","sourceRoot":"","sources":["../../src/tracking/disposer-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAmB,MAAM,gBAAgB,CAAA;AA4BlE,OAAO,EAAE,gBAAgB,EAAmB,CAAA","sourcesContent":["import { createRingBuffer, type RingBuffer } from './each-diff.js'\n\n/**\n * Dev-only disposer log entry, emitted once per `disposeScope` call\n * when the owning component instance has an `_disposerLog` ring buffer\n * installed by `installDevTools`.\n *\n * `cause` is set by the structural primitive (each / branch / child)\n * immediately before calling `disposeScope`. When no cause was\n * explicitly set, `disposeScope` falls back to `'component-unmount'`.\n * `'app-unmount'` is reserved for the top-level `mountApp` teardown.\n *\n * Used by the `llui_disposer_log` MCP tool to diagnose leaks on\n * structural transitions (e.g., branch swap that fails to release a\n * subscription registered in the old arm).\n */\nexport interface DisposerEvent {\n scopeId: string\n cause:\n | 'branch-swap'\n | 'each-remove'\n | 'show-hide'\n | 'child-unmount'\n | 'app-unmount'\n | 'component-unmount'\n timestamp: number\n}\n\nexport { createRingBuffer, type RingBuffer }\n"]}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Per-each-block reconciliation diff, recorded once per update that
3
+ * mutates an each() block's key set. Dev-only — populated when
4
+ * `installDevTools` has initialized an `_eachDiffLog` on the instance.
5
+ *
6
+ * `updateIndex` correlates with the message-history index recorded by
7
+ * `devtools.ts` so tools can join diffs back to the message that caused
8
+ * them. `eachSiteId` identifies the each() call site stably across
9
+ * updates (currently derived from the block's index in the instance's
10
+ * `structuralBlocks` array at creation time).
11
+ */
12
+ export interface EachDiff {
13
+ /**
14
+ * Message-history index at the time the diff was emitted. When messages are
15
+ * batched (multiple send() calls coalescing into one microtask), this is
16
+ * the index of the LAST message in the batch — not necessarily the one that
17
+ * caused the structural change. For per-message correlation, use
18
+ * getMessageHistory with this index as an upper bound.
19
+ */
20
+ updateIndex: number;
21
+ /**
22
+ * Stable-ish identifier for the each() call site. Currently derived from the
23
+ * position of the block in `ComponentInstance.structuralBlocks` at the moment
24
+ * of registration, formatted as `each#${N}`.
25
+ *
26
+ * Caveats for consumers:
27
+ * - The counter includes ALL structural blocks (branches, shows, portals,
28
+ * eaches), not just eaches. So `each#3` means "the 4th structural block",
29
+ * not "the 4th each".
30
+ * - Blocks registered inside a `branch` arm that switches away are spliced
31
+ * out; a subsequent each registration can reuse the same N.
32
+ * - Across HMR reloads the ID may drift if the view's structural-block
33
+ * order changed.
34
+ *
35
+ * For precise correlation across updates, pair with `updateIndex` and the
36
+ * enclosing component's state at that index (retrievable via
37
+ * getMessageHistory).
38
+ */
39
+ eachSiteId: string;
40
+ added: string[];
41
+ removed: string[];
42
+ moved: Array<{
43
+ key: string;
44
+ from: number;
45
+ to: number;
46
+ }>;
47
+ reused: string[];
48
+ }
49
+ export interface RingBuffer<T> {
50
+ push(entry: T): void;
51
+ toArray(): T[];
52
+ clear(): void;
53
+ size(): number;
54
+ }
55
+ /**
56
+ * Minimal ring buffer: unbounded `push` trimmed to `maxSize` via shift.
57
+ * Kept tiny on purpose — any fancier implementation would pay interest
58
+ * for an allocation-cost saving that only matters under unrealistic
59
+ * dev-only churn. If we ever need it, replace with a circular array.
60
+ */
61
+ export declare function createRingBuffer<T>(maxSize: number): RingBuffer<T>;
62
+ //# sourceMappingURL=each-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"each-diff.d.ts","sourceRoot":"","sources":["../../src/tracking/each-diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;;OAMG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACvD,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAA;IACpB,OAAO,IAAI,CAAC,EAAE,CAAA;IACd,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAiBlE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Minimal ring buffer: unbounded `push` trimmed to `maxSize` via shift.
3
+ * Kept tiny on purpose — any fancier implementation would pay interest
4
+ * for an allocation-cost saving that only matters under unrealistic
5
+ * dev-only churn. If we ever need it, replace with a circular array.
6
+ */
7
+ export function createRingBuffer(maxSize) {
8
+ const buf = [];
9
+ return {
10
+ push(entry) {
11
+ if (buf.length >= maxSize)
12
+ buf.shift();
13
+ buf.push(entry);
14
+ },
15
+ toArray() {
16
+ return buf.slice();
17
+ },
18
+ clear() {
19
+ buf.length = 0;
20
+ },
21
+ size() {
22
+ return buf.length;
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=each-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"each-diff.js","sourceRoot":"","sources":["../../src/tracking/each-diff.ts"],"names":[],"mappings":"AAoDA;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAI,OAAe;IACjD,MAAM,GAAG,GAAQ,EAAE,CAAA;IACnB,OAAO;QACL,IAAI,CAAC,KAAK;YACR,IAAI,GAAG,CAAC,MAAM,IAAI,OAAO;gBAAE,GAAG,CAAC,KAAK,EAAE,CAAA;YACtC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;QACD,OAAO;YACL,OAAO,GAAG,CAAC,KAAK,EAAE,CAAA;QACpB,CAAC;QACD,KAAK;YACH,GAAG,CAAC,MAAM,GAAG,CAAC,CAAA;QAChB,CAAC;QACD,IAAI;YACF,OAAO,GAAG,CAAC,MAAM,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC","sourcesContent":["/**\n * Per-each-block reconciliation diff, recorded once per update that\n * mutates an each() block's key set. Dev-only — populated when\n * `installDevTools` has initialized an `_eachDiffLog` on the instance.\n *\n * `updateIndex` correlates with the message-history index recorded by\n * `devtools.ts` so tools can join diffs back to the message that caused\n * them. `eachSiteId` identifies the each() call site stably across\n * updates (currently derived from the block's index in the instance's\n * `structuralBlocks` array at creation time).\n */\nexport interface EachDiff {\n /**\n * Message-history index at the time the diff was emitted. When messages are\n * batched (multiple send() calls coalescing into one microtask), this is\n * the index of the LAST message in the batch — not necessarily the one that\n * caused the structural change. For per-message correlation, use\n * getMessageHistory with this index as an upper bound.\n */\n updateIndex: number\n /**\n * Stable-ish identifier for the each() call site. Currently derived from the\n * position of the block in `ComponentInstance.structuralBlocks` at the moment\n * of registration, formatted as `each#${N}`.\n *\n * Caveats for consumers:\n * - The counter includes ALL structural blocks (branches, shows, portals,\n * eaches), not just eaches. So `each#3` means \"the 4th structural block\",\n * not \"the 4th each\".\n * - Blocks registered inside a `branch` arm that switches away are spliced\n * out; a subsequent each registration can reuse the same N.\n * - Across HMR reloads the ID may drift if the view's structural-block\n * order changed.\n *\n * For precise correlation across updates, pair with `updateIndex` and the\n * enclosing component's state at that index (retrievable via\n * getMessageHistory).\n */\n eachSiteId: string\n added: string[]\n removed: string[]\n moved: Array<{ key: string; from: number; to: number }>\n reused: string[]\n}\n\nexport interface RingBuffer<T> {\n push(entry: T): void\n toArray(): T[]\n clear(): void\n size(): number\n}\n\n/**\n * Minimal ring buffer: unbounded `push` trimmed to `maxSize` via shift.\n * Kept tiny on purpose — any fancier implementation would pay interest\n * for an allocation-cost saving that only matters under unrealistic\n * dev-only churn. If we ever need it, replace with a circular array.\n */\nexport function createRingBuffer<T>(maxSize: number): RingBuffer<T> {\n const buf: T[] = []\n return {\n push(entry) {\n if (buf.length >= maxSize) buf.shift()\n buf.push(entry)\n },\n toArray() {\n return buf.slice()\n },\n clear() {\n buf.length = 0\n },\n size() {\n return buf.length\n },\n }\n}\n"]}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Effect timeline + pending-effects list + mock registry — the three
3
+ * trackers that back the `llui_pending_effects`, `llui_effect_timeline`,
4
+ * `llui_mock_effect`, and `llui_resolve_effect` MCP tools.
5
+ *
6
+ * Dev-only — populated on `ComponentInstance` when `installDevTools`
7
+ * runs. Zero cost in production (the `dispatchEffectDev` wrapper in
8
+ * `update-loop.ts` short-circuits when `_effectTimeline` is undefined).
9
+ *
10
+ * The mock registry stores match-to-response pairs; the actual
11
+ * response delivery (i.e., converting a mocked response back into a
12
+ * Msg via the effect's `onSuccess` callback) is the responsibility of
13
+ * the MCP `llui_resolve_effect` tool — not this module.
14
+ */
15
+ import { createRingBuffer, type RingBuffer } from './each-diff.js';
16
+ export interface EffectTimelineEntry {
17
+ effectId: string;
18
+ type: string;
19
+ phase: 'dispatched' | 'in-flight' | 'resolved' | 'resolved-mocked' | 'cancelled';
20
+ timestamp: number;
21
+ /** Populated on `resolved` / `resolved-mocked` / `cancelled` entries; undefined on open phases. */
22
+ durationMs?: number;
23
+ }
24
+ export interface PendingEffect {
25
+ id: string;
26
+ type: string;
27
+ dispatchedAt: number;
28
+ status: 'queued' | 'in-flight';
29
+ payload: unknown;
30
+ }
31
+ /**
32
+ * Match predicate for the mock registry. All provided fields must
33
+ * match for the mock to fire:
34
+ * - `type`: exact-match against the effect's `type` discriminant.
35
+ * - `payloadPath`: dotted path into the effect object (e.g. `'url'` or
36
+ * `'body.key'`). When present without `payloadEquals`, presence of
37
+ * the path is sufficient.
38
+ * - `payloadEquals`: strict (`===`) equality check at `payloadPath`.
39
+ *
40
+ * An empty match (no fields) matches every effect — callers should
41
+ * set at least `type` to avoid accidental catch-all.
42
+ */
43
+ export interface EffectMatch {
44
+ type?: string;
45
+ payloadPath?: string;
46
+ payloadEquals?: unknown;
47
+ }
48
+ export interface EffectMock {
49
+ mockId: string;
50
+ match: EffectMatch;
51
+ response: unknown;
52
+ /** When false, the mock is removed after the first match (one-shot). */
53
+ persist: boolean;
54
+ }
55
+ export interface MockRegistry {
56
+ add(match: EffectMatch, response: unknown, persist: boolean): string;
57
+ match(effect: unknown): {
58
+ response: unknown;
59
+ mockId: string;
60
+ } | null;
61
+ clear(): void;
62
+ list(): EffectMock[];
63
+ }
64
+ export declare function createMockRegistry(): MockRegistry;
65
+ export interface PendingEffectsList {
66
+ push(p: PendingEffect): void;
67
+ findById(id: string): PendingEffect | undefined;
68
+ remove(id: string): void;
69
+ list(): PendingEffect[];
70
+ }
71
+ export declare function createPendingEffectsList(): PendingEffectsList;
72
+ export { createRingBuffer, type RingBuffer };
73
+ //# sourceMappingURL=effect-timeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect-timeline.d.ts","sourceRoot":"","sources":["../../src/tracking/effect-timeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAElE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,YAAY,GAAG,WAAW,GAAG,UAAU,GAAG,iBAAiB,GAAG,WAAW,CAAA;IAChF,SAAS,EAAE,MAAM,CAAA;IACjB,mGAAmG;IACnG,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAA;IAC9B,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,OAAO,CAAA;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,WAAW,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,wEAAwE;IACxE,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,CAAA;IACpE,KAAK,CAAC,MAAM,EAAE,OAAO,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACpE,KAAK,IAAI,IAAI,CAAA;IACb,IAAI,IAAI,UAAU,EAAE,CAAA;CACrB;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAqDjD;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAA;IAC/C,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,IAAI,IAAI,aAAa,EAAE,CAAA;CACxB;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CAa7D;AAED,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,CAAA"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Effect timeline + pending-effects list + mock registry — the three
3
+ * trackers that back the `llui_pending_effects`, `llui_effect_timeline`,
4
+ * `llui_mock_effect`, and `llui_resolve_effect` MCP tools.
5
+ *
6
+ * Dev-only — populated on `ComponentInstance` when `installDevTools`
7
+ * runs. Zero cost in production (the `dispatchEffectDev` wrapper in
8
+ * `update-loop.ts` short-circuits when `_effectTimeline` is undefined).
9
+ *
10
+ * The mock registry stores match-to-response pairs; the actual
11
+ * response delivery (i.e., converting a mocked response back into a
12
+ * Msg via the effect's `onSuccess` callback) is the responsibility of
13
+ * the MCP `llui_resolve_effect` tool — not this module.
14
+ */
15
+ import { createRingBuffer } from './each-diff.js';
16
+ export function createMockRegistry() {
17
+ const mocks = [];
18
+ let nextId = 1;
19
+ function resolvePath(obj, path) {
20
+ const parts = path.split('.');
21
+ let v = obj;
22
+ for (const p of parts) {
23
+ if (v == null || typeof v !== 'object')
24
+ return undefined;
25
+ v = v[p];
26
+ }
27
+ return v;
28
+ }
29
+ function matches(m, effect) {
30
+ if (effect == null || typeof effect !== 'object')
31
+ return false;
32
+ const eff = effect;
33
+ if (m.match.type !== undefined && eff.type !== m.match.type)
34
+ return false;
35
+ if (m.match.payloadPath !== undefined) {
36
+ const v = resolvePath(eff, m.match.payloadPath);
37
+ if (m.match.payloadEquals !== undefined && v !== m.match.payloadEquals)
38
+ return false;
39
+ // Presence-only check: path must resolve to something other than undefined.
40
+ if (m.match.payloadEquals === undefined && v === undefined)
41
+ return false;
42
+ }
43
+ return true;
44
+ }
45
+ return {
46
+ add(match, response, persist) {
47
+ const mockId = `mock-${nextId++}`;
48
+ mocks.push({ mockId, match, response, persist });
49
+ return mockId;
50
+ },
51
+ match(effect) {
52
+ for (let i = 0; i < mocks.length; i++) {
53
+ const m = mocks[i];
54
+ if (matches(m, effect)) {
55
+ const response = m.response;
56
+ const mockId = m.mockId;
57
+ if (!m.persist)
58
+ mocks.splice(i, 1);
59
+ return { response, mockId };
60
+ }
61
+ }
62
+ return null;
63
+ },
64
+ clear() {
65
+ mocks.length = 0;
66
+ nextId = 1;
67
+ },
68
+ list() {
69
+ return mocks.slice();
70
+ },
71
+ };
72
+ }
73
+ export function createPendingEffectsList() {
74
+ const items = [];
75
+ return {
76
+ push(p) {
77
+ items.push(p);
78
+ },
79
+ findById: (id) => items.find((p) => p.id === id),
80
+ remove(id) {
81
+ const i = items.findIndex((p) => p.id === id);
82
+ if (i >= 0)
83
+ items.splice(i, 1);
84
+ },
85
+ list: () => items.slice(),
86
+ };
87
+ }
88
+ export { createRingBuffer };
89
+ //# sourceMappingURL=effect-timeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effect-timeline.js","sourceRoot":"","sources":["../../src/tracking/effect-timeline.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Effect timeline + pending-effects list + mock registry — the three\n * trackers that back the `llui_pending_effects`, `llui_effect_timeline`,\n * `llui_mock_effect`, and `llui_resolve_effect` MCP tools.\n *\n * Dev-only — populated on `ComponentInstance` when `installDevTools`\n * runs. Zero cost in production (the `dispatchEffectDev` wrapper in\n * `update-loop.ts` short-circuits when `_effectTimeline` is undefined).\n *\n * The mock registry stores match-to-response pairs; the actual\n * response delivery (i.e., converting a mocked response back into a\n * Msg via the effect's `onSuccess` callback) is the responsibility of\n * the MCP `llui_resolve_effect` tool — not this module.\n */\nimport { createRingBuffer, type RingBuffer } from './each-diff.js'\n\nexport interface EffectTimelineEntry {\n effectId: string\n type: string\n phase: 'dispatched' | 'in-flight' | 'resolved' | 'resolved-mocked' | 'cancelled'\n timestamp: number\n /** Populated on `resolved` / `resolved-mocked` / `cancelled` entries; undefined on open phases. */\n durationMs?: number\n}\n\nexport interface PendingEffect {\n id: string\n type: string\n dispatchedAt: number\n status: 'queued' | 'in-flight'\n payload: unknown\n}\n\n/**\n * Match predicate for the mock registry. All provided fields must\n * match for the mock to fire:\n * - `type`: exact-match against the effect's `type` discriminant.\n * - `payloadPath`: dotted path into the effect object (e.g. `'url'` or\n * `'body.key'`). When present without `payloadEquals`, presence of\n * the path is sufficient.\n * - `payloadEquals`: strict (`===`) equality check at `payloadPath`.\n *\n * An empty match (no fields) matches every effect — callers should\n * set at least `type` to avoid accidental catch-all.\n */\nexport interface EffectMatch {\n type?: string\n payloadPath?: string\n payloadEquals?: unknown\n}\n\nexport interface EffectMock {\n mockId: string\n match: EffectMatch\n response: unknown\n /** When false, the mock is removed after the first match (one-shot). */\n persist: boolean\n}\n\nexport interface MockRegistry {\n add(match: EffectMatch, response: unknown, persist: boolean): string\n match(effect: unknown): { response: unknown; mockId: string } | null\n clear(): void\n list(): EffectMock[]\n}\n\nexport function createMockRegistry(): MockRegistry {\n const mocks: EffectMock[] = []\n let nextId = 1\n\n function resolvePath(obj: Record<string, unknown>, path: string): unknown {\n const parts = path.split('.')\n let v: unknown = obj\n for (const p of parts) {\n if (v == null || typeof v !== 'object') return undefined\n v = (v as Record<string, unknown>)[p]\n }\n return v\n }\n\n function matches(m: EffectMock, effect: unknown): boolean {\n if (effect == null || typeof effect !== 'object') return false\n const eff = effect as Record<string, unknown>\n if (m.match.type !== undefined && eff.type !== m.match.type) return false\n if (m.match.payloadPath !== undefined) {\n const v = resolvePath(eff, m.match.payloadPath)\n if (m.match.payloadEquals !== undefined && v !== m.match.payloadEquals) return false\n // Presence-only check: path must resolve to something other than undefined.\n if (m.match.payloadEquals === undefined && v === undefined) return false\n }\n return true\n }\n\n return {\n add(match, response, persist) {\n const mockId = `mock-${nextId++}`\n mocks.push({ mockId, match, response, persist })\n return mockId\n },\n match(effect) {\n for (let i = 0; i < mocks.length; i++) {\n const m = mocks[i]!\n if (matches(m, effect)) {\n const response = m.response\n const mockId = m.mockId\n if (!m.persist) mocks.splice(i, 1)\n return { response, mockId }\n }\n }\n return null\n },\n clear() {\n mocks.length = 0\n nextId = 1\n },\n list() {\n return mocks.slice()\n },\n }\n}\n\nexport interface PendingEffectsList {\n push(p: PendingEffect): void\n findById(id: string): PendingEffect | undefined\n remove(id: string): void\n list(): PendingEffect[]\n}\n\nexport function createPendingEffectsList(): PendingEffectsList {\n const items: PendingEffect[] = []\n return {\n push(p) {\n items.push(p)\n },\n findById: (id) => items.find((p) => p.id === id),\n remove(id) {\n const i = items.findIndex((p) => p.id === id)\n if (i >= 0) items.splice(i, 1)\n },\n list: () => items.slice(),\n }\n}\n\nexport { createRingBuffer, type RingBuffer }\n"]}
package/dist/types.d.ts CHANGED
@@ -137,7 +137,24 @@ export interface Scope {
137
137
  /** Per-item updaters — called directly by each() when item changes, bypassing Phase 2 */
138
138
  itemUpdaters: Array<() => void>;
139
139
  }
140
- export type BindingKind = 'text' | 'prop' | 'attr' | 'class' | 'style';
140
+ export interface ScopeNode {
141
+ scopeId: string;
142
+ kind: 'root' | 'show' | 'each' | 'branch' | 'child' | 'portal' | 'foreign';
143
+ active: boolean;
144
+ children: ScopeNode[];
145
+ }
146
+ /**
147
+ * Binding output kinds.
148
+ *
149
+ * `'text' | 'prop' | 'attr' | 'class' | 'style'` write their accessor's
150
+ * return value to the DOM. `'effect'` is a side-effect-only watcher:
151
+ * the accessor is invoked every Phase 2 tick its mask is hit, but its
152
+ * return value is discarded and `applyBinding` is a no-op. Used by
153
+ * `child()` to fire the prop-diff/propsMsg cascade on parent updates
154
+ * without the cost of stringifying the returned props bag onto a
155
+ * detached anchor node every render.
156
+ */
157
+ export type BindingKind = 'text' | 'prop' | 'attr' | 'class' | 'style' | 'effect';
141
158
  export interface Binding {
142
159
  mask: number;
143
160
  accessor: (state: unknown) => unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAA;AAG7C,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI;IACrD,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IAC3B,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;IACtC,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAA;IAC/B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAA;IAG3E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,CAAC,CAAC,CAAA;CA2BlD;AAED,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;AAEtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IACzC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IAC1D,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC,GAAG,IAAI;IAC/B,IAAI,EAAE,MAAM,CAAA;IAKZ,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IACnC,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IAC1D,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI;KACvB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAA;AAID,MAAM,WAAW,SAAS;IACxB,OAAO,IAAI,IAAI,CAAA;IACf,KAAK,IAAI,IAAI,CAAA;IACb;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;CACzB;AAID,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,KAAK,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,KAAK,EAAE,CAAA;IACjB,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAA;IAC5B,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,yFAAyF;IACzF,YAAY,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAA;CAChC;AAID,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAEtE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IACrC,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,IAAI,CAAA;IACV,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,KAAK,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;CACd;AAID,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/C,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/C,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QAAC,MAAM,EAAE,IAAI,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAClG;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,iBAAiB;IACtE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;IACvC,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;CAC1D;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,iBAAiB;IACpE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAA;IACvB,MAAM,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAA;IACjC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAA;CACrC;AAED;;;;;;GAMG;AACH;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAC5B,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAA;CACpC,GAAG;KACD,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;CAC7B,CAAA;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,iBAAiB;IACvE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAA;IACpB,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,MAAM,CAAA;IACjC,MAAM,EAAE,CAAC,IAAI,EAAE;QACb,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;QACb,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,CAAA;QACrB;;;WAGG;QACH,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,CAAA;QAC1C,KAAK,EAAE,MAAM,MAAM,CAAA;KAGpB,KAAK,IAAI,EAAE,CAAA;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,GAAG,MAAM,CAAA;IAC5B,MAAM,EAAE,MAAM,IAAI,EAAE,CAAA;CACrB;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ;IAC/E,KAAK,EAAE,CAAC,GAAG,EAAE;QAAE,SAAS,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;KAAE,KAAK,QAAQ,CAAA;IACnE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAA;IAClB,IAAI,EACA,CAAC,CAAC,GAAG,EAAE;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC;QAAC,IAAI,EAAE,CAAC,GAAG,SAAS,CAAA;KAAE,KAAK,IAAI,CAAC,GACtE;SACG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE;YAAE,QAAQ,EAAE,QAAQ,CAAC;YAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAA;SAAE,KAAK,IAAI;KAC5F,CAAA;IACL,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IACrC,SAAS,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAA;CAC7D;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,MAAM;IAMrC,GAAG,EAAE,eAAe,CAAA;IACpB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACxC,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAA;CACxC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qEAAqE","sourcesContent":["// ── Component Definition ──────────────────────────────────────────\n\nimport type { View } from './view-helpers.js'\nimport type { StructuralBlock } from './structural.js'\n\nexport interface ComponentDef<S, M, E = never, D = void> {\n name: string\n init: (data: D) => [S, E[]]\n update: (state: S, msg: M) => [S, E[]]\n view: (h: View<S, M>) => Node[]\n onEffect?: (ctx: { effect: E; send: Send<M>; signal: AbortSignal }) => void\n\n // Level 2 composition\n propsMsg?: (props: Record<string, unknown>) => M\n receives?: Record<string, (params: unknown) => M>\n\n /** @internal Compiler-injected */\n __dirty?: (oldState: S, newState: S) => number | [number, number]\n /** @internal Compiler-injected */\n __renderToString?: (state: S) => string\n /** @internal Compiler-injected */\n __msgSchema?: object\n /** @internal Compiler-injected — maps top-level state field → dirty-mask bit(s) */\n __maskLegend?: Record<string, number>\n /** @internal Compiler-injected — source-file location of the component() call */\n __componentMeta?: { file: string; line: number }\n /** @internal Compiler-injected — shape of the State type (for introspection) */\n __stateSchema?: object\n /** @internal Compiler-injected — Effect union schema (for introspection) */\n __effectSchema?: object\n /** @internal Compiler-injected — replaces generic Phase 1 + Phase 2 loop */\n __update?: (\n state: S,\n dirty: number,\n bindings: Binding[],\n blocks: StructuralBlock[],\n bindingsBeforePhase1: number,\n ) => void\n /** @internal Compiler-injected — per-message-type specialized handlers.\n * Bypass the entire processMessages pipeline for single-message updates. */\n __handlers?: Record<string, (inst: object, msg: unknown) => [S, E[]]>\n}\n\nexport type Send<M> = (msg: M) => void\n\n/**\n * Type-erased component definition for use at module boundaries where\n * the consumer's `S`, `M`, `E` are internal and invisible to the caller.\n *\n * Why this exists: `ComponentDef<S, M, E, D>` uses property syntax for\n * its callable fields (`init: (data: D) => ...`), and TypeScript\n * checks property syntax with strict (contravariant) variance. That's\n * the right call for user-facing type safety when authoring a\n * component (a narrower `Msg` type can't accidentally satisfy the\n * `update`'s param), but it means `ComponentDef<MyState, MyMsg, MyEffect, MyData>`\n * is NOT structurally assignable to `ComponentDef<unknown, unknown, unknown, unknown>`\n * — the `init: (data: MyData) => ...` field is contravariant in `MyData`,\n * so widening to `unknown` is rejected.\n *\n * `AnyComponentDef` (and `LazyDef<D>` below) declare the same fields\n * using **method syntax** (`init(data: D): ...`), which TypeScript\n * checks bivariantly. Concrete `ComponentDef<S, M, E, D>` assigns into\n * these structurally without any `widenDef` helper at the callsite.\n *\n * Used by every API that accepts an opaque component definition at a\n * module boundary:\n *\n * - `child({ def })`\n * - `lazy({ loader })` — returns `LazyDef<D>` so the loader's `D` survives\n * - `createOnRenderClient({ Layout })` (from `@llui/vike`)\n * - `createOnRenderHtml({ Layout })` (from `@llui/vike`)\n *\n * The `D` parameter is `unknown` here — `child()` doesn't pass init\n * data through, and `Layout` callers pass route-supplied data whose\n * shape is unknown at the type-erased boundary. Use `LazyDef<D>` when\n * you need to preserve the init data shape (the lazy loader case).\n */\nexport interface AnyComponentDef {\n name: string\n init(data: unknown): [unknown, unknown[]]\n update(state: unknown, msg: unknown): [unknown, unknown[]]\n view(h: unknown): Node[]\n onEffect?: unknown\n propsMsg?: unknown\n receives?: unknown\n __dirty?: unknown\n __renderToString?: unknown\n __msgSchema?: unknown\n __maskLegend?: unknown\n __componentMeta?: unknown\n __stateSchema?: unknown\n __effectSchema?: unknown\n __update?: unknown\n __handlers?: unknown\n}\n\n/**\n * Type-erased component definition for use at module boundaries where the\n * loaded component's S, M, E are internal and invisible to the caller.\n * Only `D` (init data) survives because the caller provides it.\n *\n * `ComponentDef<S, M, E, D>` is structurally assignable to `LazyDef<D>`\n * for any S, M, E — `view: (h: unknown) => Node[]` accepts any View via\n * contravariance, and all other fields widen to `unknown` return types.\n *\n * Used by `lazy()` as the loader's return type. Use `AnyComponentDef`\n * (above) when D is also opaque — most other adapter-layer APIs.\n */\nexport interface LazyDef<D = void> {\n name: string\n // Method syntax — TypeScript checks methods bivariantly, so\n // ComponentDef<S, M, E, D>'s concrete (state: S, msg: M) => ...\n // assigns here even though S/M ≠ unknown. Property syntax would\n // be contravariant and reject the assignment.\n init(data: D): [unknown, unknown[]]\n update(state: unknown, msg: unknown): [unknown, unknown[]]\n view(h: unknown): Node[]\n onEffect?: unknown\n propsMsg?: unknown\n receives?: unknown\n __dirty?: unknown\n __renderToString?: unknown\n __msgSchema?: unknown\n __maskLegend?: unknown\n __componentMeta?: unknown\n __stateSchema?: unknown\n __effectSchema?: unknown\n __update?: unknown\n __handlers?: unknown\n}\n\n/**\n * Maps a value shape to a reactive-props shape: every field becomes an accessor\n * `(s: S) => V`. Use for Level-1 view function signatures.\n *\n * ```ts\n * type ToolbarData = { tools: Tool[]; theme: 'light' | 'dark' }\n *\n * export function toolbar<S>(props: Props<ToolbarData, S>, send: Send<Msg>) {\n * return [div({ class: props.theme }, [each({ items: props.tools, ... })])]\n * }\n *\n * // Caller — TypeScript enforces per-field accessors; passing a raw value errors:\n * toolbar({ tools: (s: State) => s.tools, theme: (s) => s.theme }, send)\n * ```\n */\nexport type Props<T, S> = {\n [K in keyof T]: (s: S) => T[K]\n}\n\n// ── App Handle ────────────────────────────────────────────────────\n\nexport interface AppHandle {\n dispose(): void\n flush(): void\n /**\n * Dispatch a message into the mounted instance from outside its\n * normal view-bound `send` channel. Useful for adapter layers that\n * need to push updates into a long-lived instance — e.g.\n * `@llui/vike`'s persistent-layout chain pushes layout-data updates\n * into surviving layer instances on client navigation when their\n * `propsMsg` translates the new data into a state-update message.\n *\n * Messages are queued through the same path as `view`-side `send`\n * calls — they batch into the next microtask and process via the\n * normal update loop. Calling `send` after `dispose` is a no-op.\n */\n send(msg: unknown): void\n}\n\n// ── Scope ─────────────────────────────────────────────────────────\n\nexport interface Scope {\n id: number\n parent: Scope | null\n children: Scope[]\n disposers: Array<() => void>\n bindings: Binding[]\n /** Per-item updaters — called directly by each() when item changes, bypassing Phase 2 */\n itemUpdaters: Array<() => void>\n}\n\n// ── Binding ───────────────────────────────────────────────────────\n\nexport type BindingKind = 'text' | 'prop' | 'attr' | 'class' | 'style'\n\nexport interface Binding {\n mask: number\n accessor: (state: unknown) => unknown\n lastValue: unknown\n kind: BindingKind\n node: Node\n key?: string\n ownerScope: Scope\n perItem: boolean\n dead: boolean\n}\n\n// ── Structural Primitives ─────────────────────────────────────────\n\nexport interface TransitionOptions {\n enter?: (nodes: Node[]) => void | Promise<void>\n leave?: (nodes: Node[]) => void | Promise<void>\n onTransition?: (ctx: { entering: Node[]; leaving: Node[]; parent: Node }) => void | Promise<void>\n}\n\nexport interface BranchOptions<S, M = unknown> extends TransitionOptions {\n on: (s: S) => string | number | boolean\n cases: Record<string | number, (h: View<S, M>) => Node[]>\n}\n\nexport interface ShowOptions<S, M = unknown> extends TransitionOptions {\n when: (s: S) => boolean\n render: (h: View<S, M>) => Node[]\n fallback?: (h: View<S, M>) => Node[]\n}\n\n/**\n * Options for `each()`. The inherited `enter` / `leave` callbacks fire **per item**:\n * `enter(nodes)` runs after an item's DOM is inserted (including initial mount);\n * `leave(nodes)` runs before an item's DOM is removed and may return a Promise\n * to hold the DOM until the animation resolves. Setting `leave` disables the\n * bulk-clear / full-replace fast paths.\n */\n/**\n * Per-item accessor. Two access forms:\n * - `item.field` — shorthand, returns accessor for `item.current[field]`\n * - `item(t => t.expr)` — computed expressions\n *\n * In both cases the returned value is a `() => V` accessor.\n * Invoke it (`item.field()`) to read the current value imperatively.\n */\nexport type ItemAccessor<T> = {\n <R>(selector: (t: T) => R): () => R\n} & {\n [K in keyof T]-?: () => T[K]\n}\n\nexport interface EachOptions<S, T, M = unknown> extends TransitionOptions {\n items: (s: S) => T[]\n key: (item: T) => string | number\n render: (opts: {\n send: Send<M>\n item: ItemAccessor<T>\n /**\n * Plain (non-Proxy) accessor factory. Compiler-output path; avoid in user code\n * (use `item.field` / `item(fn)` — more ergonomic and bypasses Proxy when compiled).\n */\n acc: <R>(selector: (t: T) => R) => () => R\n index: () => number\n /** @internal Compiler-injected — entry reference for row factory */\n entry?: Record<string, unknown>\n }) => Node[]\n}\n\nexport interface PortalOptions {\n target: HTMLElement | string\n render: () => Node[]\n}\n\nexport interface ForeignOptions<S, M, T extends Record<string, unknown>, Instance> {\n mount: (ctx: { container: HTMLElement; send: Send<M> }) => Instance\n props: (s: S) => T\n sync:\n | ((ctx: { instance: Instance; props: T; prev: T | undefined }) => void)\n | {\n [K in keyof T]?: (ctx: { instance: Instance; value: T[K]; prev: T[K] | undefined }) => void\n }\n destroy: (instance: Instance) => void\n container?: { tag?: string; attrs?: Record<string, string> }\n}\n\nexport interface ChildOptions<S, ChildM> {\n // Type-erased via AnyComponentDef so callers can pass any concrete\n // ComponentDef<S, M, E, D> without a widening helper. The runtime\n // narrows the message shape via the user-supplied `onMsg` callback,\n // which keeps `ChildM` typed at this boundary even though the def\n // itself is opaque.\n def: AnyComponentDef\n key: string | number\n props: (s: S) => Record<string, unknown>\n onMsg?: (msg: ChildM) => unknown | null\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qEAAqE","sourcesContent":["// ── Component Definition ──────────────────────────────────────────\n\nimport type { View } from './view-helpers.js'\nimport type { StructuralBlock } from './structural.js'\nimport type { ComponentInstance } from './update-loop.js'\nimport type { DisposerEvent } from './tracking/disposer-log.js'\n\nexport interface ComponentDef<S, M, E = never, D = void> {\n name: string\n init: (data: D) => [S, E[]]\n update: (state: S, msg: M) => [S, E[]]\n view: (h: View<S, M>) => Node[]\n onEffect?: (ctx: { effect: E; send: Send<M>; signal: AbortSignal }) => void\n\n // Level 2 composition\n propsMsg?: (props: Record<string, unknown>) => M\n receives?: Record<string, (params: unknown) => M>\n\n /** @internal Compiler-injected */\n __dirty?: (oldState: S, newState: S) => number | [number, number]\n /** @internal Compiler-injected */\n __renderToString?: (state: S) => string\n /** @internal Compiler-injected */\n __msgSchema?: object\n /** @internal Compiler-injected — maps top-level state field → dirty-mask bit(s) */\n __maskLegend?: Record<string, number>\n /** @internal Compiler-injected — source-file location of the component() call */\n __componentMeta?: { file: string; line: number }\n /** @internal Compiler-injected — shape of the State type (for introspection) */\n __stateSchema?: object\n /** @internal Compiler-injected — Effect union schema (for introspection) */\n __effectSchema?: object\n /** @internal Compiler-injected — replaces generic Phase 1 + Phase 2 loop */\n __update?: (\n state: S,\n dirty: number,\n bindings: Binding[],\n blocks: StructuralBlock[],\n bindingsBeforePhase1: number,\n ) => void\n /** @internal Compiler-injected — per-message-type specialized handlers.\n * Bypass the entire processMessages pipeline for single-message updates. */\n __handlers?: Record<string, (inst: object, msg: unknown) => [S, E[]]>\n}\n\nexport type Send<M> = (msg: M) => void\n\n/**\n * Type-erased component definition for use at module boundaries where\n * the consumer's `S`, `M`, `E` are internal and invisible to the caller.\n *\n * Why this exists: `ComponentDef<S, M, E, D>` uses property syntax for\n * its callable fields (`init: (data: D) => ...`), and TypeScript\n * checks property syntax with strict (contravariant) variance. That's\n * the right call for user-facing type safety when authoring a\n * component (a narrower `Msg` type can't accidentally satisfy the\n * `update`'s param), but it means `ComponentDef<MyState, MyMsg, MyEffect, MyData>`\n * is NOT structurally assignable to `ComponentDef<unknown, unknown, unknown, unknown>`\n * — the `init: (data: MyData) => ...` field is contravariant in `MyData`,\n * so widening to `unknown` is rejected.\n *\n * `AnyComponentDef` (and `LazyDef<D>` below) declare the same fields\n * using **method syntax** (`init(data: D): ...`), which TypeScript\n * checks bivariantly. Concrete `ComponentDef<S, M, E, D>` assigns into\n * these structurally without any `widenDef` helper at the callsite.\n *\n * Used by every API that accepts an opaque component definition at a\n * module boundary:\n *\n * - `child({ def })`\n * - `lazy({ loader })` — returns `LazyDef<D>` so the loader's `D` survives\n * - `createOnRenderClient({ Layout })` (from `@llui/vike`)\n * - `createOnRenderHtml({ Layout })` (from `@llui/vike`)\n *\n * The `D` parameter is `unknown` here — `child()` doesn't pass init\n * data through, and `Layout` callers pass route-supplied data whose\n * shape is unknown at the type-erased boundary. Use `LazyDef<D>` when\n * you need to preserve the init data shape (the lazy loader case).\n */\nexport interface AnyComponentDef {\n name: string\n init(data: unknown): [unknown, unknown[]]\n update(state: unknown, msg: unknown): [unknown, unknown[]]\n view(h: unknown): Node[]\n onEffect?: unknown\n propsMsg?: unknown\n receives?: unknown\n __dirty?: unknown\n __renderToString?: unknown\n __msgSchema?: unknown\n __maskLegend?: unknown\n __componentMeta?: unknown\n __stateSchema?: unknown\n __effectSchema?: unknown\n __update?: unknown\n __handlers?: unknown\n}\n\n/**\n * Type-erased component definition for use at module boundaries where the\n * loaded component's S, M, E are internal and invisible to the caller.\n * Only `D` (init data) survives because the caller provides it.\n *\n * `ComponentDef<S, M, E, D>` is structurally assignable to `LazyDef<D>`\n * for any S, M, E — `view: (h: unknown) => Node[]` accepts any View via\n * contravariance, and all other fields widen to `unknown` return types.\n *\n * Used by `lazy()` as the loader's return type. Use `AnyComponentDef`\n * (above) when D is also opaque — most other adapter-layer APIs.\n */\nexport interface LazyDef<D = void> {\n name: string\n // Method syntax — TypeScript checks methods bivariantly, so\n // ComponentDef<S, M, E, D>'s concrete (state: S, msg: M) => ...\n // assigns here even though S/M ≠ unknown. Property syntax would\n // be contravariant and reject the assignment.\n init(data: D): [unknown, unknown[]]\n update(state: unknown, msg: unknown): [unknown, unknown[]]\n view(h: unknown): Node[]\n onEffect?: unknown\n propsMsg?: unknown\n receives?: unknown\n __dirty?: unknown\n __renderToString?: unknown\n __msgSchema?: unknown\n __maskLegend?: unknown\n __componentMeta?: unknown\n __stateSchema?: unknown\n __effectSchema?: unknown\n __update?: unknown\n __handlers?: unknown\n}\n\n/**\n * Maps a value shape to a reactive-props shape: every field becomes an accessor\n * `(s: S) => V`. Use for Level-1 view function signatures.\n *\n * ```ts\n * type ToolbarData = { tools: Tool[]; theme: 'light' | 'dark' }\n *\n * export function toolbar<S>(props: Props<ToolbarData, S>, send: Send<Msg>) {\n * return [div({ class: props.theme }, [each({ items: props.tools, ... })])]\n * }\n *\n * // Caller — TypeScript enforces per-field accessors; passing a raw value errors:\n * toolbar({ tools: (s: State) => s.tools, theme: (s) => s.theme }, send)\n * ```\n */\nexport type Props<T, S> = {\n [K in keyof T]: (s: S) => T[K]\n}\n\n// ── App Handle ────────────────────────────────────────────────────\n\nexport interface AppHandle {\n dispose(): void\n flush(): void\n /**\n * Dispatch a message into the mounted instance from outside its\n * normal view-bound `send` channel. Useful for adapter layers that\n * need to push updates into a long-lived instance — e.g.\n * `@llui/vike`'s persistent-layout chain pushes layout-data updates\n * into surviving layer instances on client navigation when their\n * `propsMsg` translates the new data into a state-update message.\n *\n * Messages are queued through the same path as `view`-side `send`\n * calls — they batch into the next microtask and process via the\n * normal update loop. Calling `send` after `dispose` is a no-op.\n */\n send(msg: unknown): void\n}\n\n// ── Scope ─────────────────────────────────────────────────────────\n\nexport interface Scope {\n id: number\n parent: Scope | null\n children: Scope[]\n disposers: Array<() => void>\n bindings: Binding[]\n /** Per-item updaters — called directly by each() when item changes, bypassing Phase 2 */\n itemUpdaters: Array<() => void>\n /**\n * @internal dev-only back-reference to the owning ComponentInstance.\n * Populated on the root scope by `installDevTools` so `disposeScope`\n * can walk up the scope chain and emit DisposerEvents into the\n * instance's `_disposerLog`. Undefined in production.\n */\n instance?: ComponentInstance\n /**\n * @internal dev-only cause hint. Structural primitives (branch, each,\n * child, mountApp teardown) set this field immediately before calling\n * `disposeScope`; the dispose path reads it once to stamp the emitted\n * DisposerEvent. Left undefined, `disposeScope` falls back to\n * `'component-unmount'`. Undefined in production.\n */\n disposalCause?: DisposerEvent['cause']\n /** @internal dev-only — populated by structural primitives for scope-tree classification */\n _kind?: 'root' | 'show' | 'each' | 'branch' | 'child' | 'portal' | 'foreign'\n}\n\nexport interface ScopeNode {\n scopeId: string\n kind: 'root' | 'show' | 'each' | 'branch' | 'child' | 'portal' | 'foreign'\n active: boolean\n children: ScopeNode[]\n}\n\n// ── Binding ───────────────────────────────────────────────────────\n\n/**\n * Binding output kinds.\n *\n * `'text' | 'prop' | 'attr' | 'class' | 'style'` write their accessor's\n * return value to the DOM. `'effect'` is a side-effect-only watcher:\n * the accessor is invoked every Phase 2 tick its mask is hit, but its\n * return value is discarded and `applyBinding` is a no-op. Used by\n * `child()` to fire the prop-diff/propsMsg cascade on parent updates\n * without the cost of stringifying the returned props bag onto a\n * detached anchor node every render.\n */\nexport type BindingKind = 'text' | 'prop' | 'attr' | 'class' | 'style' | 'effect'\n\nexport interface Binding {\n mask: number\n accessor: (state: unknown) => unknown\n lastValue: unknown\n kind: BindingKind\n node: Node\n key?: string\n ownerScope: Scope\n perItem: boolean\n dead: boolean\n}\n\n// ── Structural Primitives ─────────────────────────────────────────\n\nexport interface TransitionOptions {\n enter?: (nodes: Node[]) => void | Promise<void>\n leave?: (nodes: Node[]) => void | Promise<void>\n onTransition?: (ctx: { entering: Node[]; leaving: Node[]; parent: Node }) => void | Promise<void>\n}\n\nexport interface BranchOptions<S, M = unknown> extends TransitionOptions {\n on: (s: S) => string | number | boolean\n cases: Record<string | number, (h: View<S, M>) => Node[]>\n /**\n * @internal Set by `show()` when it delegates to `branch()`, so the\n * dev-only disposer log can report `'show-hide'` instead of the\n * default `'branch-swap'` for the leaving arm. User code should not\n * set this directly.\n */\n __disposalCause?: DisposerEvent['cause']\n}\n\nexport interface ShowOptions<S, M = unknown> extends TransitionOptions {\n when: (s: S) => boolean\n render: (h: View<S, M>) => Node[]\n fallback?: (h: View<S, M>) => Node[]\n}\n\n/**\n * Options for `each()`. The inherited `enter` / `leave` callbacks fire **per item**:\n * `enter(nodes)` runs after an item's DOM is inserted (including initial mount);\n * `leave(nodes)` runs before an item's DOM is removed and may return a Promise\n * to hold the DOM until the animation resolves. Setting `leave` disables the\n * bulk-clear / full-replace fast paths.\n */\n/**\n * Per-item accessor. Two access forms:\n * - `item.field` — shorthand, returns accessor for `item.current[field]`\n * - `item(t => t.expr)` — computed expressions\n *\n * In both cases the returned value is a `() => V` accessor.\n * Invoke it (`item.field()`) to read the current value imperatively.\n */\nexport type ItemAccessor<T> = {\n <R>(selector: (t: T) => R): () => R\n} & {\n [K in keyof T]-?: () => T[K]\n}\n\nexport interface EachOptions<S, T, M = unknown> extends TransitionOptions {\n items: (s: S) => T[]\n key: (item: T) => string | number\n render: (opts: {\n send: Send<M>\n item: ItemAccessor<T>\n /**\n * Plain (non-Proxy) accessor factory. Compiler-output path; avoid in user code\n * (use `item.field` / `item(fn)` — more ergonomic and bypasses Proxy when compiled).\n */\n acc: <R>(selector: (t: T) => R) => () => R\n index: () => number\n /** @internal Compiler-injected — entry reference for row factory */\n entry?: Record<string, unknown>\n }) => Node[]\n}\n\nexport interface PortalOptions {\n target: HTMLElement | string\n render: () => Node[]\n}\n\nexport interface ForeignOptions<S, M, T extends Record<string, unknown>, Instance> {\n mount: (ctx: { container: HTMLElement; send: Send<M> }) => Instance\n props: (s: S) => T\n sync:\n | ((ctx: { instance: Instance; props: T; prev: T | undefined }) => void)\n | {\n [K in keyof T]?: (ctx: { instance: Instance; value: T[K]; prev: T[K] | undefined }) => void\n }\n destroy: (instance: Instance) => void\n container?: { tag?: string; attrs?: Record<string, string> }\n}\n\nexport interface ChildOptions<S, ChildM> {\n // Type-erased via AnyComponentDef so callers can pass any concrete\n // ComponentDef<S, M, E, D> without a widening helper. The runtime\n // narrows the message shape via the user-supplied `onMsg` callback,\n // which keeps `ChildM` typed at this boundary even though the def\n // itself is opaque.\n def: AnyComponentDef\n key: string | number\n props: (s: S) => Record<string, unknown>\n onMsg?: (msg: ChildM) => unknown | null\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"update-loop.d.ts","sourceRoot":"","sources":["../src/update-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAKtD,eAAO,MAAM,SAAS,QAAiB,CAAA;AAMvC,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,CAAC,GAAG,EAAE;IAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,GAClE,IAAI,CAEN;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACtE,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B,KAAK,EAAE,CAAC,CAAA;IACR,cAAc,EAAE,CAAC,EAAE,CAAA;IACnB,SAAS,EAAE,KAAK,CAAA;IAChB,WAAW,EAAE,OAAO,EAAE,CAAA;IACtB,gBAAgB,EAAE,eAAe,EAAE,CAAA;IACnC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,kBAAkB,EAAE,OAAO,CAAA;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,CAAC,EAAE,CAAA;IAChB,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;IACtB,MAAM,EAAE,WAAW,CAAA;IACnB,eAAe,EAAE,eAAe,CAAA;CACjC;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7C,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC1B,IAAI,CAAC,EAAE,OAAO,EACd,WAAW,GAAE,KAAK,GAAG,IAAW,GAC/B,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAsC5B;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAiCxF;AA0GD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,iBAAiB,EACvB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAoCtB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EAAE,EACnB,oBAAoB,EAAE,MAAM,EAC5B,aAAa,CAAC,EAAE,MAAM,GACrB,IAAI,CAuCN"}
1
+ {"version":3,"file":"update-loop.d.ts","sourceRoot":"","sources":["../src/update-loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAatD,eAAO,MAAM,SAAS,QAAiB,CAAA;AAMvC,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,CAAC,GAAG,EAAE;IAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,GAClE,IAAI,CAEN;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACtE,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1B,KAAK,EAAE,CAAC,CAAA;IACR,cAAc,EAAE,CAAC,EAAE,CAAA;IACnB,SAAS,EAAE,KAAK,CAAA;IAChB,WAAW,EAAE,OAAO,EAAE,CAAA;IACtB,gBAAgB,EAAE,eAAe,EAAE,CAAA;IACnC,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,kBAAkB,EAAE,OAAO,CAAA;IAC3B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,CAAC,EAAE,CAAA;IAChB,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,CAAA;IACtB,MAAM,EAAE,WAAW,CAAA;IACnB,eAAe,EAAE,eAAe,CAAA;CAiCjC;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC7C,GAAG,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAC1B,IAAI,CAAC,EAAE,OAAO,EACd,WAAW,GAAE,KAAK,GAAG,IAAW,GAC/B,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAwC5B;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAqCxF;AA0GD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,iBAAiB,EACvB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,CAoCtB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,OAAO,EAAE,EACnB,oBAAoB,EAAE,MAAM,EAC5B,aAAa,CAAC,EAAE,MAAM,GACrB,IAAI,CAuDN"}
@@ -40,6 +40,7 @@ export function createComponentInstance(def, data, parentScope = null) {
40
40
  }
41
41
  },
42
42
  };
43
+ inst.rootScope._kind = 'root';
43
44
  return inst;
44
45
  }
45
46
  export function flushInstance(inst) {
@@ -78,6 +79,10 @@ export function _forceState(inst, newState) {
78
79
  const binding = bindings[i];
79
80
  if (binding.dead)
80
81
  continue;
82
+ if (binding.kind === 'effect') {
83
+ binding.accessor(state);
84
+ continue;
85
+ }
81
86
  const newValue = binding.accessor(state);
82
87
  if (Object.is(newValue, binding.lastValue))
83
88
  continue;
@@ -238,6 +243,19 @@ export function _runPhase2(state, dirty, bindings, bindingsBeforePhase1, compone
238
243
  const binding = bindings[i];
239
244
  if (binding.dead || (binding.mask & dirty) === 0)
240
245
  continue;
246
+ if (binding.kind === 'effect') {
247
+ // Side-effect-only: run accessor, discard return, skip the
248
+ // Object.is diff and `applyBinding` entirely. Used by child()'s
249
+ // prop-watch binding so fresh-object props accessors don't
250
+ // stringify onto a detached anchor every update.
251
+ try {
252
+ binding.accessor(state);
253
+ }
254
+ catch (e) {
255
+ throw enhanceBindingError(e, binding, componentName);
256
+ }
257
+ continue;
258
+ }
241
259
  let newValue;
242
260
  try {
243
261
  newValue = binding.accessor(state);
@@ -257,6 +275,10 @@ export function _runPhase2(state, dirty, bindings, bindingsBeforePhase1, compone
257
275
  const binding = bindings[i];
258
276
  if (binding.dead || (binding.mask & dirty) === 0)
259
277
  continue;
278
+ if (binding.kind === 'effect') {
279
+ binding.accessor(state);
280
+ continue;
281
+ }
260
282
  const newValue = binding.accessor(state);
261
283
  const last = binding.lastValue;
262
284
  if (newValue === last || (newValue !== newValue && last !== last))
@@ -326,9 +348,65 @@ function dispatchEffect(inst, effect) {
326
348
  console.log(eff.message);
327
349
  return;
328
350
  }
351
+ // Dev-only: record on the timeline / consult the mock registry.
352
+ // Short-circuits real dispatch when a mock matches. Zero cost in
353
+ // production — the guard on `_effectTimeline` is undefined unless
354
+ // `installDevTools` populated the trackers.
355
+ if (inst._effectTimeline !== undefined && dispatchEffectDev(inst, effect))
356
+ return;
329
357
  // User onEffect handler
330
358
  if (inst.def.onEffect) {
331
359
  inst.def.onEffect({ effect, send: inst.send, signal: inst.signal });
332
360
  }
333
361
  }
362
+ /**
363
+ * Dev-only effect dispatch wrapper. Records the `dispatched` phase and,
364
+ * when a mock matches, auto-delivers the mocked response through the
365
+ * effect's own `onSuccess` callback on a microtask (same timing contract
366
+ * as a real async resolve). Non-matched effects are tracked as pending
367
+ * so `llui_pending_effects` / `llui_resolve_effect` can observe them.
368
+ *
369
+ * @returns `true` when a mock matched (caller should skip the real
370
+ * dispatch) or `false` to proceed with the user-provided onEffect.
371
+ */
372
+ function dispatchEffectDev(inst, effect) {
373
+ const timeline = inst._effectTimeline;
374
+ if (timeline === undefined)
375
+ return false;
376
+ const eff = effect;
377
+ const id = newEffectId();
378
+ const type = typeof eff.type === 'string' ? eff.type : '<unknown>';
379
+ const dispatchedAt = Date.now();
380
+ const mock = inst._effectMocks?.match(effect);
381
+ if (mock) {
382
+ timeline.push({ effectId: id, type, phase: 'dispatched', timestamp: dispatchedAt });
383
+ // Auto-deliver the mocked response via the effect's onSuccess callback (if any).
384
+ // This mirrors what the real dispatch would do, so the component receives a Msg
385
+ // from the mocked effect without any network/IO happening.
386
+ const payload = effect;
387
+ if (typeof payload.onSuccess === 'function') {
388
+ const msg = payload.onSuccess(mock.response);
389
+ // Schedule delivery as a microtask so it runs after the current update
390
+ // cycle completes (same timing contract as a real async effect resolve).
391
+ Promise.resolve().then(() => inst.send(msg));
392
+ }
393
+ timeline.push({
394
+ effectId: id,
395
+ type,
396
+ phase: 'resolved-mocked',
397
+ timestamp: dispatchedAt,
398
+ durationMs: 0,
399
+ });
400
+ return true;
401
+ }
402
+ timeline.push({ effectId: id, type, phase: 'dispatched', timestamp: dispatchedAt });
403
+ inst._pendingEffects?.push({ id, type, dispatchedAt, status: 'queued', payload: effect });
404
+ return false;
405
+ }
406
+ function newEffectId() {
407
+ const cryptoObj = globalThis.crypto;
408
+ if (cryptoObj?.randomUUID)
409
+ return cryptoObj.randomUUID();
410
+ return `eff-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
411
+ }
334
412
  //# sourceMappingURL=update-loop.js.map