@llui/dom 0.0.30 → 0.0.33

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 (42) hide show
  1. package/README.md +1 -0
  2. package/dist/binding-descriptors.d.ts +126 -0
  3. package/dist/binding-descriptors.d.ts.map +1 -0
  4. package/dist/binding-descriptors.js +144 -0
  5. package/dist/binding-descriptors.js.map +1 -0
  6. package/dist/devtools.d.ts +7 -3
  7. package/dist/devtools.d.ts.map +1 -1
  8. package/dist/devtools.js +52 -19
  9. package/dist/devtools.js.map +1 -1
  10. package/dist/el-split.d.ts.map +1 -1
  11. package/dist/el-split.js +12 -0
  12. package/dist/el-split.js.map +1 -1
  13. package/dist/elements.d.ts.map +1 -1
  14. package/dist/elements.js +14 -0
  15. package/dist/elements.js.map +1 -1
  16. package/dist/hmr.d.ts.map +1 -1
  17. package/dist/hmr.js +194 -0
  18. package/dist/hmr.js.map +1 -1
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +10 -0
  22. package/dist/index.js.map +1 -1
  23. package/dist/mount.d.ts +22 -0
  24. package/dist/mount.d.ts.map +1 -1
  25. package/dist/mount.js +156 -173
  26. package/dist/mount.js.map +1 -1
  27. package/dist/primitives/sample.d.ts +16 -4
  28. package/dist/primitives/sample.d.ts.map +1 -1
  29. package/dist/primitives/sample.js +16 -4
  30. package/dist/primitives/sample.js.map +1 -1
  31. package/dist/primitives/unsafe-html.d.ts +1 -1
  32. package/dist/primitives/unsafe-html.d.ts.map +1 -1
  33. package/dist/primitives/unsafe-html.js.map +1 -1
  34. package/dist/types.d.ts +99 -5
  35. package/dist/types.d.ts.map +1 -1
  36. package/dist/types.js.map +1 -1
  37. package/dist/update-loop.d.ts.map +1 -1
  38. package/dist/update-loop.js.map +1 -1
  39. package/dist/view-helpers.d.ts +19 -3
  40. package/dist/view-helpers.d.ts.map +1 -1
  41. package/dist/view-helpers.js.map +1 -1
  42. package/package.json +1 -1
package/README.md CHANGED
@@ -44,6 +44,7 @@ mountApp(document.getElementById('app')!, Counter)
44
44
  `view` receives a single `View<S, M>` bag. Destructure what you need — `send` plus any state-bound helpers. TypeScript infers `S` from the component definition, so no per-call generics:
45
45
 
46
46
  ```typescript
47
+ // @doc-skip — illustrative shape; uses `[...]` placeholders for render results
47
48
  view: ({ send, text, show, each, branch, memo }) => [
48
49
  text(s => s.label), // s is State — inferred
49
50
  ...show({ when: s => s.visible, render: () => [...] }),
@@ -0,0 +1,126 @@
1
+ import type { ComponentInstance } from './update-loop.js';
2
+ import type { Lifetime } from './types.js';
3
+ /**
4
+ * A single agent-dispatchable variant tied to currently-rendered UI.
5
+ *
6
+ * The agent layer's `list_actions` reads `getBindingDescriptors()` to
7
+ * surface which Msg variants the LLM can usefully send right now —
8
+ * not just which the app *could* accept in principle, but which have
9
+ * a live UI binding the human user could also click. Each entry maps
10
+ * to one variant string the compiler discovered as a literal `send({
11
+ * type: '<variant>' })` call inside an event-handler arrow.
12
+ */
13
+ export interface BindingDescriptor {
14
+ variant: string;
15
+ }
16
+ /**
17
+ * Per-instance live registry. Keyed by variant; the value is a
18
+ * refcount because multiple bindings can dispatch the same variant
19
+ * (e.g. one button per item in an `each`), and the variant must
20
+ * remain "live" as long as ANY of those bindings is mounted.
21
+ *
22
+ * The compiler tags every event-handler arrow function containing a
23
+ * literal `send({type: 'X'})` call with a `__lluiVariants` array of
24
+ * the discovered variants. The runtime (in `elements.ts`) reads that
25
+ * tag at bind time and calls `registerBindingVariants(inst, lifetime,
26
+ * variants)`. Each registration increments the variant's refcount;
27
+ * an `onDispose` hook on the lifetime decrements when the binding's
28
+ * scope is torn down. `getBindingDescriptors(inst)` then returns the
29
+ * variants whose refcount is currently > 0.
30
+ *
31
+ * Refcount semantics (rather than a Set) matter for `each` loops.
32
+ * 100 rows that all bind `'Item/Remove'` produce 100 increments; the
33
+ * variant stays live until every row is unmounted, which mirrors what
34
+ * the LLM should observe — the action remains affordable as long as
35
+ * any row offers it.
36
+ */
37
+ export interface BindingDescriptorRegistry {
38
+ /**
39
+ * Variant → live refcount. Entries are deleted when the count
40
+ * reaches zero so iteration stays cheap regardless of churn over
41
+ * the lifetime of the app.
42
+ */
43
+ counts: Map<string, number>;
44
+ }
45
+ export declare function createBindingDescriptorRegistry(): BindingDescriptorRegistry;
46
+ /**
47
+ * Increment the live refcount for each variant in `variants`, and
48
+ * register a lifetime disposer that decrements them on unmount.
49
+ *
50
+ * The registry is lazily attached to the instance the first time a
51
+ * binding registers. Apps that don't bind any tagged event handlers
52
+ * never allocate the registry — `getBindingDescriptors` returns an
53
+ * empty array in that case.
54
+ */
55
+ export declare function registerBindingVariants(inst: ComponentInstance, lifetime: Lifetime, variants: readonly string[]): void;
56
+ /**
57
+ * Read the current set of live binding descriptors from the
58
+ * instance. Order is iteration order over the registry map (insertion
59
+ * order with deletions); callers that need a deterministic ordering
60
+ * should sort by `variant` themselves.
61
+ */
62
+ export declare function getBindingDescriptors(inst: ComponentInstance): BindingDescriptor[];
63
+ /**
64
+ * Library helper for `*.connect` implementations: tags an event
65
+ * handler with the variants it dispatches at runtime, so the binding
66
+ * registers them when the user spreads the bag onto an element.
67
+ *
68
+ * Resolution rules — choose whichever is defined and non-empty:
69
+ *
70
+ * 1. **`send.__lluiVariants`** (translator pattern). When the user
71
+ * passed a compiler-tagged dispatch translator like
72
+ * `(m) => dispatch({type: 'Auth/UserMenu'})`, `send` itself
73
+ * carries the user-side variants the translator forwards. We
74
+ * surface those — the agent should see what `update()` actually
75
+ * receives, not the library's internal Msg shape.
76
+ *
77
+ * 2. **`libraryVariants`** fallback. When `send` is the user's raw
78
+ * component send (no translator), the library's internal Msgs flow
79
+ * directly into `update()`, so the library's own variants ARE the
80
+ * user variants. Library author hand-lists them once per handler.
81
+ *
82
+ * Returns `fn` mutated (via `Object.assign`) so the same reference
83
+ * remains identity-equal — important for downstream code that diffs
84
+ * handlers across re-bindings.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * import { tagSend } from '@llui/dom'
89
+ *
90
+ * export function connect<S>(get, send, opts) {
91
+ * return {
92
+ * trigger: {
93
+ * onClick: tagSend(send, ['Open'], () => send({ type: 'open' })),
94
+ * },
95
+ * }
96
+ * }
97
+ * ```
98
+ */
99
+ export declare function tagSend<F extends (...args: never[]) => unknown>(send: unknown, libraryVariants: readonly string[], fn: F): F;
100
+ /**
101
+ * Compiler-emitted runtime helper. The vite-plugin's `*.connect(get,
102
+ * sendFn, ...)` pattern matcher emits a call to this function
103
+ * immediately before each connect call, with the variants statically
104
+ * discovered in `sendFn`'s body — covering the dispatch-translation
105
+ * layers that the event-handler tagger can't follow (a library
106
+ * onClick calls the user's `sendFn`, which in turn calls
107
+ * `dispatch(translatedMsg)`; static analysis of the library's onClick
108
+ * can't see across that hop).
109
+ *
110
+ * Reads the active render context's `instance` and `rootLifetime` —
111
+ * which is the right scope automatically: when invoked from the
112
+ * top-level view body, registers on the component's root scope; when
113
+ * invoked from inside an `each(...)` render callback, the active
114
+ * `rootLifetime` is the per-item scope, so the registration ties to
115
+ * that item's lifetime and unregisters on item removal.
116
+ *
117
+ * **No-op when called outside a render context.** The compiler tries
118
+ * to skip emission at module top-level, but tooling never has full
119
+ * scope visibility (re-exports, transformations, generated code), so
120
+ * the helper itself defensively short-circuits rather than throwing.
121
+ * The translator's variants simply don't surface — the app still
122
+ * functions; agents can fall back to declared `agentAffordances` or
123
+ * the message schema.
124
+ */
125
+ export declare function __registerScopeVariants(variants: readonly string[]): void;
126
+ //# sourceMappingURL=binding-descriptors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding-descriptors.d.ts","sourceRoot":"","sources":["../src/binding-descriptors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAI1C;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC5B;AAED,wBAAgB,+BAA+B,IAAI,yBAAyB,CAE3E;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,iBAAiB,EACvB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,IAAI,CAaN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,EAAE,CAMlF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,EAC7D,IAAI,EAAE,OAAO,EACb,eAAe,EAAE,SAAS,MAAM,EAAE,EAClC,EAAE,EAAE,CAAC,GACJ,CAAC,CAQH;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAUzE"}
@@ -0,0 +1,144 @@
1
+ import { addDisposer } from './lifetime.js';
2
+ import { getRenderContext } from './render-context.js';
3
+ export function createBindingDescriptorRegistry() {
4
+ return { counts: new Map() };
5
+ }
6
+ /**
7
+ * Increment the live refcount for each variant in `variants`, and
8
+ * register a lifetime disposer that decrements them on unmount.
9
+ *
10
+ * The registry is lazily attached to the instance the first time a
11
+ * binding registers. Apps that don't bind any tagged event handlers
12
+ * never allocate the registry — `getBindingDescriptors` returns an
13
+ * empty array in that case.
14
+ */
15
+ export function registerBindingVariants(inst, lifetime, variants) {
16
+ if (variants.length === 0)
17
+ return;
18
+ const registry = (inst._bindingDescriptors ??= createBindingDescriptorRegistry());
19
+ for (const v of variants) {
20
+ registry.counts.set(v, (registry.counts.get(v) ?? 0) + 1);
21
+ }
22
+ addDisposer(lifetime, () => {
23
+ for (const v of variants) {
24
+ const next = (registry.counts.get(v) ?? 0) - 1;
25
+ if (next <= 0)
26
+ registry.counts.delete(v);
27
+ else
28
+ registry.counts.set(v, next);
29
+ }
30
+ });
31
+ }
32
+ /**
33
+ * Read the current set of live binding descriptors from the
34
+ * instance. Order is iteration order over the registry map (insertion
35
+ * order with deletions); callers that need a deterministic ordering
36
+ * should sort by `variant` themselves.
37
+ */
38
+ export function getBindingDescriptors(inst) {
39
+ const reg = inst._bindingDescriptors;
40
+ if (!reg)
41
+ return [];
42
+ const out = [];
43
+ for (const variant of reg.counts.keys())
44
+ out.push({ variant });
45
+ return out;
46
+ }
47
+ /**
48
+ * Library helper for `*.connect` implementations: tags an event
49
+ * handler with the variants it dispatches at runtime, so the binding
50
+ * registers them when the user spreads the bag onto an element.
51
+ *
52
+ * Resolution rules — choose whichever is defined and non-empty:
53
+ *
54
+ * 1. **`send.__lluiVariants`** (translator pattern). When the user
55
+ * passed a compiler-tagged dispatch translator like
56
+ * `(m) => dispatch({type: 'Auth/UserMenu'})`, `send` itself
57
+ * carries the user-side variants the translator forwards. We
58
+ * surface those — the agent should see what `update()` actually
59
+ * receives, not the library's internal Msg shape.
60
+ *
61
+ * 2. **`libraryVariants`** fallback. When `send` is the user's raw
62
+ * component send (no translator), the library's internal Msgs flow
63
+ * directly into `update()`, so the library's own variants ARE the
64
+ * user variants. Library author hand-lists them once per handler.
65
+ *
66
+ * Returns `fn` mutated (via `Object.assign`) so the same reference
67
+ * remains identity-equal — important for downstream code that diffs
68
+ * handlers across re-bindings.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * import { tagSend } from '@llui/dom'
73
+ *
74
+ * export function connect<S>(get, send, opts) {
75
+ * return {
76
+ * trigger: {
77
+ * onClick: tagSend(send, ['Open'], () => send({ type: 'open' })),
78
+ * },
79
+ * }
80
+ * }
81
+ * ```
82
+ */
83
+ export function tagSend(send, libraryVariants, fn) {
84
+ const sendVariants = send
85
+ ?.__lluiVariants;
86
+ const variants = sendVariants && sendVariants.length > 0 ? sendVariants : libraryVariants;
87
+ if (variants.length > 0) {
88
+ Object.assign(fn, { __lluiVariants: variants });
89
+ }
90
+ return fn;
91
+ }
92
+ /**
93
+ * Compiler-emitted runtime helper. The vite-plugin's `*.connect(get,
94
+ * sendFn, ...)` pattern matcher emits a call to this function
95
+ * immediately before each connect call, with the variants statically
96
+ * discovered in `sendFn`'s body — covering the dispatch-translation
97
+ * layers that the event-handler tagger can't follow (a library
98
+ * onClick calls the user's `sendFn`, which in turn calls
99
+ * `dispatch(translatedMsg)`; static analysis of the library's onClick
100
+ * can't see across that hop).
101
+ *
102
+ * Reads the active render context's `instance` and `rootLifetime` —
103
+ * which is the right scope automatically: when invoked from the
104
+ * top-level view body, registers on the component's root scope; when
105
+ * invoked from inside an `each(...)` render callback, the active
106
+ * `rootLifetime` is the per-item scope, so the registration ties to
107
+ * that item's lifetime and unregisters on item removal.
108
+ *
109
+ * **No-op when called outside a render context.** The compiler tries
110
+ * to skip emission at module top-level, but tooling never has full
111
+ * scope visibility (re-exports, transformations, generated code), so
112
+ * the helper itself defensively short-circuits rather than throwing.
113
+ * The translator's variants simply don't surface — the app still
114
+ * functions; agents can fall back to declared `agentAffordances` or
115
+ * the message schema.
116
+ */
117
+ export function __registerScopeVariants(variants) {
118
+ if (variants.length === 0)
119
+ return;
120
+ // Probe the render context without throwing — the helper is allowed
121
+ // outside a view (no-op rather than fatal). `getRenderContext`
122
+ // throws when there's no context, so we pre-check with the module-
123
+ // private accessor pattern: import the same module and read the
124
+ // current context manually.
125
+ const ctx = getCurrentRenderContext();
126
+ if (!ctx || !ctx.instance)
127
+ return;
128
+ registerBindingVariants(ctx.instance, ctx.rootLifetime, variants);
129
+ }
130
+ /**
131
+ * Internal helper: read the current render context without throwing.
132
+ * Returns null when no context is active (module top-level, async
133
+ * callbacks, etc.) so callers can degrade gracefully instead of
134
+ * crashing.
135
+ */
136
+ function getCurrentRenderContext() {
137
+ try {
138
+ return getRenderContext('__registerScopeVariants');
139
+ }
140
+ catch {
141
+ return null;
142
+ }
143
+ }
144
+ //# sourceMappingURL=binding-descriptors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binding-descriptors.js","sourceRoot":"","sources":["../src/binding-descriptors.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ComponentInstance } from './update-loop.js'\nimport type { Lifetime } from './types.js'\nimport { addDisposer } from './lifetime.js'\nimport { getRenderContext } from './render-context.js'\n\n/**\n * A single agent-dispatchable variant tied to currently-rendered UI.\n *\n * The agent layer's `list_actions` reads `getBindingDescriptors()` to\n * surface which Msg variants the LLM can usefully send right now —\n * not just which the app *could* accept in principle, but which have\n * a live UI binding the human user could also click. Each entry maps\n * to one variant string the compiler discovered as a literal `send({\n * type: '<variant>' })` call inside an event-handler arrow.\n */\nexport interface BindingDescriptor {\n variant: string\n}\n\n/**\n * Per-instance live registry. Keyed by variant; the value is a\n * refcount because multiple bindings can dispatch the same variant\n * (e.g. one button per item in an `each`), and the variant must\n * remain \"live\" as long as ANY of those bindings is mounted.\n *\n * The compiler tags every event-handler arrow function containing a\n * literal `send({type: 'X'})` call with a `__lluiVariants` array of\n * the discovered variants. The runtime (in `elements.ts`) reads that\n * tag at bind time and calls `registerBindingVariants(inst, lifetime,\n * variants)`. Each registration increments the variant's refcount;\n * an `onDispose` hook on the lifetime decrements when the binding's\n * scope is torn down. `getBindingDescriptors(inst)` then returns the\n * variants whose refcount is currently > 0.\n *\n * Refcount semantics (rather than a Set) matter for `each` loops.\n * 100 rows that all bind `'Item/Remove'` produce 100 increments; the\n * variant stays live until every row is unmounted, which mirrors what\n * the LLM should observe — the action remains affordable as long as\n * any row offers it.\n */\nexport interface BindingDescriptorRegistry {\n /**\n * Variant → live refcount. Entries are deleted when the count\n * reaches zero so iteration stays cheap regardless of churn over\n * the lifetime of the app.\n */\n counts: Map<string, number>\n}\n\nexport function createBindingDescriptorRegistry(): BindingDescriptorRegistry {\n return { counts: new Map() }\n}\n\n/**\n * Increment the live refcount for each variant in `variants`, and\n * register a lifetime disposer that decrements them on unmount.\n *\n * The registry is lazily attached to the instance the first time a\n * binding registers. Apps that don't bind any tagged event handlers\n * never allocate the registry — `getBindingDescriptors` returns an\n * empty array in that case.\n */\nexport function registerBindingVariants(\n inst: ComponentInstance,\n lifetime: Lifetime,\n variants: readonly string[],\n): void {\n if (variants.length === 0) return\n const registry = (inst._bindingDescriptors ??= createBindingDescriptorRegistry())\n for (const v of variants) {\n registry.counts.set(v, (registry.counts.get(v) ?? 0) + 1)\n }\n addDisposer(lifetime, () => {\n for (const v of variants) {\n const next = (registry.counts.get(v) ?? 0) - 1\n if (next <= 0) registry.counts.delete(v)\n else registry.counts.set(v, next)\n }\n })\n}\n\n/**\n * Read the current set of live binding descriptors from the\n * instance. Order is iteration order over the registry map (insertion\n * order with deletions); callers that need a deterministic ordering\n * should sort by `variant` themselves.\n */\nexport function getBindingDescriptors(inst: ComponentInstance): BindingDescriptor[] {\n const reg = inst._bindingDescriptors\n if (!reg) return []\n const out: BindingDescriptor[] = []\n for (const variant of reg.counts.keys()) out.push({ variant })\n return out\n}\n\n/**\n * Library helper for `*.connect` implementations: tags an event\n * handler with the variants it dispatches at runtime, so the binding\n * registers them when the user spreads the bag onto an element.\n *\n * Resolution rules — choose whichever is defined and non-empty:\n *\n * 1. **`send.__lluiVariants`** (translator pattern). When the user\n * passed a compiler-tagged dispatch translator like\n * `(m) => dispatch({type: 'Auth/UserMenu'})`, `send` itself\n * carries the user-side variants the translator forwards. We\n * surface those — the agent should see what `update()` actually\n * receives, not the library's internal Msg shape.\n *\n * 2. **`libraryVariants`** fallback. When `send` is the user's raw\n * component send (no translator), the library's internal Msgs flow\n * directly into `update()`, so the library's own variants ARE the\n * user variants. Library author hand-lists them once per handler.\n *\n * Returns `fn` mutated (via `Object.assign`) so the same reference\n * remains identity-equal — important for downstream code that diffs\n * handlers across re-bindings.\n *\n * @example\n * ```ts\n * import { tagSend } from '@llui/dom'\n *\n * export function connect<S>(get, send, opts) {\n * return {\n * trigger: {\n * onClick: tagSend(send, ['Open'], () => send({ type: 'open' })),\n * },\n * }\n * }\n * ```\n */\nexport function tagSend<F extends (...args: never[]) => unknown>(\n send: unknown,\n libraryVariants: readonly string[],\n fn: F,\n): F {\n const sendVariants = (send as { __lluiVariants?: readonly string[] } | null | undefined)\n ?.__lluiVariants\n const variants = sendVariants && sendVariants.length > 0 ? sendVariants : libraryVariants\n if (variants.length > 0) {\n Object.assign(fn, { __lluiVariants: variants })\n }\n return fn\n}\n\n/**\n * Compiler-emitted runtime helper. The vite-plugin's `*.connect(get,\n * sendFn, ...)` pattern matcher emits a call to this function\n * immediately before each connect call, with the variants statically\n * discovered in `sendFn`'s body — covering the dispatch-translation\n * layers that the event-handler tagger can't follow (a library\n * onClick calls the user's `sendFn`, which in turn calls\n * `dispatch(translatedMsg)`; static analysis of the library's onClick\n * can't see across that hop).\n *\n * Reads the active render context's `instance` and `rootLifetime` —\n * which is the right scope automatically: when invoked from the\n * top-level view body, registers on the component's root scope; when\n * invoked from inside an `each(...)` render callback, the active\n * `rootLifetime` is the per-item scope, so the registration ties to\n * that item's lifetime and unregisters on item removal.\n *\n * **No-op when called outside a render context.** The compiler tries\n * to skip emission at module top-level, but tooling never has full\n * scope visibility (re-exports, transformations, generated code), so\n * the helper itself defensively short-circuits rather than throwing.\n * The translator's variants simply don't surface — the app still\n * functions; agents can fall back to declared `agentAffordances` or\n * the message schema.\n */\nexport function __registerScopeVariants(variants: readonly string[]): void {\n if (variants.length === 0) return\n // Probe the render context without throwing — the helper is allowed\n // outside a view (no-op rather than fatal). `getRenderContext`\n // throws when there's no context, so we pre-check with the module-\n // private accessor pattern: import the same module and read the\n // current context manually.\n const ctx = getCurrentRenderContext()\n if (!ctx || !ctx.instance) return\n registerBindingVariants(ctx.instance, ctx.rootLifetime, variants)\n}\n\n/**\n * Internal helper: read the current render context without throwing.\n * Returns null when no context is active (module top-level, async\n * callbacks, etc.) so callers can degrade gracefully instead of\n * crashing.\n */\nfunction getCurrentRenderContext(): import('./render-context.js').RenderContext | null {\n try {\n return getRenderContext('__registerScopeVariants')\n } catch {\n return null\n }\n}\n"]}
@@ -28,9 +28,13 @@ export declare function enableDevTools(): void;
28
28
  * by `@llui/mcp`. If the MCP server is running, the response gives
29
29
  * us the actual port — we connect immediately. This avoids the race
30
30
  * where HMR events fire before the listener registers, and handles
31
- * cases where MCP runs on a non-default port.
32
- * 2. **Compile-time fallback**: if the status endpoint is unavailable
33
- * (404, network error, non-Vite environment), we attempt a single
31
+ * cases where MCP runs on a non-default port. When the canonical
32
+ * path is shadowed (e.g. `@cloudflare/vite-plugin` routes every
33
+ * HTTP request to the worker), the client falls back to
34
+ * `/cdn-cgi/llui_mcp_status` which the Vite plugin also registers
35
+ * — Cloudflare lets `/cdn-cgi/*` paths through to the dev server.
36
+ * 2. **Compile-time fallback**: if both endpoints are unavailable
37
+ * (network error, non-Vite environment), we attempt a single
34
38
  * connection to the compiled-in `port` parameter as a best-effort.
35
39
  *
36
40
  * Either way: no retry loop. If both fail, `window.__lluiConnect(port?)`
@@ -1 +1 @@
1
- {"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"devtools.d.ts","sourceRoot":"","sources":["../src/devtools.ts"],"names":[],"mappings":"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"}
package/dist/devtools.js CHANGED
@@ -135,9 +135,13 @@ function connectRelay(port, isInitial) {
135
135
  * by `@llui/mcp`. If the MCP server is running, the response gives
136
136
  * us the actual port — we connect immediately. This avoids the race
137
137
  * where HMR events fire before the listener registers, and handles
138
- * cases where MCP runs on a non-default port.
139
- * 2. **Compile-time fallback**: if the status endpoint is unavailable
140
- * (404, network error, non-Vite environment), we attempt a single
138
+ * cases where MCP runs on a non-default port. When the canonical
139
+ * path is shadowed (e.g. `@cloudflare/vite-plugin` routes every
140
+ * HTTP request to the worker), the client falls back to
141
+ * `/cdn-cgi/llui_mcp_status` which the Vite plugin also registers
142
+ * — Cloudflare lets `/cdn-cgi/*` paths through to the dev server.
143
+ * 2. **Compile-time fallback**: if both endpoints are unavailable
144
+ * (network error, non-Vite environment), we attempt a single
141
145
  * connection to the compiled-in `port` parameter as a best-effort.
142
146
  *
143
147
  * Either way: no retry loop. If both fail, `window.__lluiConnect(port?)`
@@ -156,23 +160,22 @@ export function startRelay(port = 5200) {
156
160
  g.__lluiConnect = (p) => {
157
161
  connectRelay(p ?? relayPort, false);
158
162
  };
159
- // Try the Vite middleware first (knows the actual port from the marker file)
160
163
  if (typeof fetch !== 'undefined') {
161
- fetch('/__llui_mcp_status')
162
- .then((res) => (res.ok ? res.json() : null))
163
- .then((data) => {
164
- if (data && typeof data.port === 'number') {
165
- relayPort = data.port;
166
- connectRelay(data.port, true);
167
- }
168
- else {
169
- // Endpoint replied 404 MCP not running. Don't fall back to the
170
- // compile-time port; the HMR event will fire if MCP starts later.
171
- }
172
- })
173
- .catch(() => {
174
- // Network error or non-Vite environment fall back to compile-time port
175
- connectRelay(port, true);
164
+ void resolveMcpStatus().then((result) => {
165
+ if (result.kind === 'found') {
166
+ relayPort = result.port;
167
+ connectRelay(result.port, true);
168
+ }
169
+ else if (result.kind === 'network-error') {
170
+ // No Vite server reachable (e.g., production build, test
171
+ // harness without a server). Fall back to the compile-time
172
+ // port; the WS connect will either succeed or quietly fail.
173
+ connectRelay(port, true);
174
+ }
175
+ // result.kind === 'not-running' → both endpoints 404'd. MCP isn't
176
+ // active. Don't fall back to the compile-time port; the HMR
177
+ // `llui:mcp-ready` event fires if MCP starts later, and manual
178
+ // `window.__lluiConnect()` is the escape hatch.
176
179
  });
177
180
  }
178
181
  else {
@@ -180,6 +183,36 @@ export function startRelay(port = 5200) {
180
183
  connectRelay(port, true);
181
184
  }
182
185
  }
186
+ /**
187
+ * Try the canonical Vite middleware path; if it 404s (Cloudflare
188
+ * plugin's catch-all routes everything to the worker), fall back to
189
+ * `/cdn-cgi/llui_mcp_status` which the Vite plugin also registers.
190
+ *
191
+ * Distinguishes "MCP not running" (404 from a real Vite server) from
192
+ * "no Vite server" (fetch threw). Callers handle these differently —
193
+ * the former should NOT fall back to the compile-time port (avoids
194
+ * spurious WS connection attempts), the latter SHOULD.
195
+ */
196
+ async function resolveMcpStatus() {
197
+ let allThrew = true;
198
+ for (const path of ['/__llui_mcp_status', '/cdn-cgi/llui_mcp_status']) {
199
+ try {
200
+ const res = await fetch(path);
201
+ // We got a response — even a 404 means a server is live; don't
202
+ // treat this as a network error.
203
+ allThrew = false;
204
+ if (!res.ok)
205
+ continue;
206
+ const data = (await res.json());
207
+ if (typeof data.port === 'number')
208
+ return { kind: 'found', port: data.port };
209
+ }
210
+ catch {
211
+ // Network error on this path — try the next.
212
+ }
213
+ }
214
+ return allThrew ? { kind: 'network-error' } : { kind: 'not-running' };
215
+ }
183
216
  function diffNodes(client, server, path, out) {
184
217
  const clientAttrs = new Map(Array.from(client.attributes).map((a) => [a.name, a.value]));
185
218
  const serverAttrs = new Map(Array.from(server.attributes).map((a) => [a.name, a.value]));