kerfjs 2.0.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/ai/cursorrules +11 -1
- package/ai/manifest.json +5 -5
- package/ai/skill.md +11 -1
- package/dist/array-signal.d.ts +7 -1
- package/dist/array-signal.js +11 -2
- package/dist/array-signal.js.map +1 -1
- package/dist/bindings-CYwoJpQb.d.ts +60 -0
- package/dist/chunk-3APBEVHF.js +20 -0
- package/dist/chunk-3APBEVHF.js.map +1 -0
- package/dist/chunk-GY4XV2UV.js +73 -0
- package/dist/chunk-GY4XV2UV.js.map +1 -0
- package/dist/{chunk-GYRZQCSY.js → chunk-JVVU2RQO.js} +11 -79
- package/dist/chunk-JVVU2RQO.js.map +1 -0
- package/dist/chunk-QIP723L4.js +15 -0
- package/dist/chunk-QIP723L4.js.map +1 -0
- package/dist/chunk-SAYPJ6XR.js +43 -0
- package/dist/chunk-SAYPJ6XR.js.map +1 -0
- package/dist/chunk-VVDJLWMP.js +14 -0
- package/dist/chunk-VVDJLWMP.js.map +1 -0
- package/dist/chunk-YHH7OUFA.js +58 -0
- package/dist/chunk-YHH7OUFA.js.map +1 -0
- package/dist/dev.d.ts +339 -0
- package/dist/dev.js +607 -0
- package/dist/dev.js.map +1 -0
- package/dist/html.d.ts +1 -0
- package/dist/html.js +4 -2
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +49 -11
- package/dist/index.js +351 -340
- package/dist/index.js.map +1 -1
- package/dist/jsx-runtime.d.ts +16 -60
- package/dist/jsx-runtime.js +4 -2
- package/dist/testing.js +3 -2
- package/llms.txt +2 -2
- package/package.json +22 -11
- package/dist/chunk-GYRZQCSY.js.map +0 -1
- package/dist/chunk-KFUDM3VP.js +0 -131
- package/dist/chunk-KFUDM3VP.js.map +0 -1
- package/dist/chunk-NU7YHYEV.js +0 -90
- package/dist/chunk-NU7YHYEV.js.map +0 -1
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ReadonlySignal
|
|
1
|
+
import { ReadonlySignal } from '@preact/signals-core';
|
|
2
|
+
import { B as Binding } from './bindings-CYwoJpQb.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* JSX intrinsic-element types — kerf's per-tag attribute contracts.
|
|
@@ -692,63 +693,6 @@ interface KerfBuiltinIntrinsicElements {
|
|
|
692
693
|
};
|
|
693
694
|
}
|
|
694
695
|
|
|
695
|
-
/**
|
|
696
|
-
* Fine-grained signal bindings (KF-294 spike).
|
|
697
|
-
*
|
|
698
|
-
* When a `Signal` is interpolated straight into a JSX attribute
|
|
699
|
-
* (`class={sig}`) or a text child (`{sig}`) INSIDE a `mount()` render, the
|
|
700
|
-
* JSX runtime stops stringifying it. Instead it emits a marker into the HTML
|
|
701
|
-
* string and records a binding here; after the string is parsed to DOM, a
|
|
702
|
-
* wiring pass attaches one `effect` per binding that writes straight to the
|
|
703
|
-
* live node. A later change to that signal then updates the node WITHOUT
|
|
704
|
-
* re-running the render function or walking the list reconciler.
|
|
705
|
-
*
|
|
706
|
-
* This reuses the "marker in string, wire up after parse" mechanism the
|
|
707
|
-
* keyed-list reconciler already uses for `<!--kf-list:{id}-->` markers.
|
|
708
|
-
*
|
|
709
|
-
* TWO SCOPES of binding, with disjoint marker namespaces so their wiring
|
|
710
|
-
* passes never collide:
|
|
711
|
-
*
|
|
712
|
-
* - GLOBAL holes — signals in the static surrounds (outside any `each()`
|
|
713
|
-
* row). Markers: `data-kfb` attribute / `<!--kfb:{id}-->` comment. Ids come
|
|
714
|
-
* from the mount render context's counter; wired by `wireBindings()` over
|
|
715
|
-
* the whole mount root; disposed/re-wired by `mount()` each render.
|
|
716
|
-
*
|
|
717
|
-
* - ROW holes — signals inside an `each()` row. Markers: `data-kfbrow`
|
|
718
|
-
* attribute / `<!--kfbr:{id}-->` comment. Ids are row-LOCAL (reset per row)
|
|
719
|
-
* so they stay stable and collision-free as rows are inserted/removed/moved.
|
|
720
|
-
* Captured per row by `captureRowBindings()`, carried on the list segment
|
|
721
|
-
* item, and wired/disposed by the list reconciler at each row node's
|
|
722
|
-
* create/remove — so a binding's lifetime tracks its row node's lifetime,
|
|
723
|
-
* and row reorders (which reuse the same node) are free.
|
|
724
|
-
*
|
|
725
|
-
* Outside a `mount()` render (SSR / `SafeHtml.toString()`) neither scope is
|
|
726
|
-
* active: the runtime snapshots `signal.value` and emits no markers, so server
|
|
727
|
-
* output is correct and legacy `.toString()` callers are unaffected.
|
|
728
|
-
*
|
|
729
|
-
* Module-level mutable state note: `context` / `rowSink` (plus `rowCounter`,
|
|
730
|
-
* the row-hole id counter that resets with each row capture) are a third
|
|
731
|
-
* sanctioned module-level mutable location (alongside `store.ts:REGISTRY` and
|
|
732
|
-
* `each.ts:context`). They hold the current render's binding sinks and are set
|
|
733
|
-
* / cleared by `mount()` and `each()` around the render calls. The only other
|
|
734
|
-
* module-level container here is `insertedTextNodes`, a WeakMap keyed on text
|
|
735
|
-
* marker comments — a pure cache whose entries die with their nodes (GC-tied
|
|
736
|
-
* lifetime), so it carries no cross-render semantics.
|
|
737
|
-
*/
|
|
738
|
-
|
|
739
|
-
interface AttrBinding {
|
|
740
|
-
kind: 'attr';
|
|
741
|
-
id: string;
|
|
742
|
-
attr: string;
|
|
743
|
-
signal: Signal<unknown>;
|
|
744
|
-
}
|
|
745
|
-
interface TextBinding {
|
|
746
|
-
kind: 'text';
|
|
747
|
-
id: string;
|
|
748
|
-
signal: Signal<unknown>;
|
|
749
|
-
}
|
|
750
|
-
type Binding = AttrBinding | TextBinding;
|
|
751
|
-
|
|
752
696
|
/**
|
|
753
697
|
* `Segment` — kerf's structured render output.
|
|
754
698
|
*
|
|
@@ -809,6 +753,18 @@ interface ListSegment {
|
|
|
809
753
|
* patches are present.
|
|
810
754
|
*/
|
|
811
755
|
patches?: ArrayPatchInternal[];
|
|
756
|
+
/**
|
|
757
|
+
* KF-388: the identity of the data this list renders — the `arraySignal`
|
|
758
|
+
* instance, or `undefined` for a plain array.
|
|
759
|
+
*
|
|
760
|
+
* A list's `id` is its call-order index, so a render that changes how many
|
|
761
|
+
* `each()` calls precede this one hands this segment a DIFFERENT list's
|
|
762
|
+
* binding. Patches are only meaningful against the binding they were queued
|
|
763
|
+
* for, so the reconciler compares this against the binding's recorded source
|
|
764
|
+
* before trusting the patch queue. It is an identity check, not a value
|
|
765
|
+
* check — the instance is never read.
|
|
766
|
+
*/
|
|
767
|
+
source?: object;
|
|
812
768
|
}
|
|
813
769
|
/**
|
|
814
770
|
* Internal patch shape used inside list segments. Mirrors `ArrayPatch<T>`
|
|
@@ -906,7 +862,7 @@ declare function raw(html: string): SafeHtml;
|
|
|
906
862
|
* Internal: build a `SafeHtml` representing a list segment. Used by
|
|
907
863
|
* `each()` so the JSX runtime is the sole owner of `SafeHtml` construction.
|
|
908
864
|
*/
|
|
909
|
-
declare function listSafeHtml(id: string, items: ListSegment['items']): SafeHtml;
|
|
865
|
+
declare function listSafeHtml(id: string, items: ListSegment['items'], source?: object): SafeHtml;
|
|
910
866
|
/**
|
|
911
867
|
* Internal: build a `SafeHtml` representing a granular list segment with
|
|
912
868
|
* patches (KF-92). The reconciler applies the patches to the existing
|
|
@@ -919,7 +875,7 @@ declare function listSafeHtml(id: string, items: ListSegment['items']): SafeHtml
|
|
|
919
875
|
* already carries a `html` string, and the reconciler does no further
|
|
920
876
|
* row rendering.
|
|
921
877
|
*/
|
|
922
|
-
declare function granularListSafeHtml(id: string, items: ListSegment['items'], patches: NonNullable<ListSegment['patches']
|
|
878
|
+
declare function granularListSafeHtml(id: string, items: ListSegment['items'], patches: NonNullable<ListSegment['patches']>, source?: object): SafeHtml;
|
|
923
879
|
type Child = SafeHtml | string | number | boolean | null | undefined | ReadonlySignal<unknown>;
|
|
924
880
|
type Children = Child | Children[];
|
|
925
881
|
interface Props {
|
package/dist/jsx-runtime.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
export { Fragment, SafeHtml, assertEmittableAttrName as _assertEmittableAttrName, _renderAttrVerbatim, _toSegment, granularListSafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { Fragment, SafeHtml, assertEmittableAttrName as _assertEmittableAttrName, _renderAttrVerbatim, _toSegment, granularListSafeHtml, isSafeHtml, jsx, jsx as jsxDEV, jsx as jsxs, listSafeHtml, raw } from './chunk-JVVU2RQO.js';
|
|
2
|
+
import './chunk-GY4XV2UV.js';
|
|
3
|
+
import './chunk-3APBEVHF.js';
|
|
4
|
+
import './chunk-VVDJLWMP.js';
|
|
3
5
|
//# sourceMappingURL=jsx-runtime.js.map
|
|
4
6
|
//# sourceMappingURL=jsx-runtime.js.map
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { clearStoreRegistry } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
export { clearStoreRegistry } from './chunk-SAYPJ6XR.js';
|
|
2
|
+
import './chunk-3APBEVHF.js';
|
|
3
|
+
import './chunk-VVDJLWMP.js';
|
|
3
4
|
//# sourceMappingURL=testing.js.map
|
|
4
5
|
//# sourceMappingURL=testing.js.map
|
package/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> A tiny (~11 KB minified + gzipped including its one runtime dependency `@preact/signals-core`; ~12 KB with `arraySignal`) reactive UI framework — fine-grained signals + DOM morphing + JSX. No virtual DOM, no compiler. Apply the smallest possible cut to update your DOM.
|
|
4
4
|
|
|
5
|
-
kerf renders JSX to a structured `SafeHtml` (string for static content; tagged "list"/"mixed" segments where `each(...)` was used) and reconciles it against the live tree with a custom segment-aware morph. Static surrounds go through a general-purpose tree-morph; list contents go through a keyed reconciler that operates directly on live children — partial-update on huge lists is O(changes), not O(rows). Reactivity is provided by [@preact/signals-core](https://github.com/preactjs/signals). It pairs well with server-rendered HTML, embedded widgets, and any UI where preserving focus / selection across re-renders matters. Public API is one import: `signal`, `computed`, `effect`, `batch`, `defineStore`, `resetAllStores`, `mount`, `morph`, `each`, `attr`, `delegate`, `delegateCapture`, `toElement`, `SafeHtml`, `isSafeHtml`, `raw`, `Fragment`. (Two more subpaths: `kerfjs/testing` exposes `clearStoreRegistry` for unit-test isolation; `kerfjs/jsx-runtime` exposes the typed JSX building blocks for declaration-merging custom-element types.) An optional subpath at `kerfjs/array-signal` adds `arraySignal()` — a granular keyed-list signal whose patch events let `each()` reconcile in O(patches) instead of O(N). Another optional subpath at `kerfjs/html` adds the `html` tagged template — JSX-identical runtime semantics with no JSX transform, so CDN/importmap projects can author kerf UIs with literally no build step.
|
|
5
|
+
kerf renders JSX to a structured `SafeHtml` (string for static content; tagged "list"/"mixed" segments where `each(...)` was used) and reconciles it against the live tree with a custom segment-aware morph. Static surrounds go through a general-purpose tree-morph; list contents go through a keyed reconciler that operates directly on live children — partial-update on huge lists is O(changes), not O(rows). Reactivity is provided by [@preact/signals-core](https://github.com/preactjs/signals). It pairs well with server-rendered HTML, embedded widgets, and any UI where preserving focus / selection across re-renders matters. Public API is one import: `signal`, `computed`, `effect`, `batch`, `defineStore`, `resetAllStores`, `mount`, `morph`, `each`, `attr`, `delegate`, `delegateCapture`, `toElement`, `SafeHtml`, `isSafeHtml`, `raw`, `Fragment`. (Two more subpaths: `kerfjs/testing` exposes `clearStoreRegistry` for unit-test isolation; `kerfjs/jsx-runtime` exposes the typed JSX building blocks for declaration-merging custom-element types.) An optional subpath at `kerfjs/array-signal` adds `arraySignal()` — a granular keyed-list signal whose patch events let `each()` reconcile in O(patches) instead of O(N). An optional subpath at `kerfjs/dev` installs the development diagnostics — kerf does NOT infer dev mode, so you import it behind your own build's dev flag (`if (import.meta.env.DEV) await import('kerfjs/dev');`); omitting it is production and sheds ~4.7 KB min+gzip. Another optional subpath at `kerfjs/html` adds the `html` tagged template — JSX-identical runtime semantics with no JSX transform, so CDN/importmap projects can author kerf UIs with literally no build step.
|
|
6
6
|
|
|
7
7
|
## For humans new to the codebase
|
|
8
8
|
|
|
@@ -30,7 +30,7 @@ kerf renders JSX to a structured `SafeHtml` (string for static content; tagged "
|
|
|
30
30
|
- [API reference](https://github.com/brianwestphal/kerf/blob/main/docs/8-api-reference.md): every export, every option.
|
|
31
31
|
- [Live demo](https://github.com/brianwestphal/kerf/blob/main/docs/9-live-demo.md): the GitHub Pages deploy of `examples/reactivity-demo`.
|
|
32
32
|
- [Migrating](https://github.com/brianwestphal/kerf/blob/main/docs/10-migrating.md): the `/kerf/migrating/` comparison hub — coming-from-React/Alpine/Lit/vanjs pages with side-by-side todo-list translations.
|
|
33
|
-
- [Dev-mode warnings](https://github.com/brianwestphal/kerf/blob/main/docs/11-dev-warnings.md): the opt-in `KERF_DEV_WARN_*` env-gated dev-warn family (rebuilt listeners, untracked signals, narrow store sets, delegate-in-effect, each-in-morph-skip, duplicate keys, value-only re-renders, stale bindings) and the rules each new warning must follow.
|
|
33
|
+
- [Dev-mode warnings](https://github.com/brianwestphal/kerf/blob/main/docs/11-dev-warnings.md): the opt-in `KERF_DEV_WARN_*` env-gated dev-warn family (rebuilt listeners, untracked signals, narrow store sets, delegate-in-effect, each-in-morph-skip, duplicate keys, value-only re-renders, stale bindings), how the diagnostics are installed via the `kerfjs/dev` subpath rather than inferred from the environment, and the rules each new warning must follow.
|
|
34
34
|
- [AI-assistant configs](https://github.com/brianwestphal/kerf/blob/main/docs/12-ai-assistant-configs.md): how the drop-in Claude Code skill + Cursor rules ship inside the `kerfjs` npm package at `ai/skill.md` / `ai/cursorrules` / `ai/manifest.json`, the version + marker contract for customization preservation, and the `kerfjs/ai-assistant-configs` ESLint rule that surfaces drift on every lint pass.
|
|
35
35
|
- [Component packages](https://github.com/brianwestphal/kerf/blob/main/docs/13-component-packages.md): building and publishing reusable kerf components as npm packages — the no-instance component model, per-instance state via factories, event/cleanup patterns, and `kerfjs`-as-peer-dependency packaging modeled on `eslint-plugin-kerfjs`. Scaffold one with `npm create kerf-component@latest <dir>` (the `create-kerf-component` initializer).
|
|
36
36
|
- [Feature coverage](https://github.com/brianwestphal/kerf/blob/main/docs/14-feature-coverage.md): the per-behavior coverage axis orthogonal to line coverage — an index mapping each behavior (especially list-reconciler *state transitions*) to its guarding test, enforced by `npm run check:features`.
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kerfjs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Tiny reactive UI framework — fine-grained signals + DOM morphing + JSX. Apply the smallest possible cut to update your DOM.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"sideEffects":
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"./dist/dev.js",
|
|
8
|
+
"./src/dev.ts"
|
|
9
|
+
],
|
|
7
10
|
"license": "MIT",
|
|
8
11
|
"author": "Brian Westphal <brian.westphal@bleugris.com>",
|
|
9
12
|
"homepage": "https://brianwestphal.github.io/kerf/",
|
|
@@ -53,6 +56,10 @@
|
|
|
53
56
|
"types": "./dist/array-signal.d.ts",
|
|
54
57
|
"import": "./dist/array-signal.js"
|
|
55
58
|
},
|
|
59
|
+
"./dev": {
|
|
60
|
+
"types": "./dist/dev.d.ts",
|
|
61
|
+
"import": "./dist/dev.js"
|
|
62
|
+
},
|
|
56
63
|
"./html": {
|
|
57
64
|
"types": "./dist/html.d.ts",
|
|
58
65
|
"import": "./dist/html.js"
|
|
@@ -76,20 +83,22 @@
|
|
|
76
83
|
"test:integration": "vitest run tests/integration --coverage",
|
|
77
84
|
"test:dist": "npm run build && vitest run --config vitest.config.dist.ts",
|
|
78
85
|
"test:dist:full": "npm run build && vitest run --config vitest.config.dist-full.ts",
|
|
79
|
-
"test:dist:jsx-typing": "npm run build && tsc -p tests/dist/jsx-typing/tsconfig.json",
|
|
80
|
-
"test:dist:examples": "npm run build && tsc -p site/src/examples/complete/tsconfig.json",
|
|
81
|
-
"test:dist:scaffold-typing": "npm run build && tsc -p tests/dist/scaffold-typing/tsconfig.json",
|
|
86
|
+
"test:dist:jsx-typing": "npm run build && node node_modules/typescript7/bin/tsc -p tests/dist/jsx-typing/tsconfig.json",
|
|
87
|
+
"test:dist:examples": "npm run build && node node_modules/typescript7/bin/tsc -p site/src/examples/complete/tsconfig.json",
|
|
88
|
+
"test:dist:scaffold-typing": "npm run build && node node_modules/typescript7/bin/tsc -p tests/dist/scaffold-typing/tsconfig.json",
|
|
82
89
|
"test:browser": "npm run build && playwright test",
|
|
83
90
|
"bench:micro": "vitest bench --run --config vitest.config.bench.ts",
|
|
84
91
|
"bench:serve": "bash bench/site.sh",
|
|
85
92
|
"lint": "eslint src tests",
|
|
86
|
-
"typecheck": "tsc --noEmit",
|
|
87
|
-
"check": "npm run lint && npm run typecheck && node scripts/check-doc-test-inventory.mjs && node scripts/check-doc-api-coverage.mjs && node scripts/check-feature-coverage.mjs && node scripts/check-ai-bundle.mjs && npm test && npm run build && node scripts/check-doc-api-signatures.mjs && vitest run --config vitest.config.dist.ts && vitest run --config vitest.config.dist-full.ts && tsc -p tests/dist/jsx-typing/tsconfig.json && tsc -p site/src/examples/complete/tsconfig.json && tsc -p tests/dist/scaffold-typing/tsconfig.json && node scripts/check-docs-examples.mjs",
|
|
93
|
+
"typecheck": "node node_modules/typescript7/bin/tsc --noEmit",
|
|
94
|
+
"check": "npm run lint && npm run typecheck && node scripts/check-doc-test-inventory.mjs && node scripts/check-doc-api-coverage.mjs && node scripts/check-doc-site-tickets.mjs && node scripts/check-feature-coverage.mjs && node scripts/check-ai-bundle.mjs && npm test && npm run build && node scripts/check-bundle-size.mjs && node scripts/check-doc-api-signatures.mjs && vitest run --config vitest.config.dist.ts && vitest run --config vitest.config.dist-full.ts && node node_modules/typescript7/bin/tsc -p tests/dist/jsx-typing/tsconfig.json && node node_modules/typescript7/bin/tsc -p site/src/examples/complete/tsconfig.json && node node_modules/typescript7/bin/tsc -p tests/dist/scaffold-typing/tsconfig.json && node scripts/check-docs-examples.mjs",
|
|
88
95
|
"check:docs:examples": "node scripts/check-docs-examples.mjs",
|
|
89
96
|
"check:full": "npm run check && playwright test",
|
|
90
97
|
"check:docs:test-inventory": "node scripts/check-doc-test-inventory.mjs",
|
|
91
98
|
"check:docs:api-coverage": "node scripts/check-doc-api-coverage.mjs",
|
|
99
|
+
"check:docs:site-tickets": "node scripts/check-doc-site-tickets.mjs",
|
|
92
100
|
"check:docs:api-signatures": "npm run build && node scripts/check-doc-api-signatures.mjs",
|
|
101
|
+
"fuzz:soak": "node scripts/fuzz-soak.mjs",
|
|
93
102
|
"check:features": "node scripts/check-feature-coverage.mjs",
|
|
94
103
|
"check:ai-bundle-in-sync": "node scripts/check-ai-bundle.mjs",
|
|
95
104
|
"ai-bundle:sync": "node scripts/sync-ai-bundle.mjs",
|
|
@@ -103,7 +112,8 @@
|
|
|
103
112
|
"example:reactivity-demo:build": "cd examples/reactivity-demo && npm install && npm run build",
|
|
104
113
|
"site:dev": "cd site && npm install && npm run dev",
|
|
105
114
|
"site:dev:hmr": "cd site && npm install && npm run dev:hmr",
|
|
106
|
-
"site:build": "cd site && npm install && npm run build"
|
|
115
|
+
"site:build": "cd site && npm install && npm run build",
|
|
116
|
+
"check:bundle-size": "npm run build && node scripts/check-bundle-size.mjs"
|
|
107
117
|
},
|
|
108
118
|
"dependencies": {
|
|
109
119
|
"@preact/signals-core": "^1.14.1"
|
|
@@ -112,8 +122,8 @@
|
|
|
112
122
|
"@playwright/test": "^1.59.1",
|
|
113
123
|
"@types/jsdom": "^28.0.1",
|
|
114
124
|
"@types/node": "^22.10.0",
|
|
115
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
116
|
-
"@typescript-eslint/parser": "^8.
|
|
125
|
+
"@typescript-eslint/eslint-plugin": "^8.65.0",
|
|
126
|
+
"@typescript-eslint/parser": "^8.65.0",
|
|
117
127
|
"@vitest/coverage-v8": "^3.0.0",
|
|
118
128
|
"domotion-svg": "^0.21.1",
|
|
119
129
|
"eslint": "^9.16.0",
|
|
@@ -124,7 +134,8 @@
|
|
|
124
134
|
"husky": "^9.1.7",
|
|
125
135
|
"jsdom": "^29.1.1",
|
|
126
136
|
"tsup": "^8.3.0",
|
|
127
|
-
"typescript": "^
|
|
137
|
+
"typescript": "^6.0.3",
|
|
138
|
+
"typescript7": "npm:typescript@^7.0.2",
|
|
128
139
|
"vitest": "^3.0.0"
|
|
129
140
|
}
|
|
130
141
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/syncFormProp.ts","../src/utils/urlScreen.ts","../src/bindings.ts","../src/segment.ts","../src/utils/escapeHtml.ts","../src/utils/jsx-attr-aliases.ts","../src/jsx-runtime.ts"],"names":["context","SAFE_HTML_BRAND"],"mappings":"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","file":"chunk-GYRZQCSY.js","sourcesContent":["/**\n * Form-state property sync — shared by the morph's attribute writer and the\n * fine-grained binding writer (KF-335: controlled checked/value/selected went\n * stale after user interaction).\n *\n * Browsers detach a form control's live property from its attribute once the\n * control is \"dirty\" (the user — or script — has touched it): the attribute\n * becomes only the *default*. An attribute-only reconciler therefore updates\n * `checked=\"\"` / `value=\"…\"` / `selected=\"\"` while the visible state stays\n * stale.\n *\n * The rule: callers invoke this ONLY at the moment they actually MUTATE one of\n * these attributes (set, change, or remove). The property then follows the\n * attribute. Attribute-unchanged elements are never touched, so uncontrolled\n * usage — JSX that never mentions the attribute — keeps user-driven state\n * exactly as before. This is the same philosophy as the user-agent-owned\n * `open` carve-out on `<details>`/`<dialog>`: kerf only touches what the\n * template expressed an opinion about.\n *\n * The focused-element exception: a focused text-entry control's `value` is the\n * user's in-progress edit — the morph's preservation rule owns it, so `value`\n * sync is skipped for `document.activeElement`.\n */\nexport function syncFormProp(\n el: Element,\n name: string,\n value: string,\n present: boolean,\n): void {\n const tag = el.tagName;\n if (name === 'checked') {\n if (tag === 'INPUT') (el as HTMLInputElement).checked = present;\n } else if (name === 'value') {\n if (tag === 'INPUT' && el !== document.activeElement) {\n (el as HTMLInputElement).value = present ? value : '';\n }\n } else if (name === 'selected') {\n if (tag === 'OPTION') (el as HTMLOptionElement).selected = present;\n }\n}\n","/**\n * URL-attribute screening, shared by the JSX runtime's static-attribute\n * serializer (`renderAttr` in `jsx-runtime.ts`) and the fine-grained binding's\n * live-attribute writer (`setBoundAttr` in `bindings.ts`) — KF-297.\n *\n * A stored-XSS payload like `href={userInput}` with `javascript:alert(1)` is\n * dropped (attribute omitted from the string / removed from the live node)\n * rather than written. `raw(...)` / `SafeHtml` values bypass this — the\n * documented opt-out for legitimate cases (bookmarklet builders, values\n * sanitized by a separate trust layer).\n *\n * The screen is a scheme allow/deny check, not a full URL sanitizer, but it is\n * hardened against the obfuscations a real browser sees through:\n *\n * - **Control-character / whitespace obfuscation of the scheme.** Browsers\n * strip leading C0 controls + spaces and remove TAB/LF/CR from anywhere in\n * a URL before resolving the scheme, so `java\\tscript:`, `\\x01javascript:`,\n * and `javascript\\x00:` all resolve to `javascript:`. We normalize the same\n * way (strip every C0 control 0x00-0x1F + DEL, trim leading whitespace)\n * BEFORE extracting the scheme, so none of those slip past.\n *\n * - **`data:` is subtype-specific.** `data:image/png` in `<img src>` is safe\n * and common; `data:text/html` / `data:image/svg+xml` / `data:*xml` load as\n * a document and run script (SVG `<script>`, HTML/XHTML `<script>`). We\n * allowlist the inert media families (raster images, fonts, audio, video,\n * plain text/css) and drop every other `data:` — so a novel dangerous\n * subtype fails closed.\n */\n\nimport { isDevMode } from './devMode.js';\n\n/**\n * URL-bearing HTML/SVG attributes whose plain-string values are screened.\n * `data` covers `<object data>` (loads its target as a document, so\n * `data:text/html` there executes). Image-context URL attributes\n * (`srcset` / `poster` / `background` / `ping`) are intentionally NOT screened:\n * a `javascript:` / `data:` value in them does not execute as script in modern\n * browsers, so screening would add false positives without closing a real sink.\n */\nconst URL_ATTRS = new Set(['href', 'src', 'xlink:href', 'formaction', 'action', 'data']);\n\n/** Schemes that execute script when a browser resolves them as a URL. */\nconst DANGEROUS_SCHEMES = new Set(['javascript', 'vbscript']);\n\n/** Matches every C0 control character (0x00-0x1F) and DEL (0x7F). */\n// eslint-disable-next-line no-control-regex -- deliberately matching C0 + DEL.\nconst CONTROL_CHARS = /[\\u0000-\\u001F\\u007F]/g;\n\n/**\n * Normalize a URL the way a browser does before scheme resolution: remove every\n * C0 control (0x00-0x1F) and DEL (0x7F) from anywhere — no legitimate URL\n * carries a raw control char (they must be percent-encoded), so this collapses\n * `java\\tscript:` / `\\x01javascript:` / `javascript\\x00:` back to their real\n * scheme — then trim leading whitespace. Internal spaces are left intact: a\n * space is not a valid scheme character, so a browser treats `java script:` as\n * a relative URL, not the `javascript:` scheme, and we must not \"repair\" it\n * into a false positive.\n */\nfunction normalizeUrl(value: string): string {\n return value.replace(CONTROL_CHARS, '').replace(/^\\s+/, '');\n}\n\n/** The lowercased URL scheme (text before the first `:`), or null if none. */\nfunction extractScheme(value: string): string | null {\n const m = /^([a-zA-Z][a-zA-Z0-9+.-]*):/.exec(normalizeUrl(value));\n return m ? m[1].toLowerCase() : null;\n}\n\n/**\n * True if a `data:` URL is a script-executing document type. Allowlists the\n * inert media families and fails closed on everything else — so `text/html`,\n * `image/svg+xml`, XHTML/XML, and any unknown/novel subtype are all treated as\n * dangerous, while `data:image/png` / fonts / audio / video / plain text pass.\n */\nfunction isDangerousDataUrl(value: string): boolean {\n const media = /^data:([^;,]*)/.exec(normalizeUrl(value).toLowerCase())?.[1].trim() ?? '';\n if (media === '' || media === 'text/plain' || media === 'text/css') return false;\n if (media === 'image/svg+xml') return true; // SVG can carry <script>\n if (media.startsWith('image/')) return false;\n if (media.startsWith('font/') || media.startsWith('application/font')) return false;\n if (media.startsWith('audio/') || media.startsWith('video/')) return false;\n return true; // text/html, application/xhtml+xml, *xml, unknown → block\n}\n\n/** True if `value` is a dangerous URL for the URL-bearing attribute `name`. */\nexport function isDangerousUrlValue(name: string, value: string): boolean {\n if (!URL_ATTRS.has(name)) return false;\n const scheme = extractScheme(value);\n if (scheme === null) return false;\n if (DANGEROUS_SCHEMES.has(scheme)) return true;\n return scheme === 'data' && isDangerousDataUrl(value);\n}\n\n/**\n * The shared warning body for a dropped dangerous URL. Each caller prefixes\n * its own context (`JSX:` for the string serializer, `kerf binding:` for the\n * live-attribute writer).\n */\nexport function dangerousUrlWarning(name: string, value: string): string {\n return `dropped dangerous URL value for ${name}=${JSON.stringify(value.slice(0, 80))}. `\n + 'kerf blocks javascript:, vbscript:, and script-executing data: URLs '\n + '(text/html, image/svg+xml, xml) in href/src/data/formaction/action/xlink:href by default. '\n + 'Wrap in raw() if this is intentional (e.g. bookmarklets), or sanitize upstream.';\n}\n\n/**\n * Report a screened dangerous URL, with the dev-vs-prod split (KF-340). Both\n * call sites (the JSX string serializer's `renderAttr` and the live-attribute\n * writer's `setBoundAttr`) still DROP the attribute; this only chooses how the\n * screen surfaces the diagnostic:\n *\n * - **DEV** (`isDevMode()` — default under `NODE_ENV !== 'production'`, or a\n * `globalThis.KERF_DEV === true` override): THROW an `Error` with the\n * diagnostic, failing loudly at the developer's desk so a mistyped/unsafe\n * URL can't slip by unnoticed (nobody reads the console).\n * - **PRODUCTION** (`globalThis.KERF_DEV === false`, or `NODE_ENV ===\n * 'production'`): `console.warn` and let the caller drop — never crash a\n * shipped app on attacker-influenced data.\n *\n * `context` is the caller's prefix (`JSX`/`kerf binding`); the composed message\n * is byte-identical to the pre-KF-340 warn text in production.\n */\nexport function reportDangerousUrl(context: string, name: string, value: string): void {\n const message = `${context}: ${dangerousUrlWarning(name, value)}`;\n if (isDevMode()) throw new Error(message);\n console.warn(message);\n}\n","/**\n * Fine-grained signal bindings (KF-294 spike).\n *\n * When a `Signal` is interpolated straight into a JSX attribute\n * (`class={sig}`) or a text child (`{sig}`) INSIDE a `mount()` render, the\n * JSX runtime stops stringifying it. Instead it emits a marker into the HTML\n * string and records a binding here; after the string is parsed to DOM, a\n * wiring pass attaches one `effect` per binding that writes straight to the\n * live node. A later change to that signal then updates the node WITHOUT\n * re-running the render function or walking the list reconciler.\n *\n * This reuses the \"marker in string, wire up after parse\" mechanism the\n * keyed-list reconciler already uses for `<!--kf-list:{id}-->` markers.\n *\n * TWO SCOPES of binding, with disjoint marker namespaces so their wiring\n * passes never collide:\n *\n * - GLOBAL holes — signals in the static surrounds (outside any `each()`\n * row). Markers: `data-kfb` attribute / `<!--kfb:{id}-->` comment. Ids come\n * from the mount render context's counter; wired by `wireBindings()` over\n * the whole mount root; disposed/re-wired by `mount()` each render.\n *\n * - ROW holes — signals inside an `each()` row. Markers: `data-kfbrow`\n * attribute / `<!--kfbr:{id}-->` comment. Ids are row-LOCAL (reset per row)\n * so they stay stable and collision-free as rows are inserted/removed/moved.\n * Captured per row by `captureRowBindings()`, carried on the list segment\n * item, and wired/disposed by the list reconciler at each row node's\n * create/remove — so a binding's lifetime tracks its row node's lifetime,\n * and row reorders (which reuse the same node) are free.\n *\n * Outside a `mount()` render (SSR / `SafeHtml.toString()`) neither scope is\n * active: the runtime snapshots `signal.value` and emits no markers, so server\n * output is correct and legacy `.toString()` callers are unaffected.\n *\n * Module-level mutable state note: `context` / `rowSink` (plus `rowCounter`,\n * the row-hole id counter that resets with each row capture) are a third\n * sanctioned module-level mutable location (alongside `store.ts:REGISTRY` and\n * `each.ts:context`). They hold the current render's binding sinks and are set\n * / cleared by `mount()` and `each()` around the render calls. The only other\n * module-level container here is `insertedTextNodes`, a WeakMap keyed on text\n * marker comments — a pure cache whose entries die with their nodes (GC-tied\n * lifetime), so it carries no cross-render semantics.\n */\n\nimport { effect, isSignal, type Signal } from './reactive.js';\nimport { syncFormProp } from './utils/syncFormProp.js';\nimport { isDangerousUrlValue, reportDangerousUrl } from './utils/urlScreen.js';\n\n// RESERVED NAMESPACE (consumer contract, KF-314). The wiring pass finds these\n// markers by scanning the mounted subtree and matching by id, and resolves an\n// id collision by document order (last/first wins) with no ownership check — so\n// a consumer element that carries `data-kfb`/`data-kfbrow`, or a comment\n// beginning `kfb:`/`kfbr:`/`kf-list:`, can collide with a real binding's id and\n// steal its effect (the update wires to the wrong node). These names are\n// therefore reserved: consumers must not emit them (documented in\n// docs/2-reactivity.md § \"Reserved marker names\"). Kerf's own escaping already\n// prevents a plain text/attribute *value* from forging one; the remaining ways\n// in are a hand-written attribute or a `raw()` payload — i.e. the consumer's\n// own trust boundary. A dev-mode collision warning is a possible future\n// enhancement (fix direction (a) on KF-314) if silent mis-wiring proves easy to\n// hit in practice.\n\n/** Marker attribute for GLOBAL (static-surround) attribute bindings. */\nexport const BIND_ATTR = 'data-kfb';\n/** Comment-marker prefix for a GLOBAL text binding: `<!--kfb:{id}-->`. */\nexport const TEXT_MARKER_PREFIX = 'kfb:';\n/** Marker attribute for ROW (each()-scoped) attribute bindings. */\nexport const BIND_ATTR_ROW = 'data-kfbrow';\n/** Comment-marker prefix for a ROW text binding: `<!--kfbr:{id}-->`. */\nexport const ROW_TEXT_PREFIX = 'kfbr:';\n\ninterface AttrBinding {\n kind: 'attr';\n id: string;\n attr: string;\n signal: Signal<unknown>;\n}\ninterface TextBinding {\n kind: 'text';\n id: string;\n signal: Signal<unknown>;\n}\nexport type Binding = AttrBinding | TextBinding;\n\n/**\n * Per-render GLOBAL binding sink. `counter` assigns ids by registration order\n * (stable across renders since the JSX render is deterministic); `list`\n * accumulates this render's global (static-surround) holes.\n */\nexport interface BindingContext {\n counter: number;\n list: Binding[];\n}\n\nlet context: BindingContext | null = null;\n\n// Active row-capture sink + its row-local id counter. Non-null only while\n// `each()` renders a single row through `captureRowBindings()`.\nlet rowSink: Binding[] | null = null;\nlet rowCounter = 0;\n\n// Frozen shared sentinel for the no-holes case — readonly so no caller can\n// push into it and corrupt every other no-hole mount.\nconst NO_DISPOSERS: ReadonlyArray<() => void> = Object.freeze([]);\n\nexport function newBindingContext(): BindingContext {\n return { counter: 0, list: [] };\n}\n\nexport function _setBindingContext(c: BindingContext | null): void {\n context = c;\n}\n\n/**\n * Render one `each()` row while capturing the row-scoped bindings it emits.\n * Row ids are local (reset to 0) so they're stable + collision-free per row.\n * Returns the row HTML and its captured bindings (empty when the row has no\n * signal holes). Restores the prior capture state (supports nested `each()`).\n */\nexport function captureRowBindings(renderRow: () => string): { html: string; bindings: Binding[] } {\n const prevSink = rowSink;\n const prevCounter = rowCounter;\n rowSink = [];\n rowCounter = 0;\n try {\n const html = renderRow();\n return { html, bindings: rowSink };\n } finally {\n rowSink = prevSink;\n rowCounter = prevCounter;\n }\n}\n\n/**\n * Register a signal attribute. Routes to the row sink when a row capture is\n * active, else the global context. Returns the marker id,\n * or null to snapshot. The marker attribute NAME (`data-kfb` vs `data-kfbrow`)\n * is fetched once per element via `bindMarkerAttr()` — all of an element's\n * signal attrs share the same scope — so this avoids a per-attr object alloc.\n */\nexport function bindAttr(attr: string, signal: Signal<unknown>): string | null {\n if (rowSink !== null) {\n const id = `a${rowCounter++}`;\n rowSink.push({ kind: 'attr', id, attr, signal });\n return id;\n }\n if (context !== null) {\n const id = `a${context.counter++}`;\n context.list.push({ kind: 'attr', id, attr, signal });\n return id;\n }\n return null;\n}\n\n/**\n * The marker attribute name for the currently-active binding scope — row holes\n * use `data-kfbrow`, global holes `data-kfb`. Called once per element by the\n * JSX runtime after collecting the element's signal-attr ids.\n */\nexport function bindMarkerAttr(): string {\n return rowSink !== null ? BIND_ATTR_ROW : BIND_ATTR;\n}\n\n/**\n * Register a signal text hole. Returns the comment-marker HTML to emit, or\n * null to snapshot. Same routing as `bindAttr()`.\n */\nexport function bindText(signal: Signal<unknown>): string | null {\n if (rowSink !== null) {\n const id = `t${rowCounter++}`;\n rowSink.push({ kind: 'text', id, signal });\n return `<!--${ROW_TEXT_PREFIX}${id}-->`;\n }\n if (context !== null) {\n const id = `t${context.counter++}`;\n context.list.push({ kind: 'text', id, signal });\n return `<!--${TEXT_MARKER_PREFIX}${id}-->`;\n }\n return null;\n}\n\n/**\n * Wire this render's GLOBAL bindings against the freshly-built live DOM.\n * Disposes `prevDisposers` first (a surrounds-changed morph strips bound attrs\n * and removes inserted text nodes, so we re-establish them), then attaches one\n * effect per hole. Zero-cost when there are no global holes.\n */\nexport function wireBindings(\n rootEl: Element,\n ctx: BindingContext,\n prevDisposers: ReadonlyArray<() => void>,\n): ReadonlyArray<() => void> {\n for (const d of prevDisposers) d();\n if (ctx.list.length === 0) return NO_DISPOSERS;\n const disposers: Array<() => void> = [];\n wireInto(rootEl, ctx.list, disposers);\n return disposers;\n}\n\n/**\n * Wire one row's ROW-scoped bindings against its freshly-built row node\n * (including the node itself, since a row's top-level element may carry the\n * marker, e.g. `<tr data-kfbrow>`). Returns the row's disposers for the\n * reconciler to store on the bound item and call when the row node is removed.\n */\nexport function wireRowBindings(rowNode: Element, bindings: Binding[]): Array<() => void> {\n // Callers (snapshot buildFreshNodes, mount first-render inline) only invoke\n // this for rows with at least one binding, so no empty-guard is needed.\n //\n // Hot path: most row holes are an attribute on the row's ROOT element (e.g.\n // `<tr class={sig}>`). For those we resolve the node with a single\n // `getAttribute` + allocation-free id membership check — no `querySelectorAll`,\n // no `collectComments` walk, no Map. The descendant-attr index and the\n // text-comment index are built lazily, only if a hole actually needs them.\n const disposers: Array<() => void> = new Array(bindings.length);\n const rootIds = rowNode.getAttribute(BIND_ATTR_ROW);\n // For the common single-root-binding row, `rootIds === b.id` resolves the\n // node with zero allocation. Only a row with 2+ root bindings builds the Set.\n let rootIdSet: Set<string> | null = null;\n let descIndex: Map<string, Element> | null = null;\n let textMarkers: Map<string, Comment> | null = null;\n\n for (let i = 0; i < bindings.length; i++) {\n const b = bindings[i];\n if (b.kind === 'attr') {\n let onRoot = false;\n if (rootIds !== null) {\n if (rootIds === b.id) {\n onRoot = true;\n } else if (rootIds.indexOf(',') !== -1) {\n rootIdSet ??= new Set(rootIds.split(','));\n onRoot = rootIdSet.has(b.id);\n }\n }\n let el: Element | undefined;\n if (onRoot) {\n el = rowNode;\n } else {\n descIndex ??= indexAttrEls(rowNode, BIND_ATTR_ROW);\n el = descIndex.get(b.id);\n }\n /* c8 ignore next -- defensive: a registered binding always emits its marker into the row. */\n if (el === undefined) continue;\n disposers[i] = attachAttrEffect(el, b.attr, b.signal);\n } else {\n if (textMarkers === null) {\n textMarkers = new Map();\n collectComments(rowNode, ROW_TEXT_PREFIX, textMarkers);\n }\n const marker = textMarkers.get(b.id);\n /* c8 ignore next -- defensive: same invariant as the attr branch. */\n if (marker === undefined) continue;\n disposers[i] = attachTextEffect(marker, b.signal);\n }\n }\n return disposers;\n}\n\n/** Dispose a row's binding effects (called when its node leaves the DOM). */\nexport function disposeRowBindings(disposers: Array<() => void> | undefined): void {\n if (disposers === undefined) return;\n for (const d of disposers) d();\n}\n\n/**\n * KF-347 — decide, for a row whose DOM node survives an in-place update,\n * whether the live binding effects can be carried forward or must be\n * re-wired. The old effects closed over the signal INSTANCES captured at the\n * previous render; if this render's bindings reference the same instances\n * per hole (the cache-hit case, and rows binding stable external signals),\n * the old effects remain correct and re-wiring would be wasted work — the\n * select-row hot path stays free. If any hole's instance changed — the\n * typical shape after `arraySignal.update()` swaps the row object and the\n * row re-renders fresh `computed`s closing over the NEW item — the old\n * effects are stale (they'd keep reading the pre-update row), so dispose\n * them and wire the fresh bindings against the surviving node. Marker\n * alignment holds across every in-place route: row-local binding ids are\n * deterministic per render, the surgical fast paths leave marker attrs and\n * comments untouched, and `_morphElement` syncs them.\n *\n * Also covers the from-scratch case (`oldBindings` undefined with fresh\n * `newBindings`): the length mismatch routes to the wire branch, so a\n * replaceChild caller can hand its brand-new node straight here.\n */\nexport function carryOrRewireRowBindings(\n node: Element,\n oldBindings: Binding[] | undefined,\n oldDisposers: Array<() => void> | undefined,\n newBindings: Binding[] | undefined,\n): { bindings: Binding[] | undefined; bindingDisposers: Array<() => void> | undefined } {\n const oldLen = oldBindings === undefined ? 0 : oldBindings.length;\n const newLen = newBindings === undefined ? 0 : newBindings.length;\n if (oldLen === newLen) {\n let same = true;\n for (let i = 0; i < newLen; i++) {\n if ((oldBindings as Binding[])[i].signal !== (newBindings as Binding[])[i].signal) {\n same = false;\n break;\n }\n }\n if (same) return { bindings: oldBindings, bindingDisposers: oldDisposers };\n }\n disposeRowBindings(oldDisposers);\n return {\n bindings: newBindings,\n bindingDisposers: newLen > 0 ? wireRowBindings(node, newBindings as Binding[]) : undefined,\n };\n}\n\n/**\n * GLOBAL-scope wiring core. Indexes `data-kfb`-marked elements + `kfb:`\n * comment markers under `scope` by binding id, then attaches an effect per\n * binding. Row-scope wiring lives in `wireRowBindings` (with its own inlined\n * root-attr fast path), so this always operates on the GLOBAL marker names.\n */\nfunction wireInto(\n scope: Element,\n bindings: Binding[],\n disposers: Array<() => void>,\n): void {\n const attrEls = indexAttrEls(scope, BIND_ATTR);\n const textMarkers = new Map<string, Comment>();\n collectComments(scope, TEXT_MARKER_PREFIX, textMarkers);\n\n for (const b of bindings) {\n if (b.kind === 'attr') {\n const el = attrEls.get(b.id);\n /* c8 ignore next -- defensive: a registered binding always emits its marker into `scope`. */\n if (el === undefined) continue;\n disposers.push(attachAttrEffect(el, b.attr, b.signal));\n } else {\n const marker = textMarkers.get(b.id);\n /* c8 ignore next -- defensive: same invariant as the attr branch. */\n if (marker === undefined) continue;\n disposers.push(attachTextEffect(marker, b.signal));\n }\n }\n}\n\n/**\n * Index every DESCENDANT element under `scope` carrying `attrName` by binding\n * id. Callers that also need the scope root itself check it separately (row\n * roots via the `rootIds` fast path; global holes are never on the mount root).\n */\nfunction indexAttrEls(scope: Element, attrName: string): Map<string, Element> {\n const map = new Map<string, Element>();\n for (const el of scope.querySelectorAll(`[${attrName}]`)) {\n for (const id of (el.getAttribute(attrName) as string).split(',')) map.set(id, el);\n }\n return map;\n}\n\n/** Attach a fine-grained attribute effect; returns its disposer. */\nfunction attachAttrEffect(el: Element, attr: string, signal: Signal<unknown>): () => void {\n return effect(() => setBoundAttr(el, attr, signal.value));\n}\n\n/**\n * Tracks the live text node each text-hole marker owns, so RE-wiring a hole\n * (KF-347 — an in-place row update whose binding instances changed) reuses\n * the node it inserted the first time instead of stacking a second one next\n * to it. Keyed on the marker comment: markers persist exactly as long as\n * their row/surround nodes do, so the WeakMap entries die with them.\n */\nconst insertedTextNodes = new WeakMap<Comment, Text>();\n\n/**\n * The live text node `marker` currently owns, or null (KF-374 — morph drops\n * static siblings of a bound hole). Position-strict, same rule as the reuse\n * check below: the node counts as owned only while it still sits at\n * `marker.nextSibling`. The morph's child pairing uses this to step PAST the\n * binding-inserted node — the template never contains it (templates carry\n * only the marker comment), so without the skip a template static sibling\n * pairs positionally with the inserted node, the morph overwrites the bound\n * text with the static content, and the real static sibling falls off the\n * cursor's tail and is removed.\n */\nexport function boundTextNodeOf(marker: Comment): Text | null {\n const t = insertedTextNodes.get(marker);\n return t !== undefined && marker.nextSibling === t ? t : null;\n}\n\n/**\n * Bind a live text node after `marker` to `signal`; returns the effect\n * disposer. Reuses the marker's previously-inserted node when it is still\n * exactly where we put it (`marker.nextSibling`) — a rewire then just\n * retargets the write, preserving node identity. Anything else (fresh parse,\n * node removed by a morph) inserts anew. The reuse check is deliberately\n * position-strict so a static text node that legitimately follows the marker\n * in template output can never be hijacked: static content sits at\n * `nextSibling` only until the FIRST wiring inserts our node in front of it.\n */\nfunction attachTextEffect(marker: Comment, signal: Signal<unknown>): () => void {\n let text = insertedTextNodes.get(marker);\n if (text === undefined || marker.nextSibling !== text) {\n text = (marker.ownerDocument as Document).createTextNode('');\n (marker.parentNode as Node).insertBefore(text, marker.nextSibling);\n insertedTextNodes.set(marker, text);\n }\n const node = text;\n return effect(() => { node.data = coerceText(signal.value); });\n}\n\n/**\n * Apply a bound value to a live attribute, mirroring the JSX runtime's\n * `renderAttr` rules: boolean/nullish toggling, `SafeHtml` (raw()) unwrapping,\n * and the KF-297 URL-screening that drops `javascript:` / `vbscript:` /\n * `data:text/html` on `href`/`src`/`formaction`/`action`/`xlink:href`.\n *\n * Unlike `renderAttr` (which builds an HTML string, so escapes with\n * `escapeAttr`), this writes the RAW value via `setAttribute` — the DOM stores\n * attribute values verbatim, so no HTML-escaping is applied here.\n *\n * The attribute NAME is trusted here: `on*` and malformed names are rejected at\n * binding-registration time in the JSX runtime's `jsx()` signal branch (shared\n * `assertEmittableAttrName`, KF-322), so `setAttribute('onclick', …)` — which\n * would install a live inline handler — can never reach this writer.\n */\nfunction setBoundAttr(el: Element, name: string, value: unknown): void {\n // KF-335: every attribute write below also syncs the matching form-state\n // property (checked/value/selected) — after user interaction the dirty flag\n // detaches the property from the attribute, so an attribute-only write\n // leaves the visible state stale. `syncFormProp` no-ops for other names.\n if (value == null || value === false) {\n el.removeAttribute(name);\n syncFormProp(el, name, '', false);\n return;\n }\n if (value === true) {\n el.setAttribute(name, '');\n syncFormProp(el, name, '', true);\n return;\n }\n // SafeHtml (raw()) is the documented opt-out — bypasses URL screening and is\n // written verbatim, matching renderAttr's SafeHtml branch.\n if (isSafeHtmlValue(value)) {\n el.setAttribute(name, value.__html);\n syncFormProp(el, name, value.__html, true);\n return;\n }\n const str = String(value);\n if (isDangerousUrlValue(name, str)) {\n // KF-340: throw in dev (fail loudly), warn+drop in prod.\n reportDangerousUrl('kerf binding', name, str);\n el.removeAttribute(name);\n return;\n }\n el.setAttribute(name, str);\n syncFormProp(el, name, str, true);\n}\n\n// Cross-bundle SafeHtml brand check (mirrors jsx-runtime's `isSafeHtml`).\n// Duplicated here — rather than importing `isSafeHtml` from jsx-runtime — to\n// keep the bindings ← jsx-runtime dependency acyclic. `Symbol.for` makes it\n// recognize SafeHtml instances from any copy of the module.\nconst SAFE_HTML_BRAND = Symbol.for('kerfjs.SafeHtml');\nfunction isSafeHtmlValue(v: unknown): v is { __html: string } {\n return typeof v === 'object' && v !== null\n && (v as Record<symbol, unknown>)[SAFE_HTML_BRAND] === true;\n}\n\n/** Coerce a bound text value: nullish + boolean render nothing (React-style). */\nfunction coerceText(value: unknown): string {\n if (value == null || typeof value === 'boolean') return '';\n return String(value);\n}\n\n/**\n * Collect comment markers with the given prefix under `node`, keyed by id.\n * Hand-rolled recursion (same as `mount.ts`'s comment walker) because\n * happy-dom's `TreeWalker` does not surface comment nodes.\n */\nfunction collectComments(node: Node, prefix: string, out: Map<string, Comment>): void {\n for (let c: Node | null = node.firstChild; c !== null; c = c.nextSibling) {\n if (c.nodeType === Node.COMMENT_NODE) {\n const data = (c as Comment).data;\n if (data.startsWith(prefix)) out.set(data.slice(prefix.length), c as Comment);\n } else if (c.nodeType === Node.ELEMENT_NODE) {\n collectComments(c, prefix, out);\n }\n }\n}\n\n// Re-exported so the JSX runtime imports signal-detection + binding\n// registration from one place.\nexport { isSignal };\n","/**\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\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 | { type: 'update'; index: number; item: object; html: string; bindings?: Binding[] }\n | { type: 'insert'; index: number; item: object; html: string; bindings?: Binding[] }\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 ? `<!--${LIST_MARKER_PREFIX}${segment.id}-->${items}` : 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') 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(child: Segment, openTag: string, closeTag: string): 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","/**\n * HTML / attribute escaping for the JSX runtime. Identical to the helpers\n * used in any reasonable HTML emitter — included here so kerf has no extra\n * runtime dependencies beyond `@preact/signals-core`.\n */\n\nexport function escapeHtml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\nexport function escapeAttr(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n}\n","/**\n * JSX → HTML / SVG attribute name aliases.\n *\n * The JSX runtime translates camelCase attributes (React convention) to\n * the kebab-case / colon-form names the browser actually wants. Anything\n * not in this map is passed through verbatim — `data-*`, `aria-*`, and\n * any custom attribute work without ceremony.\n *\n * Lives in its own module so the alias data stays a separable concern from\n * `src/jsx-runtime.ts`'s runtime logic; the bulk of `jsx-runtime.ts` was this\n * table.\n */\n\nexport const ATTR_ALIASES: Record<string, string> = {\n // HTML attributes\n className: 'class',\n htmlFor: 'for',\n httpEquiv: 'http-equiv',\n acceptCharset: 'accept-charset',\n accessKey: 'accesskey',\n autoCapitalize: 'autocapitalize',\n autoComplete: 'autocomplete',\n autoFocus: 'autofocus',\n autoPlay: 'autoplay',\n colSpan: 'colspan',\n contentEditable: 'contenteditable',\n crossOrigin: 'crossorigin',\n dateTime: 'datetime',\n defaultChecked: 'checked',\n defaultValue: 'value',\n encType: 'enctype',\n formAction: 'formaction',\n formEncType: 'formenctype',\n formMethod: 'formmethod',\n formNoValidate: 'formnovalidate',\n formTarget: 'formtarget',\n hrefLang: 'hreflang',\n inputMode: 'inputmode',\n maxLength: 'maxlength',\n minLength: 'minlength',\n noModule: 'nomodule',\n noValidate: 'novalidate',\n readOnly: 'readonly',\n referrerPolicy: 'referrerpolicy',\n rowSpan: 'rowspan',\n spellCheck: 'spellcheck',\n srcDoc: 'srcdoc',\n srcLang: 'srclang',\n srcSet: 'srcset',\n tabIndex: 'tabindex',\n useMap: 'usemap',\n\n // SVG presentation attributes (camelCase → kebab-case)\n strokeWidth: 'stroke-width',\n strokeLinecap: 'stroke-linecap',\n strokeLinejoin: 'stroke-linejoin',\n strokeDasharray: 'stroke-dasharray',\n strokeDashoffset: 'stroke-dashoffset',\n strokeMiterlimit: 'stroke-miterlimit',\n strokeOpacity: 'stroke-opacity',\n fillOpacity: 'fill-opacity',\n fillRule: 'fill-rule',\n clipPath: 'clip-path',\n clipRule: 'clip-rule',\n colorInterpolation: 'color-interpolation',\n colorInterpolationFilters: 'color-interpolation-filters',\n floodColor: 'flood-color',\n floodOpacity: 'flood-opacity',\n lightingColor: 'lighting-color',\n stopColor: 'stop-color',\n stopOpacity: 'stop-opacity',\n shapeRendering: 'shape-rendering',\n imageRendering: 'image-rendering',\n textRendering: 'text-rendering',\n pointerEvents: 'pointer-events',\n vectorEffect: 'vector-effect',\n paintOrder: 'paint-order',\n\n // SVG text/font attributes\n fontFamily: 'font-family',\n fontSize: 'font-size',\n fontStyle: 'font-style',\n fontVariant: 'font-variant',\n fontWeight: 'font-weight',\n fontStretch: 'font-stretch',\n textAnchor: 'text-anchor',\n textDecoration: 'text-decoration',\n dominantBaseline: 'dominant-baseline',\n alignmentBaseline: 'alignment-baseline',\n baselineShift: 'baseline-shift',\n letterSpacing: 'letter-spacing',\n wordSpacing: 'word-spacing',\n writingMode: 'writing-mode',\n\n // SVG marker attributes\n markerStart: 'marker-start',\n markerMid: 'marker-mid',\n markerEnd: 'marker-end',\n\n // SVG xlink (legacy but still used)\n xlinkHref: 'xlink:href',\n xlinkShow: 'xlink:show',\n xlinkActuate: 'xlink:actuate',\n xlinkType: 'xlink:type',\n xlinkRole: 'xlink:role',\n xlinkTitle: 'xlink:title',\n xlinkArcrole: 'xlink:arcrole',\n xmlBase: 'xml:base',\n xmlLang: 'xml:lang',\n xmlSpace: 'xml:space',\n xmlnsXlink: 'xmlns:xlink',\n};\n","/**\n * kerf JSX runtime.\n *\n * JSX renders to `SafeHtml`, which wraps both:\n * - `__html`: the flattened HTML string (what `toString()` returns; what\n * legacy/SSR consumers care about)\n * - `__segment`: a structured representation that distinguishes \"static\n * html\", \"keyed list\", and \"mixed\" content.\n *\n * Most renders are pure-static and the segment is just `{kind:'static',html}`.\n * When the tree contains a list (via `each()`) or a parent whose children\n * include a non-static segment, the runtime threads that structure up so\n * `mount()` can dispatch on it — running its native keyed reconciler for\n * the list parts and leaving the static surrounds to the general-purpose\n * diff.\n *\n * Configure in your `tsconfig.json`:\n *\n * \"jsx\": \"react-jsx\",\n * \"jsxImportSource\": \"kerfjs\"\n *\n * Then write JSX as you normally would — kerf provides the `jsx` /\n * `jsxs` / `jsxDEV` / `Fragment` exports the JSX transform looks for.\n */\n\nimport { bindAttr, bindMarkerAttr, bindText, isSignal } from './bindings.js';\nimport type { KerfBuiltinIntrinsicElements } from './jsx-types.js';\nimport type { ReadonlySignal, Signal } from './reactive.js';\nimport {\n flatten,\n type ListSegment,\n mergeChildSegments,\n type Segment,\n wrapWithTags,\n} from './segment.js';\nimport { escapeAttr, escapeHtml } from './utils/escapeHtml.js';\nimport { ATTR_ALIASES } from './utils/jsx-attr-aliases.js';\nimport { isDangerousUrlValue, reportDangerousUrl } from './utils/urlScreen.js';\n\n// Cross-realm/cross-bundle brand. Using `Symbol.for` (the global registry)\n// means two `SafeHtml` classes from different module copies still recognize\n// each other. Same approach React uses for `$$typeof: Symbol.for('react.element')`.\n// Without this, `instanceof SafeHtml` fails when the consumer's bundler ends\n// up loading two copies of kerf (separate barrel + jsx-runtime entries,\n// monorepo dedup misses, ESM/CJS interop, etc.).\nconst SAFE_HTML_BRAND = Symbol.for('kerfjs.SafeHtml');\n\nexport class SafeHtml {\n readonly __html: string;\n readonly __segment: Segment;\n // Branded so `isSafeHtml()` recognizes instances from any copy of this module.\n readonly [SAFE_HTML_BRAND] = true as const;\n constructor(input: string | Segment) {\n if (typeof input === 'string') {\n this.__segment = { kind: 'static', html: input };\n this.__html = input;\n } else {\n this.__segment = input;\n this.__html = flatten(input, false);\n }\n }\n toString(): string {\n return this.__html;\n }\n}\n\n/**\n * Type guard for `SafeHtml`. Prefer this over `instanceof SafeHtml` — it works\n * across module copies (e.g. when the consumer's bundler loads kerf's barrel\n * and JSX-runtime entries as independent modules).\n *\n * Security note (KF-321): this is a duck-check on the global `Symbol.for` brand,\n * so same-realm code *can* forge a \"trusted\" value — `{ [SAFE_HTML_BRAND]: true,\n * __html: '<img onerror=…>' }` passes and bypasses escaping + the URL screen.\n * This is intentional and not a vulnerability: minting the brand requires a\n * Symbol key, which no data channel (JSON.parse, form/query/localStorage,\n * structuredClone, JSON-based prototype-pollution) can produce — those all yield\n * string keys. The only way to forge it is to run JS that writes the symbol, and\n * such code can equally `import { raw }`. Forgery therefore grants no capability\n * an attacker with code execution lacks — the same posture as React's\n * `$$typeof: Symbol.for('react.element')`. The global `Symbol.for` (vs a\n * module-private symbol) is a deliberate cross-bundle-recognition tradeoff (see\n * the `SAFE_HTML_BRAND` note above); a private symbol would additionally block\n * same-realm forgery, but only closes a non-threat at the cost of that\n * recognition, so it's kept global by design.\n */\nexport function isSafeHtml(value: unknown): value is SafeHtml {\n return typeof value === 'object'\n && value !== null\n && (value as Record<symbol, unknown>)[SAFE_HTML_BRAND] === true;\n}\n\n/** Inject a pre-escaped HTML string. Use sparingly — caller is responsible for escaping. */\nexport function raw(html: string): SafeHtml {\n return new SafeHtml(html);\n}\n\n/**\n * Internal: build a `SafeHtml` representing a list segment. Used by\n * `each()` so the JSX runtime is the sole owner of `SafeHtml` construction.\n */\nexport function listSafeHtml(id: string, items: ListSegment['items']): SafeHtml {\n return new SafeHtml({ kind: 'list', id, items });\n}\n\n/**\n * Internal: build a `SafeHtml` representing a granular list segment with\n * patches (KF-92). The reconciler applies the patches to the existing\n * binding directly, skipping the per-item iteration that the snapshot\n * `listSafeHtml` requires. `items` is included for fall-through paths\n * (toString during SSR, fall-back when the binding doesn't exist yet).\n *\n * Patch HTML is rendered upstream (in `each()`) inside a try/catch — see\n * KF-99 — so by the time we get here every `update` / `insert` patch\n * already carries a `html` string, and the reconciler does no further\n * row rendering.\n */\nexport function granularListSafeHtml(\n id: string,\n items: ListSegment['items'],\n patches: NonNullable<ListSegment['patches']>,\n): SafeHtml {\n return new SafeHtml({ kind: 'list', id, items, patches });\n}\n\n// KF-294: `ReadonlySignal<unknown>` (covariant) accepts both `signal()` and\n// `computed()` values of any T handed straight into a text hole — the runtime\n// binds them fine-grained instead of stringifying.\ntype Child = SafeHtml | string | number | boolean | null | undefined | ReadonlySignal<unknown>;\ntype Children = Child | Children[];\n\ninterface Props {\n children?: Children;\n [key: string]: unknown;\n}\n\nconst VOID_TAGS = new Set([\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\n 'link', 'meta', 'source', 'track', 'wbr',\n]);\n\n/**\n * Convert a single JSX child into a Segment. Handles SafeHtml passthrough,\n * primitive coercion + escaping, arrays (recursive), and the nullish/false\n * skip cases.\n */\nfunction toSegment(child: Children): Segment {\n if (child == null || typeof child === 'boolean') return { kind: 'static', html: '' };\n // KF-294: a signal handed straight into a text position. Inside a mount\n // render, emit a comment marker and record a binding so the text node\n // updates fine-grained (no render re-run). Outside a mount (SSR/toString),\n // snapshot the current value as escaped text.\n if (isSignal(child)) {\n const marker = bindText(child);\n if (marker !== null) return { kind: 'static', html: marker };\n const v = (child as Signal<unknown>).value;\n return { kind: 'static', html: v == null || typeof v === 'boolean' ? '' : escapeHtml(String(v)) };\n }\n if (isSafeHtml(child)) {\n // Cross-bundle SafeHtml shims (KF-14 case) may have only `__html`.\n return child.__segment ?? { kind: 'static', html: child.__html };\n }\n if (typeof child === 'string') return { kind: 'static', html: escapeHtml(child) };\n if (typeof child === 'number') return { kind: 'static', html: String(child) };\n if (Array.isArray(child)) return mergeChildSegments(child.map(toSegment));\n // Catch the common mistake of passing a DOM element (e.g. the result of\n // toElement(...)) as a JSX child. The runtime renders to HTML strings, so\n // DOM nodes can't be composed — they'd silently serialize to \"\" and their\n // event listeners would be lost. Throw loudly so this can't sneak in.\n const maybeNode = child as unknown;\n if (typeof maybeNode === 'object' && maybeNode !== null\n && ('nodeType' in maybeNode || 'outerHTML' in maybeNode)) {\n throw new Error(\n 'JSX: DOM elements cannot be passed as children (the JSX runtime renders to HTML strings). '\n + 'Build the tree in one JSX expression and use querySelector after toElement() to get element refs.',\n );\n }\n throw new Error(\n `JSX: unsupported child of type ${describeValue(child)}. `\n + 'Children must be SafeHtml, string, number, boolean, null, undefined, or an array of those. '\n + 'Common mistakes: passing a Signal/Store object directly (use signal.value or store.state.value), '\n + 'passing a function (call it first), or passing a Promise (await it before render).',\n );\n}\n\nfunction describeValue(v: unknown): string {\n if (Array.isArray(v)) return 'array';\n if (typeof v === 'object' && v !== null) {\n const ctor = (v as { constructor?: { name?: string } }).constructor?.name;\n return ctor && ctor !== 'Object' ? `object (${ctor})` : 'object';\n }\n return typeof v;\n}\n\n/**\n * A well-formed HTML/SVG attribute name: a letter/underscore/colon, then\n * letters, digits, or `_.:-` — covers `class`, `data-id`, `aria-label`,\n * `xlink:href`, `xmlns:xlink`, `stroke-width`, `viewBox`, etc. A name outside\n * this shape can only come from spreading untrusted KEYS into JSX\n * (`<div {...obj}>`), and is exactly the shape that could carry the whitespace,\n * `>`, `=`, quotes, or control chars needed to break out of the open tag and\n * inject markup — so `renderAttr` rejects it (KF-306).\n */\nconst SAFE_ATTR_NAME = /^[A-Za-z_:][\\w.:-]*$/;\n\n/**\n * Reject an attribute NAME that kerf must never route into HTML or the DOM.\n * Shared by BOTH attribute paths so they enforce one contract (KF-306, KF-322):\n *\n * - the static string path (`renderAttr`) — a name is emitted verbatim into\n * the open tag, and `on*` values become live inline handlers once parsed;\n * - the fine-grained bound path (`jsx()` signal branch → `bindAttr` →\n * `setBoundAttr` → `el.setAttribute(name, …)`) — `setAttribute('onclick', …)`\n * installs a LIVE handler in the browser, an XSS vector that would otherwise\n * bypass the static guard entirely.\n *\n * Two rejections:\n * 1. `on*` (any case) — kerf's model is event delegation, never inline\n * handlers. `isFn` tailors the message: function values get the\n * delegate() migration pointer; string/signal/other values get the\n * XSS-aware message.\n * 2. a malformed name (spread of untrusted keys, `<div {...obj}>`) that could\n * break out of the open tag. The bound path can't actually inject markup\n * this way — `setAttribute` throws `InvalidCharacterError` rather than\n * parsing — but the same guard runs on both paths for one consistent\n * contract. Validated post-alias; every `ATTR_ALIASES` value is itself a\n * valid name, so aliasing is unaffected.\n */\nfunction assertEmittableAttrName(key: string, name: string, isFn: boolean): void {\n if (/^on[a-z]/i.test(name)) {\n if (isFn) {\n throw new Error(\n `JSX: inline event handlers like ${key}={fn} are not supported by kerf's JSX → HTML-string runtime. `\n + 'Use event delegation from the mount root instead:\\n\\n'\n + ' delegate(rootEl, \\'click\\', \\'[data-action=\"...\"]\\', (evt, target) => { ... });\\n'\n + ' <button data-action=\"...\">click</button>\\n\\n'\n + 'See docs/5-event-delegation.md for the tier-1/tier-2/tier-3 model.',\n );\n }\n throw new Error(\n `JSX: event-handler attribute ${JSON.stringify(key)} is not allowed — an `\n + '`on*` attribute (whether a string emitted into HTML or a signal bound via '\n + 'setAttribute) installs a live inline handler, an XSS vector. '\n + 'kerf uses event delegation: delegate(rootEl, \\'click\\', \\'[data-action=\"...\"]\\', handler). '\n + 'See docs/5-event-delegation.md.',\n );\n }\n if (!SAFE_ATTR_NAME.test(name)) {\n throw new Error(\n `JSX: invalid attribute name ${JSON.stringify(key)}. Attribute names must be a `\n + 'letter/underscore/colon followed by letters, digits, or \"_.:-\" (e.g. class, '\n + 'data-id, aria-label, xlink:href). This usually means an untrusted object was '\n + 'spread into JSX ({...obj}) with attacker-controlled keys — validate keys first.',\n );\n }\n}\n\nfunction renderAttr(key: string, value: unknown): string {\n return renderAttrNamed(key, ATTR_ALIASES[key] ?? key, value);\n}\n\n/**\n * Core attribute renderer. `key` is the author-written attribute key (used in\n * error messages); `name` is the final emitted attribute name — post-alias for\n * JSX, verbatim for the `kerfjs/html` tagged-template path.\n */\nfunction renderAttrNamed(key: string, name: string, value: unknown): string {\n if (value == null || value === false) return '';\n assertEmittableAttrName(key, name, typeof value === 'function');\n if (value === true) return ` ${name}`;\n let strValue: string;\n if (isSafeHtml(value)) {\n strValue = value.__html;\n } else if (typeof value === 'number') {\n strValue = String(value);\n } else if (typeof value === 'string') {\n // URL-screening shared with the fine-grained binding writer (KF-297).\n // `SafeHtml` values (raw()) skip this — they hit the branch above.\n // KF-340: throw in dev (fail loudly), warn+drop in prod.\n if (isDangerousUrlValue(name, value)) {\n reportDangerousUrl('JSX', name, value);\n return '';\n }\n strValue = escapeAttr(value);\n } else {\n throw new Error(\n `JSX: unsupported value for attribute \"${key}\" — got ${describeValue(value)}. `\n + 'Attribute values must be string, number, boolean, null, undefined, or SafeHtml. '\n + 'Did you mean to read .value off a Signal, or stringify the object first?',\n );\n }\n return ` ${name}=\"${strValue}\"`;\n}\n\nexport function jsx(tag: string | ((props: Props) => SafeHtml), props: Props): SafeHtml {\n if (typeof tag === 'function') return tag(props);\n\n const { children, ...attrs } = props;\n let attrStr = '';\n let bindIds: string[] | null = null;\n for (const [k, v] of Object.entries(attrs)) {\n // KF-294: a signal handed straight into an attribute. Inside a mount\n // render, register a binding and mark the element (via `data-kfb` for\n // static-surround holes / `data-kfbrow` for each()-row holes) instead of\n // emitting the attribute — the wiring pass sets it after parse and keeps\n // it fine-grained. Outside a mount, snapshot the current value.\n if (isSignal(v)) {\n const name = ATTR_ALIASES[k] ?? k;\n // Reject `on*` / malformed names on the bound path too (KF-322 completes\n // KF-306). Unconditional: a signal's value can change over time, so we\n // can't gate on the current value — an `onclick={signal}` binding would\n // otherwise install a live inline handler via setAttribute, bypassing the\n // static renderAttr guard entirely. `isFn` is false: a signal is not a\n // function value, so this routes to the XSS-aware message.\n assertEmittableAttrName(k, name, false);\n const id = bindAttr(name, v);\n if (id !== null) {\n (bindIds ??= []).push(id);\n continue;\n }\n attrStr += renderAttr(k, (v as Signal<unknown>).value);\n continue;\n }\n attrStr += renderAttr(k, v);\n }\n // All signal attrs on one element share a scope, so the marker attr name is\n // fetched once (avoids a per-attr object alloc from bindAttr).\n if (bindIds !== null) attrStr += ` ${bindMarkerAttr()}=\"${bindIds.join(',')}\"`;\n\n if (VOID_TAGS.has(tag)) return new SafeHtml(`<${tag}${attrStr}>`);\n\n const childSegment: Segment = children != null\n ? toSegment(children)\n : { kind: 'static', html: '' };\n return new SafeHtml(wrapWithTags(childSegment, `<${tag}${attrStr}>`, `</${tag}>`));\n}\n\nexport { jsx as jsxs };\n// vitest's dev-mode JSX transform emits `jsxDEV(tag, props, ...)`; the\n// alias lets tests import this module without the production build pipeline\n// caring.\nexport { jsx as jsxDEV };\n\nexport function Fragment({ children }: { children?: Children }): SafeHtml {\n return new SafeHtml(children != null ? toSegment(children) : { kind: 'static', html: '' });\n}\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace JSX {\n export type Element = SafeHtml;\n export interface ElementChildrenAttribute {\n children: unknown;\n }\n // Per-tag attribute contracts live in `./jsx-types.ts` as\n // `KerfBuiltinIntrinsicElements`. Re-exposed as an **interface** (not a\n // type alias) so consumers can declaration-merge custom-element tags\n // (KF-100):\n //\n // declare module 'kerfjs/jsx-runtime' {\n // namespace JSX {\n // interface IntrinsicElements {\n // 'my-element': KerfCustomElement & { foo?: string };\n // }\n // }\n // }\n //\n // KF-123: the imported interface is named `KerfBuiltinIntrinsicElements`\n // upstream so tsup/tsc cannot strip an import alias and end up emitting\n // `interface IntrinsicElements extends IntrinsicElements {}` in the .d.ts\n // — that shadowed form self-resolves to empty and breaks every `<tag>` in\n // consumer .tsx with TS2339. Verified against `dist/jsx-runtime.d.ts` by\n // `tests/dist/jsx-typing/` on every `npm run build`.\n // eslint-disable-next-line @typescript-eslint/no-empty-object-type\n export interface IntrinsicElements extends KerfBuiltinIntrinsicElements {}\n}\n\n/**\n * Internal coordination exports for the `kerfjs/html` tagged-template\n * front-end (`src/html.ts`). Underscore-prefixed and deliberately NOT in the\n * main barrel — the contract is that `html\\`\\`` routes through the exact same\n * value semantics as JSX (text holes: `_toSegment`; attribute holes:\n * `_assertEmittableAttrName` + `_renderAttrVerbatim`), so the two authoring\n * paths cannot drift. `_renderAttrVerbatim` skips the camelCase\n * `ATTR_ALIASES` table: template authors write real HTML attribute names\n * (`class`, not `className`).\n */\nexport function _toSegment(child: unknown): Segment {\n return toSegment(child as Children);\n}\n\nexport function _renderAttrVerbatim(name: string, value: unknown): string {\n return renderAttrNamed(name, name, value);\n}\n\nexport { assertEmittableAttrName as _assertEmittableAttrName };\n\n/**\n * Public re-exports of the JSX type primitives so consumers can compose\n * attribute interfaces for custom elements without reaching into\n * `kerfjs/jsx-types` (which is intentionally not in `package.json#exports`).\n */\nexport type {\n AttrLike,\n AttrValue,\n DataAriaAttrs,\n KerfBaseAttrs,\n KerfCustomElement,\n} from './jsx-types.js';\n"]}
|
package/dist/chunk-KFUDM3VP.js
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import { signal, isDevMode } from './chunk-NU7YHYEV.js';
|
|
2
|
-
|
|
3
|
-
// src/dev-store-warn.ts
|
|
4
|
-
var WARNING_PREFIX = "kerf: defineStore.set() called with keys missing from the current state \u2014 ";
|
|
5
|
-
var WARNING_SUFFIX = ". set() REPLACES state; the missing keys will be undefined after this call. Use `set({ ...get(), ...next })` to merge instead, or update each call site to pass the full state. Set KERF_DEV_WARN_NARROW_SET=0 (or unset it) to silence this warning.";
|
|
6
|
-
function isOptedIn() {
|
|
7
|
-
if (!isDevMode()) return false;
|
|
8
|
-
const proc = globalThis.process;
|
|
9
|
-
return proc?.env?.KERF_DEV_WARN_NARROW_SET === "1";
|
|
10
|
-
}
|
|
11
|
-
function isPlainObjectState(v) {
|
|
12
|
-
if (v === null || typeof v !== "object") return false;
|
|
13
|
-
if (Array.isArray(v)) return false;
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
function maybeWarnNarrowSet(prev, next, ctx) {
|
|
17
|
-
if (ctx.warned) return;
|
|
18
|
-
if (!isOptedIn()) return;
|
|
19
|
-
if (!isPlainObjectState(prev) || !isPlainObjectState(next)) return;
|
|
20
|
-
const missing = [];
|
|
21
|
-
for (const k of Object.keys(prev)) {
|
|
22
|
-
if (!(k in next)) missing.push(k);
|
|
23
|
-
}
|
|
24
|
-
if (missing.length === 0) return;
|
|
25
|
-
ctx.warned = true;
|
|
26
|
-
const keysList = missing.map((k) => `\`${k}\``).join(", ");
|
|
27
|
-
console.warn(`${WARNING_PREFIX}${keysList}${WARNING_SUFFIX}`);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// src/utils/devReadonly.ts
|
|
31
|
-
var RULE_MESSAGE = "kerf: store state is read-only \u2014 all writes must go through actions (build a new state object and pass it to `set()`). Mutating the object returned by `get()` is a Rule 8 violation and never notifies subscribers.";
|
|
32
|
-
var proxyToRaw = /* @__PURE__ */ new WeakMap();
|
|
33
|
-
var rawToProxy = /* @__PURE__ */ new WeakMap();
|
|
34
|
-
function isWrappable(v) {
|
|
35
|
-
if (v === null || typeof v !== "object") return false;
|
|
36
|
-
if (Array.isArray(v)) return true;
|
|
37
|
-
const proto = Object.getPrototypeOf(v);
|
|
38
|
-
return proto === Object.prototype || proto === null;
|
|
39
|
-
}
|
|
40
|
-
var handler = {
|
|
41
|
-
get(target, prop, receiver) {
|
|
42
|
-
const value = Reflect.get(target, prop, receiver);
|
|
43
|
-
return isWrappable(value) ? devReadonlyProxy(value) : value;
|
|
44
|
-
},
|
|
45
|
-
set() {
|
|
46
|
-
throw new TypeError(RULE_MESSAGE);
|
|
47
|
-
},
|
|
48
|
-
deleteProperty() {
|
|
49
|
-
throw new TypeError(RULE_MESSAGE);
|
|
50
|
-
},
|
|
51
|
-
defineProperty() {
|
|
52
|
-
throw new TypeError(RULE_MESSAGE);
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
function devReadonlyProxy(obj) {
|
|
56
|
-
if (proxyToRaw.has(obj)) return obj;
|
|
57
|
-
const cached = rawToProxy.get(obj);
|
|
58
|
-
if (cached) return cached;
|
|
59
|
-
const p = new Proxy(obj, handler);
|
|
60
|
-
rawToProxy.set(obj, p);
|
|
61
|
-
proxyToRaw.set(p, obj);
|
|
62
|
-
return p;
|
|
63
|
-
}
|
|
64
|
-
function toRaw(value) {
|
|
65
|
-
return unwrap(value);
|
|
66
|
-
}
|
|
67
|
-
function unwrap(v) {
|
|
68
|
-
if (v === null || typeof v !== "object") return v;
|
|
69
|
-
const raw = proxyToRaw.get(v);
|
|
70
|
-
if (raw !== void 0) return raw;
|
|
71
|
-
if (!isWrappable(v)) return v;
|
|
72
|
-
if (Array.isArray(v)) {
|
|
73
|
-
let changed2 = false;
|
|
74
|
-
const out2 = v.map((item) => {
|
|
75
|
-
const u = unwrap(item);
|
|
76
|
-
if (u !== item) changed2 = true;
|
|
77
|
-
return u;
|
|
78
|
-
});
|
|
79
|
-
return changed2 ? out2 : v;
|
|
80
|
-
}
|
|
81
|
-
let changed = false;
|
|
82
|
-
const src = v;
|
|
83
|
-
const out = {};
|
|
84
|
-
for (const k of Object.keys(src)) {
|
|
85
|
-
const u = unwrap(src[k]);
|
|
86
|
-
if (u !== src[k]) changed = true;
|
|
87
|
-
out[k] = u;
|
|
88
|
-
}
|
|
89
|
-
return changed ? out : v;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// src/store.ts
|
|
93
|
-
var REGISTRY = [];
|
|
94
|
-
function defineStore(spec) {
|
|
95
|
-
const internal = signal(spec.initial());
|
|
96
|
-
const warnCtx = { warned: false };
|
|
97
|
-
let devGate;
|
|
98
|
-
const isDev = () => devGate ??= isDevMode();
|
|
99
|
-
const set = (next) => {
|
|
100
|
-
const raw = isDev() ? toRaw(next) : next;
|
|
101
|
-
maybeWarnNarrowSet(internal.value, raw, warnCtx);
|
|
102
|
-
internal.value = raw;
|
|
103
|
-
};
|
|
104
|
-
const get = () => {
|
|
105
|
-
const v = internal.value;
|
|
106
|
-
if (isDev() && v !== null && typeof v === "object") {
|
|
107
|
-
return devReadonlyProxy(v);
|
|
108
|
-
}
|
|
109
|
-
return v;
|
|
110
|
-
};
|
|
111
|
-
const actions = spec.actions(set, get);
|
|
112
|
-
const store = {
|
|
113
|
-
state: internal,
|
|
114
|
-
actions,
|
|
115
|
-
reset() {
|
|
116
|
-
internal.value = spec.initial();
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
REGISTRY.push(store);
|
|
120
|
-
return store;
|
|
121
|
-
}
|
|
122
|
-
function resetAllStores() {
|
|
123
|
-
for (const s of REGISTRY) s.reset();
|
|
124
|
-
}
|
|
125
|
-
function clearStoreRegistry() {
|
|
126
|
-
REGISTRY.length = 0;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export { clearStoreRegistry, defineStore, resetAllStores };
|
|
130
|
-
//# sourceMappingURL=chunk-KFUDM3VP.js.map
|
|
131
|
-
//# sourceMappingURL=chunk-KFUDM3VP.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dev-store-warn.ts","../src/utils/devReadonly.ts","../src/store.ts"],"names":["changed","out"],"mappings":"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","file":"chunk-KFUDM3VP.js","sourcesContent":["/**\n * Dev-mode warning for partial-set violations of Hard Rule 8 (KF-212). When\n * the opt-in env var `KERF_DEV_WARN_NARROW_SET=1` is set in a non-production\n * build, `defineStore`'s `set()` calls `maybeWarnNarrowSet(prev, next, ctx)`\n * before assigning. If `next` is a plain object whose own-keys are a strict\n * subset of `prev`'s own-keys, a one-shot `console.warn` fires naming the\n * missing keys and pointing at the canonical `set({ ...get(), ...next })`\n * merge fix.\n *\n * Why opt-in: narrow-set IS legal — sometimes you want to replace state with\n * a smaller shape (a reset() that drops keys, a feature-flag-driven schema\n * change). The warn is the right shape for the canonical bug (\"I wrote\n * `set({filter})` against a replace-semantics store and wiped items+editingId\")\n * but produces false positives for intentional shape changes. Opt-in keeps\n * the warning available to dev/CI environments that want the diagnostic\n * without surprising existing projects.\n *\n * Trigger condition: ANY key in `prev` missing from `next` — strictly broader\n * than \"fewer keys total.\" A `set({a, c})` against `cur = {a, b}` (same count,\n * different keys) also wipes `b`, so it warns. The original partial-set bug\n * shape was always \"at least one key from current is missing in next\"; the\n * key-count check in the original ticket sketch was an early-exit\n * optimization, not the semantic gate.\n *\n * Skips: non-object cur/next (booleans, numbers, strings — no \"keys\" to\n * miss), null/undefined either side, and arrays either side (shrinking-array\n * replacement is normal, not a partial set).\n *\n * Per-store one-shot dedup: each store warns at most once across its\n * lifetime — matches the KF-174 / KF-176 pattern of \"tell the developer\n * about the rule violation once, then trust them to fix it.\" The dedup\n * scope is the store, not the module, so a second store can still warn\n * if it independently hits the same bug.\n *\n * Production behavior is unchanged for zero runtime cost (the env-var read\n * short-circuits before any per-set work runs).\n */\n\nimport { isDevMode } from './utils/devMode.js';\n\nexport interface NarrowSetWarnContext {\n /** Set once per store; the warner reads/writes this to enforce the per-store one-shot dedup. */\n warned: boolean;\n}\n\nconst WARNING_PREFIX\n = 'kerf: defineStore.set() called with keys missing from the current state — ';\nconst WARNING_SUFFIX\n = '. set() REPLACES state; the missing keys will be undefined after this call. '\n + 'Use `set({ ...get(), ...next })` to merge instead, or update each call site to pass the full state. '\n + 'Set KERF_DEV_WARN_NARROW_SET=0 (or unset it) to silence this warning.';\n\nexport function isOptedIn(): boolean {\n if (!isDevMode()) return false;\n const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n return proc?.env?.KERF_DEV_WARN_NARROW_SET === '1';\n}\n\nfunction isPlainObjectState(v: unknown): v is Record<string, unknown> {\n if (v === null || typeof v !== 'object') return false;\n if (Array.isArray(v)) return false;\n return true;\n}\n\nexport function maybeWarnNarrowSet(\n prev: unknown,\n next: unknown,\n ctx: NarrowSetWarnContext,\n): void {\n if (ctx.warned) return;\n if (!isOptedIn()) return;\n if (!isPlainObjectState(prev) || !isPlainObjectState(next)) return;\n\n const missing: string[] = [];\n for (const k of Object.keys(prev)) {\n if (!(k in next)) missing.push(k);\n }\n if (missing.length === 0) return;\n\n ctx.warned = true;\n const keysList = missing.map((k) => `\\`${k}\\``).join(', ');\n console.warn(`${WARNING_PREFIX}${keysList}${WARNING_SUFFIX}`);\n}\n\n/**\n * Test helper — resets the per-store `warned` flag on a context so a\n * subsequent test in the same module can re-exercise the first-warning\n * path. Not exported from the public barrel; the unit-test file imports it\n * directly via the relative path.\n */\nexport function _resetWarnContext(ctx: NarrowSetWarnContext): void {\n ctx.warned = false;\n}\n","/**\n * Dev-only deep read-only guard for `defineStore`'s `get()` snapshot.\n *\n * Replaces the older `Object.freeze(get())` guard, which had three problems:\n * it mutated (froze) the LIVE state object as a side effect of a read, so\n * external references that later legitimately mutated it threw in dev but not\n * prod; it was shallow (`get().nested.x = 1` slipped through); and freezing on\n * read is surprising. This module instead wraps the returned reference in a\n * lazy `Proxy` that:\n *\n * - throws a store-rule-specific `TypeError` on any write (`set` /\n * `deleteProperty` / `defineProperty`) — mutating the object returned by\n * `get()` is a Rule 8 violation (all writes go through actions), and now it\n * is a loud throw instead of a silent desync;\n * - lazily wraps plain-object / array property values in the SAME proxy on\n * access (deep coverage, O(1) per access, no clones), so `get().nested.x = 1`\n * also throws;\n * - leaves primitives, functions, and exotic objects (Date, Map, …) as-is, so\n * `instanceof`, `JSON.stringify`, spread, `Object.keys`, and array iteration\n * all behave exactly as on the raw object.\n *\n * The live state object is never frozen or mutated, so an external reference to\n * it stays writable. This guard is DEV-ONLY: production returns the raw\n * reference and never constructs a proxy, so its perf and semantics are\n * byte-identical to a bare object.\n *\n * `toRaw()` reverses the wrapping so a state object DERIVED from `get()` output\n * (e.g. `set({ ...get(), count: 1 })`, whose nested values are proxies handed\n * back by the `get` trap) is stored as a plain object — the internal signal\n * must never hold a Proxy.\n */\n\nconst RULE_MESSAGE\n = 'kerf: store state is read-only — all writes must go through actions '\n + '(build a new state object and pass it to `set()`). Mutating the object '\n + 'returned by `get()` is a Rule 8 violation and never notifies subscribers.';\n\n/** proxy → its raw target. Lets `toRaw()` unwrap a value derived from `get()`. */\nconst proxyToRaw = new WeakMap<object, object>();\n/** raw → its proxy. Stable proxy identity + avoids re-wrapping the same object. */\nconst rawToProxy = new WeakMap<object, object>();\n\n/** Only plain objects and arrays are wrapped; exotic objects pass through untouched. */\nfunction isWrappable(v: unknown): v is object {\n if (v === null || typeof v !== 'object') return false;\n if (Array.isArray(v)) return true;\n const proto = Object.getPrototypeOf(v) as unknown;\n return proto === Object.prototype || proto === null;\n}\n\nconst handler: ProxyHandler<object> = {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver) as unknown;\n return isWrappable(value) ? devReadonlyProxy(value) : value;\n },\n set() {\n throw new TypeError(RULE_MESSAGE);\n },\n deleteProperty() {\n throw new TypeError(RULE_MESSAGE);\n },\n defineProperty() {\n throw new TypeError(RULE_MESSAGE);\n },\n};\n\n/** Wrap `obj` in the dev read-only proxy (idempotent, identity-stable per raw). */\nexport function devReadonlyProxy<T extends object>(obj: T): T {\n if (proxyToRaw.has(obj)) return obj; // already a proxy — don't double-wrap\n const cached = rawToProxy.get(obj);\n if (cached) return cached as T;\n const p = new Proxy(obj, handler) as T;\n rawToProxy.set(obj, p as object);\n proxyToRaw.set(p as object, obj);\n return p;\n}\n\n/**\n * Deep-unwrap any dev read-only proxies out of `value`, preserving structural\n * sharing: returns the SAME reference when nothing was a proxy, and only\n * allocates along the path to a proxy it actually replaces. Raw targets are\n * fully plain (proxies are never stored), so unwrapping one is deep-clean.\n */\nexport function toRaw<T>(value: T): T {\n return unwrap(value) as T;\n}\n\nfunction unwrap(v: unknown): unknown {\n if (v === null || typeof v !== 'object') return v;\n const raw = proxyToRaw.get(v);\n if (raw !== undefined) return raw; // a proxy → its fully-plain raw target\n if (!isWrappable(v)) return v; // exotic object — leave as-is\n\n if (Array.isArray(v)) {\n let changed = false;\n const out = v.map((item) => {\n const u = unwrap(item);\n if (u !== item) changed = true;\n return u;\n });\n return changed ? out : v;\n }\n\n let changed = false;\n const src = v as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(src)) {\n const u = unwrap(src[k]);\n if (u !== src[k]) changed = true;\n out[k] = u;\n }\n return changed ? out : v;\n}\n","/**\n * `defineStore({ initial, actions })` — composable testable stores layered on\n * top of `reactive.ts`'s signals.\n *\n * Three rules:\n * 1. `state` is read-only. Consumers read via `state.value` or subscribe via\n * `effect()`. They cannot write directly.\n * 2. `actions` is the only mutation surface. All writes go through named\n * action functions. This is what makes stores testable — assert against\n * actions, not against arbitrary writes.\n * 3. `reset()` resets to `initial()`. Always defined; tests use it for\n * setup, lifecycle hooks (route change, sign-out, etc.) use it for\n * tear-down.\n *\n * A module-level registry tracks every store created via `defineStore()`;\n * `resetAllStores()` walks the registry and calls each `reset()`. Useful for\n * tests + project-switch / logout / route-reset scenarios where every piece\n * of client state should return to its initial shape.\n */\n\nimport { maybeWarnNarrowSet, type NarrowSetWarnContext } from './dev-store-warn.js';\nimport type { ReadonlySignal, Signal } from './reactive.js';\nimport { signal } from './reactive.js';\nimport { isDevMode } from './utils/devMode.js';\nimport { devReadonlyProxy, toRaw } from './utils/devReadonly.js';\n\nexport interface Store<TState, TActions> {\n /** Read-only reactive view. Consumers read `state.value` or subscribe via `effect()`. */\n readonly state: ReadonlySignal<TState>;\n /** Named mutators — the only way to change state. */\n readonly actions: TActions;\n /** Reset state to `initial()`. Used by tests and lifecycle hooks. */\n reset(): void;\n}\n\ninterface DefineStoreSpec<TState, TActions> {\n initial: () => TState;\n actions: (set: (next: TState) => void, get: () => Readonly<TState>) => TActions;\n}\n\nconst REGISTRY: Array<{ reset: () => void }> = [];\n\nexport function defineStore<TState, TActions>(\n spec: DefineStoreSpec<TState, TActions>,\n): Store<TState, TActions> {\n const internal: Signal<TState> = signal(spec.initial());\n // KF-212: per-store one-shot dedup for the opt-in narrow-set warning.\n // Default off; consumers opt in via `KERF_DEV_WARN_NARROW_SET=1` in dev.\n // Production behavior is unchanged — `maybeWarnNarrowSet` short-circuits\n // on the env-var read before any per-set work runs.\n const warnCtx: NarrowSetWarnContext = { warned: false };\n\n // The dev gate is resolved once per store, lazily on first `set()`/`get()`\n // (so a runtime `globalThis.KERF_DEV` override set before mount is honored),\n // then cached — the prod hot path stays a bare boolean read, never a\n // per-call env probe.\n let devGate: boolean | undefined;\n const isDev = (): boolean => (devGate ??= isDevMode());\n\n const set = (next: TState): void => {\n // In dev, `next` may carry proxies handed back by the `get()` trap (e.g.\n // `set({ ...get(), count: 1 })`). Unwrap them so the internal signal only\n // ever holds a plain object — the narrow-set warning and every consumer\n // read see raw state, never a Proxy. Prod stores the bare reference.\n const raw = isDev() ? toRaw(next) : next;\n maybeWarnNarrowSet(internal.value, raw, warnCtx);\n internal.value = raw;\n };\n // In dev, wrap the reference returned to actions in a deep read-only Proxy so\n // that `get().count = 42` / `get().nested.x = 1` (documented Rule 8\n // violations) throw a `TypeError` instead of silently landing on the\n // underlying state without notifying subscribers. The live state object is\n // never frozen or mutated, so external references to it stay writable.\n // Production returns the bare reference for zero overhead (no proxy).\n const get = (): Readonly<TState> => {\n const v = internal.value;\n if (isDev() && v !== null && typeof v === 'object') {\n return devReadonlyProxy(v as TState & object);\n }\n return v;\n };\n\n const actions = spec.actions(set, get);\n\n const store: Store<TState, TActions> = {\n state: internal,\n actions,\n reset() {\n internal.value = spec.initial();\n },\n };\n\n REGISTRY.push(store);\n return store;\n}\n\n/**\n * Reset every store registered via `defineStore()` to its `initial()` value.\n * Used by tests and by application lifecycle hooks (project switch, logout,\n * route reset).\n */\nexport function resetAllStores(): void {\n for (const s of REGISTRY) s.reset();\n}\n\n/**\n * Test helper — clears the registry. Exposed via the `kerfjs/testing` subpath,\n * not the main `kerfjs` entry. Unit tests use it to isolate stores between cases.\n */\nexport function clearStoreRegistry(): void {\n REGISTRY.length = 0;\n}\n"]}
|