kerfjs 5.0.0-beta.4 → 5.0.0-beta.40

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/CHANGELOG.md +344 -116
  2. package/README.md +43 -23
  3. package/ai/cursorrules +87 -48
  4. package/ai/manifest.json +10 -7
  5. package/ai/skill.md +101 -67
  6. package/dist/actions.js +2 -2
  7. package/dist/actions.js.map +1 -1
  8. package/dist/array-signal.js +1 -1
  9. package/dist/async.js +22 -19
  10. package/dist/async.js.map +1 -1
  11. package/dist/attach.js +3 -1
  12. package/dist/attach.js.map +1 -1
  13. package/dist/{chunk-QIP723L4.js → chunk-5WRGJZV6.js} +3 -2
  14. package/dist/chunk-5WRGJZV6.js.map +1 -0
  15. package/dist/{chunk-GY4XV2UV.js → chunk-BDX3R4OM.js} +3 -2
  16. package/dist/chunk-BDX3R4OM.js.map +1 -0
  17. package/dist/{chunk-HW7KSM2Y.js → chunk-CEQMZYLR.js} +1 -1
  18. package/dist/{chunk-HW7KSM2Y.js.map → chunk-CEQMZYLR.js.map} +1 -1
  19. package/dist/{chunk-SVATPF5R.js → chunk-DLY444MN.js} +121 -49
  20. package/dist/chunk-DLY444MN.js.map +1 -0
  21. package/dist/{chunk-KPXIOG2C.js → chunk-E5R5GNKE.js} +14 -4
  22. package/dist/chunk-E5R5GNKE.js.map +1 -0
  23. package/dist/{chunk-LVH3GC6B.js → chunk-ELXVRKY2.js} +3 -3
  24. package/dist/chunk-ELXVRKY2.js.map +1 -0
  25. package/dist/{chunk-ZDCJZCNO.js → chunk-JRKE6XEK.js} +37 -16
  26. package/dist/chunk-JRKE6XEK.js.map +1 -0
  27. package/dist/{chunk-UZJ6I4T6.js → chunk-MK42GLPV.js} +1 -1
  28. package/dist/chunk-MK42GLPV.js.map +1 -0
  29. package/dist/{chunk-V46JKE44.js → chunk-WKIPLNVO.js} +1 -1
  30. package/dist/chunk-WKIPLNVO.js.map +1 -0
  31. package/dist/{chunk-U6FK33SG.js → chunk-Y2FOYPBV.js} +2 -2
  32. package/dist/{chunk-U6FK33SG.js.map → chunk-Y2FOYPBV.js.map} +1 -1
  33. package/dist/{chunk-KZJXHFIB.js → chunk-ZOIERTUW.js} +3 -3
  34. package/dist/chunk-ZOIERTUW.js.map +1 -0
  35. package/dist/dev.js +64 -17
  36. package/dist/dev.js.map +1 -1
  37. package/dist/html.js +5 -4
  38. package/dist/html.js.map +1 -1
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.js +23 -14
  41. package/dist/index.js.map +1 -1
  42. package/dist/jsx-runtime.d.ts +12 -5
  43. package/dist/jsx-runtime.js +1 -1
  44. package/dist/list.js +43 -14
  45. package/dist/list.js.map +1 -1
  46. package/dist/overlay.js +99 -32
  47. package/dist/overlay.js.map +1 -1
  48. package/dist/remount.js +2 -2
  49. package/dist/router.js +33 -10
  50. package/dist/router.js.map +1 -1
  51. package/dist/scope.js +5 -4
  52. package/dist/scope.js.map +1 -1
  53. package/dist/testing.js +1 -1
  54. package/dist/timing.js +1 -1
  55. package/dist/timing.js.map +1 -1
  56. package/llms.txt +6 -2
  57. package/package.json +32 -7
  58. package/setup/cli.mjs +90 -0
  59. package/setup/index.d.mts +37 -0
  60. package/setup/index.mjs +1347 -0
  61. package/setup/jsonc.mjs +201 -0
  62. package/setup/state.schema.json +56 -0
  63. package/dist/chunk-GY4XV2UV.js.map +0 -1
  64. package/dist/chunk-KPXIOG2C.js.map +0 -1
  65. package/dist/chunk-KZJXHFIB.js.map +0 -1
  66. package/dist/chunk-LVH3GC6B.js.map +0 -1
  67. package/dist/chunk-QIP723L4.js.map +0 -1
  68. package/dist/chunk-SVATPF5R.js.map +0 -1
  69. package/dist/chunk-UZJ6I4T6.js.map +0 -1
  70. package/dist/chunk-V46JKE44.js.map +0 -1
  71. package/dist/chunk-ZDCJZCNO.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/segment.ts"],"names":[],"mappings":"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","file":"chunk-BDX3R4OM.js","sourcesContent":["/**\n * `Segment` — kerf's structured render output.\n *\n * The JSX runtime emits a `SafeHtml` wrapping a `Segment`. Most renders\n * produce a single static segment (just an HTML string), which behaves\n * exactly like a string for backward compatibility. When the tree\n * contains a list (`each()`) or a parent whose children include a list,\n * the runtime emits a structured segment that `mount()` can dispatch\n * on — running its native keyed reconciler for the list parts and\n * leaving the static surrounds to the general-purpose diff.\n *\n * Why have a structured form at all: the perf bottleneck for huge\n * keyed lists isn't the per-row JSX work (which `each()` already\n * memoizes). It's that flattening every render's whole tree to one\n * big HTML string forces a full `innerHTML` parse and a tree walk\n * over rows we know are unchanged. The segment shape lets mount()\n * skip both for the list parts.\n */\n\nimport type { Binding } from './bindings.js';\n\nexport type Segment = StaticSegment | ListSegment | MixedSegment;\n\nexport interface StaticSegment {\n kind: 'static';\n html: string;\n}\n\nexport interface ListItem {\n /**\n * The row's object identity. Used by the reconciler to match new items\n * against live DOM nodes across renders. Unchanged ref → reuse the\n * existing live node; replaced ref → build a fresh node.\n */\n ref: object;\n /**\n * KF-294: the row's fine-grained binding specs (signals in row attrs/text).\n * Undefined for granular-path rows (which snapshot in this spike). The\n * snapshot reconciler wires these to the fresh row node and disposes them\n * when the row is removed.\n */\n bindings?: Binding[];\n /**\n * Optional cache-invalidation key that captures external state affecting\n * this row's render (e.g. selection class). Different cacheKey on the\n * same `ref` triggers a cache miss for that row. `undefined` when the\n * user didn't pass a `key` callback to `each()`.\n */\n cacheKey: unknown;\n html: string;\n}\n\nexport interface ListSegment {\n kind: 'list';\n id: string;\n items: ListItem[];\n /**\n * Optional granular patches (KF-92). When present, the list reconciler\n * applies these directly to the existing binding instead of doing a\n * full classify+reconcile pass. Emitted by `each()` when bound to an\n * `arraySignal`. Mutually exclusive with the `items` snapshot in the\n * sense that the snapshot is treated as informational/fall-back when\n * patches are present.\n */\n patches?: ArrayPatchInternal[];\n /**\n * KF-388: the identity of the data this list renders — the `arraySignal`\n * instance, or `undefined` for a plain array.\n *\n * A list's `id` is its call-order index, so a render that changes how many\n * `each()` calls precede this one hands this segment a DIFFERENT list's\n * binding. Patches are only meaningful against the binding they were queued\n * for, so the reconciler compares this against the binding's recorded source\n * before trusting the patch queue. It is an identity check, not a value\n * check — the instance is never read.\n */\n source?: object;\n}\n\n/**\n * Internal patch shape used inside list segments. Mirrors `ArrayPatch<T>`\n * from `array-signal.ts` but typed against `object` so the segment layer\n * doesn't need to be generic. `update` / `insert` patches carry the row's\n * pre-rendered HTML — `each()` renders them at JSX-evaluation time inside a\n * try/catch so a throwing render falls back to the snapshot path (KF-99)\n * instead of leaving the signal and DOM divergent.\n */\nexport type ArrayPatchInternal =\n | {\n type: 'update';\n index: number;\n item: object;\n html: string;\n bindings?: Binding[];\n }\n | {\n type: 'insert';\n index: number;\n item: object;\n html: string;\n bindings?: Binding[];\n }\n | { type: 'remove'; index: number }\n | { type: 'move'; from: number; to: number }\n | { type: 'replace'; items: readonly object[] };\n\n/**\n * Narrowed patch aliases. Array indexing loses the union discriminant, so\n * the granular reconciler casts through these instead of restating the full\n * object type at every site — a field rename is then a one-place edit.\n */\nexport type UpdatePatch = Extract<ArrayPatchInternal, { type: 'update' }>;\nexport type InsertPatch = Extract<ArrayPatchInternal, { type: 'insert' }>;\n\nexport interface MixedSegment {\n kind: 'mixed';\n parts: Segment[];\n}\n\n/**\n * Flatten a segment to a complete HTML string. Used for first render\n * (bulk innerHTML), for SSR-style consumption via `toString()`, and\n * for diagnostics.\n *\n * If `withMarkers` is set, list segments are wrapped in\n * `<!--kf-list:{id}-->` comments so the post-parse walk can find each\n * list's live parent. Plain (non-marker) flatten is what JSX consumers\n * see when they call `.toString()` on the SafeHtml.\n */\n/**\n * Comment-marker prefix emitted before each list (`<!--kf-list:{id}-->`).\n * `mount()` consumes it when binding lists from the live DOM — the emitter\n * (here) and the consumer must agree byte-for-byte, so both import this one\n * constant. Part of the reserved marker namespace (see `bindings.ts`).\n */\nexport const LIST_MARKER_PREFIX = 'kf-list:';\n\nexport function flatten(segment: Segment, withMarkers: boolean): string {\n if (segment.kind === 'static') return segment.html;\n if (segment.kind === 'list') {\n const items = segment.items.map((i) => i.html).join('');\n return withMarkers\n ? `<!--${LIST_MARKER_PREFIX}${segment.id}-->${items}`\n : items;\n }\n return segment.parts.map((p) => flatten(p, withMarkers)).join('');\n}\n\n/**\n * Variant of `flatten` for the static-only diff path on subsequent\n * renders. Lists are reduced to a single marker comment with no items\n * inside — the actual list children stay in the live DOM and are\n * reconciled separately. Keeping list items out of this string is\n * what makes the morph cheap on huge lists where most rows are\n * unchanged.\n */\nexport function flattenWithoutListItems(segment: Segment): string {\n if (segment.kind === 'static') return segment.html;\n if (segment.kind === 'list')\n return `<!--${LIST_MARKER_PREFIX}${segment.id}-->`;\n return segment.parts.map(flattenWithoutListItems).join('');\n}\n\n/** Collect every `ListSegment` in the tree, keyed by its id. */\nexport function collectLists(\n segment: Segment,\n out: Map<string, ListSegment> = new Map(),\n): Map<string, ListSegment> {\n if (segment.kind === 'list') out.set(segment.id, segment);\n else if (segment.kind === 'mixed') {\n for (const part of segment.parts) collectLists(part, out);\n }\n return out;\n}\n\n/**\n * Combine a list of child segments into the smallest equivalent\n * representation: collapses adjacent statics into one static, returns\n * a single static if everything is static, otherwise a mixed segment\n * with statics coalesced.\n */\nexport function mergeChildSegments(parts: Segment[]): Segment {\n if (parts.length === 0) return { kind: 'static', html: '' };\n if (parts.every((p) => p.kind === 'static')) {\n return {\n kind: 'static',\n html: parts.map((p) => (p as StaticSegment).html).join(''),\n };\n }\n const merged: Segment[] = [];\n let coalesced = '';\n for (const p of parts) {\n if (p.kind === 'static') {\n coalesced += p.html;\n } else {\n if (coalesced !== '') {\n merged.push({ kind: 'static', html: coalesced });\n coalesced = '';\n }\n merged.push(p);\n }\n }\n if (coalesced !== '') merged.push({ kind: 'static', html: coalesced });\n return { kind: 'mixed', parts: merged };\n}\n\n/**\n * Wrap a child segment with surrounding open/close tags from the\n * parent JSX element. Used by the JSX runtime when constructing\n * `_jsx(tag, ...)` output.\n */\nexport function wrapWithTags(\n child: Segment,\n openTag: string,\n closeTag: string,\n): Segment {\n if (child.kind === 'static') {\n return { kind: 'static', html: openTag + child.html + closeTag };\n }\n if (child.kind === 'mixed') {\n return {\n kind: 'mixed',\n parts: [\n { kind: 'static', html: openTag },\n ...child.parts,\n { kind: 'static', html: closeTag },\n ],\n };\n }\n return {\n kind: 'mixed',\n parts: [\n { kind: 'static', html: openTag },\n child,\n { kind: 'static', html: closeTag },\n ],\n };\n}\n"]}
@@ -11,4 +11,4 @@ function clearDevHooks() {
11
11
 
12
12
  export { clearDevHooks, devHooks, installDevHooks };
13
13
 
14
- //# sourceMappingURL=chunk-HW7KSM2Y.js.map
14
+ //# sourceMappingURL=chunk-CEQMZYLR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/dev-hooks.ts"],"names":[],"mappings":";AA8IO,IAAM,WAAqB;AAS3B,SAAS,gBAAgB,KAAA,EAAuB;AACrD,EAAA,MAAA,CAAO,MAAA,CAAO,UAAU,KAAK,CAAA;AAC/B;AAOO,SAAS,aAAA,GAAsB;AACpC,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,EAAG;AACvC,IAAA,OAAQ,SAAqC,GAAG,CAAA;AAAA,EAClD;AACF","file":"chunk-HW7KSM2Y.js","sourcesContent":["/**\n * The dev-hook registry — kerf's single seam between production code and the\n * opt-in development diagnostics.\n *\n * ## Why this exists\n *\n * kerf used to INFER whether it was running in development, by reading\n * `globalThis.process?.env?.NODE_ENV` through `utils/devMode.ts`. That\n * inference cannot be made correct, and it was wrong in the most common case:\n * bundlers substitute the BARE `process.env.NODE_ENV` token and never create a\n * `globalThis.process` object for browser targets, so the read returned\n * `undefined` and `undefined !== 'production'` resolved to DEVELOPMENT inside\n * production browser bundles.\n *\n * It also could not be fixed by rewriting the expression. Only the\n * *production* answer can be made static: `X && false` folds to a constant for\n * any side-effect-free `X`, while `X && true` does not. So any form that a\n * bundler can eliminate is also a form that treats \"no `process` binding\" as\n * production — which silently disables every warning in the no-build/CDN path\n * and in browser dev bundles.\n *\n * The fix is to stop guessing. Every environment already has a correct,\n * statically-foldable dev flag; what none of them offers is a way to hand that\n * flag to a *library*. So the consumer writes the conditional, in their own\n * code, with their own flag:\n *\n * ```js\n * if (import.meta.env.DEV) await import('kerfjs/dev'); // Vite\n * if (process.env.NODE_ENV !== 'production') await import('kerfjs/dev');\n * ```\n *\n * Because that condition folds to `false` in the consumer's production build,\n * the entire statement is eliminated and the dev chunk is never emitted or\n * fetched. Installation IS the development signal — there is nothing left to\n * detect, and no environment kerf can be wrong about.\n *\n * ## The contract\n *\n * Core modules never import a `dev-*` module. They read a nullable slot off\n * `devHooks` and call through it:\n *\n * ```ts\n * devHooks.listRebind?.(id, marker.parentElement as Element);\n * ```\n *\n * When nothing is installed every slot is `undefined`, so the cost is one\n * property read per call site and the `dev-*` modules are unreachable from the\n * main entry — which is what lets a bundler drop them. This is why the gate\n * lives at the CALL SITE rather than inside each warner: an unconditional call\n * into a self-gating warner keeps the module reachable no matter how the gate\n * is written, so no amount of dead-code elimination can reclaim it.\n *\n * Slots ending in `Enabled` are predicates rather than warnings. They exist for\n * the handful of call sites that must decide whether to do *expensive\n * preparatory work* — capturing the previous render's binding list, allocating\n * a per-render `Map` — before there is anything to warn about. Core must check\n * those before paying the cost, exactly as it checked the old `isOptedIn()`\n * exports.\n *\n * Each opt-in warner keeps its own internal switch check through `devFlag()`;\n * an `enableWarnings()` override wins over the matching `KERF_DEV_WARN_*`\n * environment variable. Installation decides whether the diagnostics are\n * *present*; the opt-in warner decides whether it is *switched on*. Always-on\n * hooks skip that second gate.\n *\n * @see docs/11-dev-warnings.md\n */\n\nimport type { Binding } from './bindings.js';\nimport type { ListBinding } from './list-binding.js';\nimport type { Signal } from './reactive.js';\n\n/** Per-mount / per-store one-shot dedup flag, owned by the caller in core. */\nexport interface WarnOnceContext {\n warned: boolean;\n}\n\nexport interface DevHooks {\n // --- reactive.ts -------------------------------------------------------\n /**\n * Replaces `signal()`'s constructor so writes to never-subscribed signals can\n * warn. Resolved at signal-CREATION time, so signals created before the dev\n * entry is installed stay plain — see `signalsCreatedBeforeInstall`.\n */\n signalFactory?: <T>(value: T) => Signal<T>;\n /**\n * Wraps an `effect()` body so `delegate()` can detect that it is running\n * inside one. Returns the body to actually run.\n */\n wrapEffect?: (fn: () => void | (() => void)) => () => void | (() => void);\n\n // --- delegate.ts -------------------------------------------------------\n delegateInEffect?: (fn: 'delegate' | 'delegateCapture') => void;\n\n // --- store.ts ----------------------------------------------------------\n narrowSet?: (prev: unknown, next: unknown, ctx: WarnOnceContext) => void;\n /** Deep read-only proxy for the `get()` snapshot, so stray writes throw. */\n storeReadonly?: <T extends object>(state: T) => T;\n /** Unwraps a proxy handed back through `set({ ...get() })`. */\n storeToRaw?: <T>(next: T) => T;\n\n // --- mount.ts ----------------------------------------------------------\n listenerRebuild?: (rootEl: Element) => MutationObserver | null;\n listIdShift?: (id: string) => void;\n parserRepair?: (html: string) => void;\n staleBindingEnabled?: () => boolean;\n staleBinding?: (prevWired: readonly Binding[], current: readonly Binding[]) => void;\n listInvariantsEnabled?: () => boolean;\n listInvariants?: (\n rootEl: Element,\n bindings: ReadonlyMap<string, ListBinding>,\n expectedCounts?: ReadonlyMap<string, number>,\n ) => void;\n valueOnlyRerender?: (prevHtml: string, nextHtml: string, ctx: WarnOnceContext) => void;\n listRebind?: (id: string, liveParent: Element) => void;\n eachInMorphSkip?: (id: string, liveParent: Element, rootEl: Element) => void;\n missingRowKey?: (\n rowEl: Element,\n rowHtml: string,\n binding: { warnedMissingKey?: boolean },\n ) => void;\n\n // --- each.ts -----------------------------------------------------------\n staleIndexEnabled?: () => boolean;\n staleIndex?: (id: string) => void;\n duplicateCacheKeys?: (id: string, segItems: readonly { cacheKey: unknown }[]) => void;\n\n // --- utils/url-screen.ts -----------------------------------------------\n /**\n * When installed, a screened URL throws instead of warning-and-dropping.\n * A slot rather than a boolean so the check stays uniform with the rest.\n */\n urlScreenThrow?: (message: string) => never;\n}\n\n/**\n * The live slot table. Mutable by design — this is the fourth sanctioned\n * module-level mutable location (Design rule 5), and like `store.ts:REGISTRY`\n * it depends on there being exactly ONE copy at runtime. `tsup`'s\n * `splitting: true` guarantees that: shared modules are promoted into a single\n * chunk that both the main entry and the `kerfjs/dev` entry import.\n */\nexport const devHooks: DevHooks = {};\n\n/**\n * Install (or extend) the dev hooks. Called by the `kerfjs/dev` entry; not part\n * of the public API surface.\n *\n * Merges rather than replaces, so a consumer can install the standard bundle\n * and then override a single slot in a test.\n */\nexport function installDevHooks(hooks: DevHooks): void {\n Object.assign(devHooks, hooks);\n}\n\n/**\n * Remove every installed hook. Exists for test isolation — a suite that asserts\n * the not-installed (production-shaped) path needs to get back to a clean slate\n * without reloading modules.\n */\nexport function clearDevHooks(): void {\n for (const key of Object.keys(devHooks)) {\n delete (devHooks as Record<string, unknown>)[key];\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/dev-hooks.ts"],"names":[],"mappings":";AAwJO,IAAM,WAAqB;AAS3B,SAAS,gBAAgB,KAAA,EAAuB;AACrD,EAAA,MAAA,CAAO,MAAA,CAAO,UAAU,KAAK,CAAA;AAC/B;AAOO,SAAS,aAAA,GAAsB;AACpC,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,EAAG;AACvC,IAAA,OAAQ,SAAqC,GAAG,CAAA;AAAA,EAClD;AACF","file":"chunk-CEQMZYLR.js","sourcesContent":["/**\n * The dev-hook registry — kerf's single seam between production code and the\n * opt-in development diagnostics.\n *\n * ## Why this exists\n *\n * kerf used to INFER whether it was running in development, by reading\n * `globalThis.process?.env?.NODE_ENV` through `utils/devMode.ts`. That\n * inference cannot be made correct, and it was wrong in the most common case:\n * bundlers substitute the BARE `process.env.NODE_ENV` token and never create a\n * `globalThis.process` object for browser targets, so the read returned\n * `undefined` and `undefined !== 'production'` resolved to DEVELOPMENT inside\n * production browser bundles.\n *\n * It also could not be fixed by rewriting the expression. Only the\n * *production* answer can be made static: `X && false` folds to a constant for\n * any side-effect-free `X`, while `X && true` does not. So any form that a\n * bundler can eliminate is also a form that treats \"no `process` binding\" as\n * production — which silently disables every warning in the no-build/CDN path\n * and in browser dev bundles.\n *\n * The fix is to stop guessing. Every environment already has a correct,\n * statically-foldable dev flag; what none of them offers is a way to hand that\n * flag to a *library*. So the consumer writes the conditional, in their own\n * code, with their own flag:\n *\n * ```js\n * if (import.meta.env.DEV) await import('kerfjs/dev'); // Vite\n * if (process.env.NODE_ENV !== 'production') await import('kerfjs/dev');\n * ```\n *\n * Because that condition folds to `false` in the consumer's production build,\n * the entire statement is eliminated and the dev chunk is never emitted or\n * fetched. Installation IS the development signal — there is nothing left to\n * detect, and no environment kerf can be wrong about.\n *\n * ## The contract\n *\n * Core modules never import a `dev-*` module. They read a nullable slot off\n * `devHooks` and call through it:\n *\n * ```ts\n * devHooks.listRebind?.(id, marker.parentElement as Element);\n * ```\n *\n * When nothing is installed every slot is `undefined`, so the cost is one\n * property read per call site and the `dev-*` modules are unreachable from the\n * main entry — which is what lets a bundler drop them. This is why the gate\n * lives at the CALL SITE rather than inside each warner: an unconditional call\n * into a self-gating warner keeps the module reachable no matter how the gate\n * is written, so no amount of dead-code elimination can reclaim it.\n *\n * Slots ending in `Enabled` are predicates rather than warnings. They exist for\n * the handful of call sites that must decide whether to do *expensive\n * preparatory work* — capturing the previous render's binding list, allocating\n * a per-render `Map` — before there is anything to warn about. Core must check\n * those before paying the cost, exactly as it checked the old `isOptedIn()`\n * exports.\n *\n * Each opt-in warner keeps its own internal switch check through `devFlag()`;\n * an `enableWarnings()` override wins over the matching `KERF_DEV_WARN_*`\n * environment variable. Installation decides whether the diagnostics are\n * *present*; the opt-in warner decides whether it is *switched on*. Always-on\n * hooks skip that second gate.\n *\n * @see docs/11-dev-warnings.md\n */\n\nimport type { Binding } from './bindings.js';\nimport type { ListBinding } from './list-binding.js';\nimport type { Signal } from './reactive.js';\n\n/** Per-mount / per-store one-shot dedup flag, owned by the caller in core. */\nexport interface WarnOnceContext {\n warned: boolean;\n}\n\nexport interface DevHooks {\n // --- reactive.ts -------------------------------------------------------\n /**\n * Replaces `signal()`'s constructor so writes to never-subscribed signals can\n * warn. Resolved at signal-CREATION time, so signals created before the dev\n * entry is installed stay plain — see `signalsCreatedBeforeInstall`.\n */\n signalFactory?: <T>(value: T) => Signal<T>;\n /**\n * Wraps an `effect()` body so `delegate()` can detect that it is running\n * inside one. Returns the body to actually run.\n */\n wrapEffect?: (fn: () => void | (() => void)) => () => void | (() => void);\n\n // --- delegate.ts -------------------------------------------------------\n delegateInEffect?: (fn: 'delegate' | 'delegateCapture') => void;\n\n // --- store.ts ----------------------------------------------------------\n narrowSet?: (prev: unknown, next: unknown, ctx: WarnOnceContext) => void;\n /** Deep read-only proxy for the `get()` snapshot, so stray writes throw. */\n storeReadonly?: <T extends object>(state: T) => T;\n /** Unwraps a proxy handed back through `set({ ...get() })`. */\n storeToRaw?: <T>(next: T) => T;\n\n // --- mount.ts ----------------------------------------------------------\n listenerRebuild?: (rootEl: Element) => MutationObserver | null;\n listIdShift?: (id: string) => void;\n parserRepair?: (html: string) => void;\n staleBindingEnabled?: () => boolean;\n staleBinding?: (\n prevWired: readonly Binding[],\n current: readonly Binding[],\n ) => void;\n listInvariantsEnabled?: () => boolean;\n listInvariants?: (\n rootEl: Element,\n bindings: ReadonlyMap<string, ListBinding>,\n expectedCounts?: ReadonlyMap<string, number>,\n ) => void;\n valueOnlyRerender?: (\n prevHtml: string,\n nextHtml: string,\n ctx: WarnOnceContext,\n ) => void;\n listRebind?: (id: string, liveParent: Element) => void;\n eachInMorphSkip?: (id: string, liveParent: Element, rootEl: Element) => void;\n missingRowKey?: (\n rowEl: Element,\n rowHtml: string,\n binding: { warnedMissingKey?: boolean },\n ) => void;\n\n // --- each.ts -----------------------------------------------------------\n staleIndexEnabled?: () => boolean;\n staleIndex?: (id: string) => void;\n duplicateCacheKeys?: (\n id: string,\n segItems: readonly { cacheKey: unknown }[],\n ) => void;\n\n // --- utils/url-screen.ts -----------------------------------------------\n /**\n * When installed, a screened URL throws instead of warning-and-dropping.\n * A slot rather than a boolean so the check stays uniform with the rest.\n */\n urlScreenThrow?: (message: string) => never;\n}\n\n/**\n * The live slot table. Mutable by design — this is the fourth sanctioned\n * module-level mutable location (Design rule 5), and like `store.ts:REGISTRY`\n * it depends on there being exactly ONE copy at runtime. `tsup`'s\n * `splitting: true` guarantees that: shared modules are promoted into a single\n * chunk that both the main entry and the `kerfjs/dev` entry import.\n */\nexport const devHooks: DevHooks = {};\n\n/**\n * Install (or extend) the dev hooks. Called by the `kerfjs/dev` entry; not part\n * of the public API surface.\n *\n * Merges rather than replaces, so a consumer can install the standard bundle\n * and then override a single slot in a test.\n */\nexport function installDevHooks(hooks: DevHooks): void {\n Object.assign(devHooks, hooks);\n}\n\n/**\n * Remove every installed hook. Exists for test isolation — a suite that asserts\n * the not-installed (production-shaped) path needs to get back to a clean slate\n * without reloading modules.\n */\nexport function clearDevHooks(): void {\n for (const key of Object.keys(devHooks)) {\n delete (devHooks as Record<string, unknown>)[key];\n }\n}\n"]}
@@ -1,9 +1,9 @@
1
- import { itemVersion } from './chunk-QIP723L4.js';
2
- import { parseRowTemplate, rowContractError, parseSingleRow, collectTemplateChildren } from './chunk-V46JKE44.js';
3
- import { captureRowBindings, listSafeHtml, boundTextNodeOf, syncFormProp, newBindingContext, disposeRowBindings, wireBindings, isSafeHtml, _setBindingContext, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX, wireRowBindings, carryOrRewireRowBindings, granularListSafeHtml } from './chunk-ZDCJZCNO.js';
4
- import { effect } from './chunk-U6FK33SG.js';
5
- import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, flatten } from './chunk-GY4XV2UV.js';
6
- import { devHooks } from './chunk-HW7KSM2Y.js';
1
+ import { itemVersion } from './chunk-5WRGJZV6.js';
2
+ import { parseRowTemplate, rowContractError, parseSingleRow, collectTemplateChildren } from './chunk-WKIPLNVO.js';
3
+ import { captureRowBindings, listSafeHtml, boundTextNodeOf, syncFormProp, newBindingContext, disposeRowBindings, wireBindings, isSafeHtml, _setBindingContext, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX, wireRowBindings, carryOrRewireRowBindings, granularListSafeHtml } from './chunk-JRKE6XEK.js';
4
+ import { effect } from './chunk-Y2FOYPBV.js';
5
+ import { LIST_MARKER_PREFIX, flattenWithoutListItems, collectLists, flatten } from './chunk-BDX3R4OM.js';
6
+ import { devHooks } from './chunk-CEQMZYLR.js';
7
7
 
8
8
  // src/list-render-state.ts
9
9
  function deriveListRenderState(bindingCount) {
@@ -18,7 +18,8 @@ function decideListPath(state, patches, snapshotLength, previousBindingCount) {
18
18
  for (const p of patches) {
19
19
  if (p.type === "insert") netDelta += 1;
20
20
  else if (p.type === "remove") netDelta -= 1;
21
- else if (p.type === "replace") return { path: "snapshot", reason: "replace" };
21
+ else if (p.type === "replace")
22
+ return { path: "snapshot", reason: "replace" };
22
23
  }
23
24
  const count = previousBindingCount ?? 0;
24
25
  if (count + netDelta !== snapshotLength) {
@@ -153,10 +154,12 @@ function eachGranular(sig, render, cacheKey, listKey) {
153
154
  return eachSnapshotById(snapshot, render, cacheKey, id, sig);
154
155
  }
155
156
  }
156
- const renderRow = (item, index) => captureRowBindings(() => inRowScope(() => {
157
- const out = render(item, index);
158
- return isSafeHtml(out) ? out.toString() : out;
159
- }));
157
+ const renderRow = (item, index) => captureRowBindings(
158
+ () => inRowScope(() => {
159
+ const out = render(item, index);
160
+ return isSafeHtml(out) ? out.toString() : out;
161
+ })
162
+ );
160
163
  const internalPatches = new Array(patches.length);
161
164
  const cache = ctx.caches.get(id);
162
165
  try {
@@ -223,13 +226,16 @@ function eachSnapshotById(items, render, cacheKey, id, source) {
223
226
  devHooks.staleIndex?.(id);
224
227
  }
225
228
  } else {
226
- const captured = captureRowBindings(() => inRowScope(() => {
227
- const out = render(item, i);
228
- return isSafeHtml(out) ? out.toString() : out;
229
- }));
229
+ const captured = captureRowBindings(
230
+ () => inRowScope(() => {
231
+ const out = render(item, i);
232
+ return isSafeHtml(out) ? out.toString() : out;
233
+ })
234
+ );
230
235
  html = captured.html;
231
236
  bindings = captured.bindings;
232
- if (cache !== null) cache.set(item, { cacheKey: k, html, bindings, version, index: i });
237
+ if (cache !== null)
238
+ cache.set(item, { cacheKey: k, html, bindings, version, index: i });
233
239
  }
234
240
  segItems[i] = { ref: item, cacheKey: k, html, bindings };
235
241
  }
@@ -281,12 +287,7 @@ function restoreFocus(snap) {
281
287
  if (domSelection === null) return;
282
288
  const [anchorNode, anchorOffset, focusNode, focusOffset] = domSelection;
283
289
  try {
284
- document.getSelection()?.setBaseAndExtent(
285
- anchorNode,
286
- anchorOffset,
287
- focusNode,
288
- focusOffset
289
- );
290
+ document.getSelection()?.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
290
291
  } catch {
291
292
  }
292
293
  }
@@ -343,7 +344,11 @@ function protectionTag(node) {
343
344
  const { dataset } = node;
344
345
  return (dataset.morphSkip !== void 0 ? "s" : "") + (dataset.morphSkipChildren !== void 0 ? "c" : "") + (dataset.morphPreserve !== void 0 ? "p" : "");
345
346
  }
346
- var MARKER_PREFIXES = [LIST_MARKER_PREFIX, TEXT_MARKER_PREFIX, ROW_TEXT_PREFIX];
347
+ var MARKER_PREFIXES = [
348
+ LIST_MARKER_PREFIX,
349
+ TEXT_MARKER_PREFIX,
350
+ ROW_TEXT_PREFIX
351
+ ];
347
352
  function isMarker(node) {
348
353
  if (node.nodeType !== COMMENT_NODE) return false;
349
354
  const { data } = node;
@@ -421,7 +426,8 @@ function morphChildren(fromParent, toParent, ownedItems) {
421
426
  if (matched === null && fromChild !== null && toChild.nodeType === COMMENT_NODE && toChild.data.startsWith(LIST_MARKER_PREFIX)) {
422
427
  const wantData = toChild.data;
423
428
  for (let scan = fromChild.nextSibling; scan !== null; scan = scan.nextSibling) {
424
- if (scan.nodeType !== COMMENT_NODE || scan.data !== wantData) continue;
429
+ if (scan.nodeType !== COMMENT_NODE || scan.data !== wantData)
430
+ continue;
425
431
  const regionEnd = afterListRegion(scan, ownedItems);
426
432
  const run = [];
427
433
  for (let r = scan; r !== null && r !== regionEnd; r = r.nextSibling) {
@@ -534,7 +540,10 @@ function preserveTextEntryState(fromEl, toEl) {
534
540
  const toInput = toEl;
535
541
  toInput.value = fromInput.value;
536
542
  try {
537
- toInput.setSelectionRange(fromInput.selectionStart, fromInput.selectionEnd);
543
+ toInput.setSelectionRange(
544
+ fromInput.selectionStart,
545
+ fromInput.selectionEnd
546
+ );
538
547
  } catch {
539
548
  }
540
549
  }
@@ -567,7 +576,8 @@ function tryAttributeOnlyFastPath(liveNode, oldHtml, newHtml) {
567
576
  if (oldGt === -1 || newGt === -1) return false;
568
577
  if (oldHtml.length - oldGt !== newHtml.length - newGt) return false;
569
578
  if (oldHtml.slice(oldGt) !== newHtml.slice(newGt)) return false;
570
- if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml)) return false;
579
+ if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml))
580
+ return false;
571
581
  const oldTag = parseOpeningTag(oldHtml, oldGt);
572
582
  const newTag = parseOpeningTag(newHtml, newGt);
573
583
  if (oldTag === null || newTag === null) return false;
@@ -595,7 +605,8 @@ function tryAttributeOnlyFastPath(liveNode, oldHtml, newHtml) {
595
605
  return true;
596
606
  }
597
607
  function tryTextContentFastPath(liveNode, oldHtml, newHtml) {
598
- if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml)) return false;
608
+ if (containsDataMorphSkip(oldHtml) || containsDataMorphSkip(newHtml))
609
+ return false;
599
610
  let p = 0;
600
611
  const minLen = Math.min(oldHtml.length, newHtml.length);
601
612
  while (p < minLen && oldHtml.charCodeAt(p) === newHtml.charCodeAt(p)) p++;
@@ -610,7 +621,8 @@ function tryTextContentFastPath(liveNode, oldHtml, newHtml) {
610
621
  if (!isPureTextWindow(newHtml, p, newWinEnd)) return false;
611
622
  if (p === 0) return false;
612
623
  const boundaryCc = oldHtml.charCodeAt(p - 1);
613
- if (boundaryCc === LT || boundaryCc === DQUOTE || boundaryCc === SQUOTE || boundaryCc === EQ || boundaryCc === AMP) return false;
624
+ if (boundaryCc === LT || boundaryCc === DQUOTE || boundaryCc === SQUOTE || boundaryCc === EQ || boundaryCc === AMP)
625
+ return false;
614
626
  const textStart = lastIndexOfChar(oldHtml, GT, p - 1);
615
627
  if (textStart === -1) return false;
616
628
  const textEnd = oldHtml.indexOf("<", p);
@@ -637,7 +649,8 @@ function containsDataMorphSkip(html) {
637
649
  function isPureTextWindow(html, start, end) {
638
650
  for (let i = start; i < end; i++) {
639
651
  const cc = html.charCodeAt(i);
640
- if (cc === LT || cc === GT || cc === DQUOTE || cc === SQUOTE || cc === AMP || cc === EQ) return false;
652
+ if (cc === LT || cc === GT || cc === DQUOTE || cc === SQUOTE || cc === AMP || cc === EQ)
653
+ return false;
641
654
  }
642
655
  return true;
643
656
  }
@@ -769,7 +782,14 @@ function reconcileGranular(binding, patches) {
769
782
  if (runLen === 1) {
770
783
  applySingleInsert(liveParent, items, patch, endAnchor(binding));
771
784
  } else {
772
- applyBulkInsert(liveParent, items, patches, i, runEnd, endAnchor(binding));
785
+ applyBulkInsert(
786
+ liveParent,
787
+ items,
788
+ patches,
789
+ i,
790
+ runEnd,
791
+ endAnchor(binding)
792
+ );
773
793
  }
774
794
  i = runEnd;
775
795
  continue;
@@ -881,7 +901,10 @@ function applyBulkUpdate(liveParent, items, patches, start, end) {
881
901
  morphChanges.push({ patchIdx: k, html: p.html });
882
902
  }
883
903
  if (morphChanges.length === 0) return;
884
- const { content, count } = parseRowTemplate(morphChanges.map((c) => c.html).join(""), liveParent);
904
+ const { content, count } = parseRowTemplate(
905
+ morphChanges.map((c) => c.html).join(""),
906
+ liveParent
907
+ );
885
908
  if (count !== morphChanges.length) {
886
909
  throw findOffendingChange(patches, morphChanges, liveParent);
887
910
  }
@@ -924,18 +947,30 @@ function applyBulkInsert(liveParent, items, patches, start, end, tailAnchor) {
924
947
  function findOffendingInsert(patches, start, htmls, liveParent) {
925
948
  for (let i = 0; i < htmls.length; i++) {
926
949
  if (parseRowTemplate(htmls[i], liveParent).count !== 1) {
927
- return rowContractError(patches[start + i].index, htmls[i], liveParent);
950
+ return rowContractError(
951
+ patches[start + i].index,
952
+ htmls[i],
953
+ liveParent
954
+ );
928
955
  }
929
956
  }
930
- return new Error("each(): bulk-insert mismatch with no per-row offender (kerf bug).");
957
+ return new Error(
958
+ "each(): bulk-insert mismatch with no per-row offender (kerf bug)."
959
+ );
931
960
  }
932
961
  function findOffendingChange(patches, changes, liveParent) {
933
962
  for (const c of changes) {
934
963
  if (parseRowTemplate(c.html, liveParent).count !== 1) {
935
- return rowContractError(patches[c.patchIdx].index, c.html, liveParent);
964
+ return rowContractError(
965
+ patches[c.patchIdx].index,
966
+ c.html,
967
+ liveParent
968
+ );
936
969
  }
937
970
  }
938
- return new Error("each(): bulk-update mismatch with no per-row offender (kerf bug).");
971
+ return new Error(
972
+ "each(): bulk-update mismatch with no per-row offender (kerf bug)."
973
+ );
939
974
  }
940
975
 
941
976
  // src/list-reconcile-inplace.ts
@@ -960,7 +995,12 @@ function tryInPlaceContentUpdate(binding, listSeg) {
960
995
  }
961
996
  function updateRowInPlace(liveParent, old, ni, index) {
962
997
  if (old.html === ni.html || tryAttributeOnlyFastPath(old.node, old.html, ni.html) || tryTextContentFastPath(old.node, old.html, ni.html)) {
963
- const kept = carryOrRewireRowBindings(old.node, old.bindings, old.bindingDisposers, ni.bindings);
998
+ const kept = carryOrRewireRowBindings(
999
+ old.node,
1000
+ old.bindings,
1001
+ old.bindingDisposers,
1002
+ ni.bindings
1003
+ );
964
1004
  return {
965
1005
  ref: ni.ref,
966
1006
  cacheKey: ni.cacheKey,
@@ -973,7 +1013,12 @@ function updateRowInPlace(liveParent, old, ni, index) {
973
1013
  const newNode = parseSingleRow(ni.html, index, liveParent);
974
1014
  if (old.node.tagName === newNode.tagName) {
975
1015
  _morphElement(old.node, newNode);
976
- const kept = carryOrRewireRowBindings(old.node, old.bindings, old.bindingDisposers, ni.bindings);
1016
+ const kept = carryOrRewireRowBindings(
1017
+ old.node,
1018
+ old.bindings,
1019
+ old.bindingDisposers,
1020
+ ni.bindings
1021
+ );
977
1022
  return {
978
1023
  ref: ni.ref,
979
1024
  cacheKey: ni.cacheKey,
@@ -985,7 +1030,12 @@ function updateRowInPlace(liveParent, old, ni, index) {
985
1030
  }
986
1031
  disposeRowBindings(old.bindingDisposers);
987
1032
  liveParent.replaceChild(newNode, old.node);
988
- const fresh = carryOrRewireRowBindings(newNode, void 0, void 0, ni.bindings);
1033
+ const fresh = carryOrRewireRowBindings(
1034
+ newNode,
1035
+ void 0,
1036
+ void 0,
1037
+ ni.bindings
1038
+ );
989
1039
  return {
990
1040
  ref: ni.ref,
991
1041
  cacheKey: ni.cacheKey,
@@ -1070,15 +1120,22 @@ function buildFreshNodes(newRecord, freshIndices, freshHtmls, liveParent) {
1070
1120
  function findOffendingRow(newRecord, freshIndices, freshHtmls, liveParent) {
1071
1121
  for (let i = 0; i < freshHtmls.length; i++) {
1072
1122
  if (parseRowTemplate(freshHtmls[i], liveParent).count !== 1) {
1073
- return rowContractError(freshIndices[i], newRecord[freshIndices[i]].html, liveParent);
1123
+ return rowContractError(
1124
+ freshIndices[i],
1125
+ newRecord[freshIndices[i]].html,
1126
+ liveParent
1127
+ );
1074
1128
  }
1075
1129
  }
1076
- return new Error("each(): bulk-parse mismatch with no per-row offender (kerf bug).");
1130
+ return new Error(
1131
+ "each(): bulk-parse mismatch with no per-row offender (kerf bug)."
1132
+ );
1077
1133
  }
1078
1134
  function removeOldNodes(liveParent, removedItems) {
1079
1135
  for (const item of removedItems) {
1080
1136
  disposeRowBindings(item.bindingDisposers);
1081
- if (item.node.parentElement === liveParent) liveParent.removeChild(item.node);
1137
+ if (item.node.parentElement === liveParent)
1138
+ liveParent.removeChild(item.node);
1082
1139
  }
1083
1140
  }
1084
1141
  function applyMoves(liveParent, newRecord, prevIdx, stable, tailAnchor) {
@@ -1160,7 +1217,8 @@ function assertNotInsideMountedTree(rootEl) {
1160
1217
  ancestor = ancestor.parentElement;
1161
1218
  }
1162
1219
  const stack = [];
1163
- for (let i = 0; i < rootEl.children.length; i++) stack.push(rootEl.children[i]);
1220
+ for (let i = 0; i < rootEl.children.length; i++)
1221
+ stack.push(rootEl.children[i]);
1164
1222
  while (stack.length > 0) {
1165
1223
  const cur = stack.pop();
1166
1224
  if (isMounted(cur)) throw new Error(NESTED_MOUNT_MSG);
@@ -1241,7 +1299,8 @@ function mount(rootEl, render) {
1241
1299
  valueOnlyWarnCtx
1242
1300
  );
1243
1301
  if (anyRebuiltListIsGranular(segment, renderCtx.rebuiltLists)) {
1244
- for (const id of renderCtx.rebuiltLists) renderCtx.bindingCounts.delete(id);
1302
+ for (const id of renderCtx.rebuiltLists)
1303
+ renderCtx.bindingCounts.delete(id);
1245
1304
  result = runRenderPass();
1246
1305
  segment = resultToSegment(result);
1247
1306
  nextStaticHtml = runSubsequentRender(
@@ -1255,7 +1314,8 @@ function mount(rootEl, render) {
1255
1314
  }
1256
1315
  if (nextStaticHtml !== prevStaticHtml) {
1257
1316
  bindingDisposers = wireBindings(rootEl, bindingCtx, bindingDisposers);
1258
- if (devHooks.staleBindingEnabled?.()) prevWiredBindings = bindingCtx.list;
1317
+ if (devHooks.staleBindingEnabled?.())
1318
+ prevWiredBindings = bindingCtx.list;
1259
1319
  } else {
1260
1320
  devHooks.staleBinding?.(prevWiredBindings, bindingCtx.list);
1261
1321
  }
@@ -1307,12 +1367,22 @@ function runSubsequentRender(rootEl, segment, bindings, renderCtx, prevStaticHtm
1307
1367
  if (currentStaticHtml === prevStaticHtml) {
1308
1368
  return prevStaticHtml;
1309
1369
  }
1310
- devHooks.valueOnlyRerender?.(prevStaticHtml, currentStaticHtml, valueOnlyWarnCtx);
1370
+ devHooks.valueOnlyRerender?.(
1371
+ prevStaticHtml,
1372
+ currentStaticHtml,
1373
+ valueOnlyWarnCtx
1374
+ );
1311
1375
  cleanupOrphanBindings(segment, bindings, renderCtx);
1312
1376
  const template = rootEl.cloneNode(false);
1313
1377
  template.innerHTML = currentStaticHtml;
1314
1378
  morph(rootEl, template, collectOwnedItems(bindings));
1315
- bindListsFromMarkers(rootEl, segment, bindings, false, renderCtx.rebuiltLists);
1379
+ bindListsFromMarkers(
1380
+ rootEl,
1381
+ segment,
1382
+ bindings,
1383
+ false,
1384
+ renderCtx.rebuiltLists
1385
+ );
1316
1386
  return currentStaticHtml;
1317
1387
  }
1318
1388
  function coerceRenderResult(result) {
@@ -1339,7 +1409,8 @@ function bindListsFromMarkers(rootEl, segment, bindings, inlinedItems, rebuiltLi
1339
1409
  const id = marker.data.slice(LIST_MARKER_PREFIX.length);
1340
1410
  const existing = bindings.get(id);
1341
1411
  if (existing) {
1342
- if (existing.marker === marker && rootEl.contains(existing.marker)) continue;
1412
+ if (existing.marker === marker && rootEl.contains(existing.marker))
1413
+ continue;
1343
1414
  for (const item of existing.items) {
1344
1415
  disposeRowBindings(item.bindingDisposers);
1345
1416
  if (rootEl.contains(item.node)) {
@@ -1385,7 +1456,8 @@ function validateInlinedRowMatch(expectedHtml, index, boundEl, liveParent) {
1385
1456
  const { content, count } = parseRowTemplate(expectedHtml, liveParent);
1386
1457
  if (count !== 1) throw rowContractError(index, expectedHtml, liveParent);
1387
1458
  const expectedTag = content.firstElementChild.tagName;
1388
- if (boundEl.tagName !== expectedTag) throw rowStructureError(index, boundEl.tagName, expectedTag);
1459
+ if (boundEl.tagName !== expectedTag)
1460
+ throw rowStructureError(index, boundEl.tagName, expectedTag);
1389
1461
  }
1390
1462
  function rowStructureError(index, gotTag, wantTag) {
1391
1463
  const got = gotTag.toLowerCase();
@@ -1425,4 +1497,4 @@ function collectComments(node, out) {
1425
1497
 
1426
1498
  export { captureFocus, each, morph, mount, moveNode, restoreFocus };
1427
1499
 
1428
- //# sourceMappingURL=chunk-SVATPF5R.js.map
1500
+ //# sourceMappingURL=chunk-DLY444MN.js.map