@kudzujs/core 0.12.1 → 0.12.3

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/PERFORMANCE.md CHANGED
@@ -6,6 +6,53 @@ Reproducibility classes: `npm run benchmark`, `npm run benchmark:keyed`, `npm ru
6
6
 
7
7
  The maintained 2026-08-13 comparison used Node 24.14.0 and an Intel Core i5-9500 Linux x64 host, one warm-up, and seven alternating fresh-process samples against clean `v0.8.44`. A narrow fast path skips Kudzu semantic transformation for 450 plain `.ts` modules whose runtime edges are exclusively resolvable relative TypeScript imports or exports; all other modules retain the existing transformer. Compile median fell from 2,323.9 ms to 1,413.2 ms (39.2%) and clean-build median from 3,325.3 ms to 2,382.4 ms (28.4%); every paired sample improved. Compile peak-RSS median fell from 571.2 MiB to 552.6 MiB, while build peak RSS was 570.9 MiB versus 568.8 MiB. Compiler scratch fell from 7,328,390 to 1,971,061 bytes. Both targets emitted the same 50 static HTML files, 10,980 bytes, and deploy SHA-256 `e107d78a7f55bc8a1af0ea6e53efeffa19b3d44d21c892484d103fa346e7ba7b`. This is a source-scale compiler comparison, not a cross-framework result.
8
8
 
9
+ ## 0.12.3 Route Failure And Restoration Policy
10
+
11
+ Measured 2026-08-24 on Linux x64 with Node 24.14.0 and Chrome
12
+ 142.0.7444.175. Required Chrome proves current-document retention for fetch and
13
+ response-body transport failures, accessible failure status, restored link
14
+ focus, retry after a failed pending prefetch, invalid-document fallback,
15
+ capability-module fallback, stylesheet fallback, and no pre-commit route
16
+ removal. The maintained application-owned HTTP 500 alert and explicit data
17
+ retry continue to pass.
18
+
19
+ The two-route session uses 16 JavaScript files totaling 61,126 raw / 22,663
20
+ aggregate gzip bytes, an increase of 359 raw bytes from `0.12.2` for
21
+ transport-error classification, status, and focus restoration. The 102-byte
22
+ gzip difference is unpaired and environment-sensitive, so it is not attributed
23
+ to the patch. Navigation
24
+ samples are `[1.5, 1.6, 2.0, 1.7, 1.8, 2.4, 1.8]` ms, with a 1.8 ms median and
25
+ 1.5/2.4 ms minimum/maximum. The environment differs from the macOS arm64 Chrome
26
+ 151 `0.12.2` measurement, so no latency comparison is claimed.
27
+
28
+ The application emits 43 files totaling 123,835 raw / 45,379 aggregate gzip
29
+ bytes with deploy SHA-256
30
+ `fb9d24cc01791bf80b67b659738ba62beded6ff6ce14a86a278fa4b34d088acf`.
31
+ Core semantic LOC remains 5,682 with no semantic primitive, compiler pass, core
32
+ compiler line, runtime concept, or public API. Navigation runtime source grows
33
+ from 351 to 374 lines. `/help` remains 0 B JavaScript.
34
+
35
+ ## 0.12.2 Authentication And Permission Boundary
36
+
37
+ Measured 2026-08-23 on macOS arm64 with Node 25.6.1 and Chrome
38
+ 151.0.7922.172. Required Chrome proves invalid and valid login, token-backed
39
+ reload restoration, anonymous and rejected direct entry, role-aware controls,
40
+ server-enforced API and admin authorization, token clearing, and logout.
41
+
42
+ The two-route session uses 16 JavaScript files totaling 60,767 raw / 22,561
43
+ aggregate gzip bytes, an increase of 1,793 raw / 432 gzip bytes from `0.12.1`
44
+ for authored session state, restoration, and authorization headers. Navigation
45
+ samples are `[1.3, 1.5, 1.5, 1.2, 1.3, 1.4, 1.4]` ms, with a 1.4 ms median and
46
+ 1.2/1.5 ms minimum/maximum. The range overlaps `0.12.1`, so no latency change
47
+ is claimed.
48
+
49
+ The application emits 43 files totaling 123,476 raw / 45,305 aggregate gzip
50
+ bytes with deploy SHA-256
51
+ `81d0b3c5e0d1d1f72f29d219647601463f5317f215274e14a45fe5ba92eb033e`.
52
+ The login route uses 12,093 raw / 5,795 aggregate gzip JavaScript bytes. Core
53
+ semantic LOC remains 5,682 with no pass, primitive, production compiler/runtime
54
+ change, or runtime-concept change. `/help` remains 0 B JavaScript.
55
+
9
56
  ## 0.12.1 Shared Layout, History, Focus, And Scroll
10
57
 
11
58
  Measured 2026-08-23 on macOS arm64 with Node 25.6.1 and Chrome
package/README.md CHANGED
@@ -14,7 +14,7 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
14
14
 
15
15
  > Experimental `0.12.x`: the compiler API and supported TSX surface may change.
16
16
 
17
- **Latest release: 0.12.1 - Shared layout, history, focus, and scroll.** Enhanced route groups now prove retained layout state, route cleanup, back/forward history, titles, live announcements, hash and heading focus, explicit scroll policy, and native navigation outside the group. Read the [release notes](./RELEASES.md#0121---shared-layout-history-focus-and-scroll), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.12.1), or follow the [architecture packet](./docs/next-architecture/README.md).
17
+ **Latest release: 0.12.3 - Route failure and restoration policy.** Fetch and response-body transport failures retain the current document for focused retry, while invalid documents and assets keep native fallback. Read the [release notes](./RELEASES.md#0123---route-failure-and-restoration-policy), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.12.3), or follow the [architecture packet](./docs/next-architecture/README.md).
18
18
 
19
19
  - [Documentation](https://kudzujs.cloud/docs)
20
20
  - [Installation guide](https://kudzujs.cloud/docs#install)
package/RELEASES.md CHANGED
@@ -1,5 +1,106 @@
1
1
  # Kudzu Releases
2
2
 
3
+ ## 0.12.3 - Route Failure And Restoration Policy
4
+
5
+ Kudzu 0.12.3 defines recovery for enhanced route failures without adding an
6
+ error-boundary renderer or client router.
7
+
8
+ ### Changed in 0.12.3
9
+
10
+ - Retained the current document when an enhanced navigation fetch or response
11
+ body fails in transit.
12
+ - Announced transport failure through the existing polite status and restored
13
+ focus to the initiating native link for explicit retry.
14
+ - Kept invalid document identity, missing capability modules, and missing
15
+ stylesheets on the existing native fallback path before route disposal.
16
+ - Proved retry after a failed pending prefetch and subsequent click request.
17
+ - Updated `create-kudzu@0.1.116` to generate projects on
18
+ `@kudzujs/core@^0.12.3`.
19
+
20
+ ### Output Evidence
21
+
22
+ - The application emits 43 files, 123,835 raw / 45,379 aggregate gzip bytes,
23
+ and deploy digest
24
+ `fb9d24cc01791bf80b67b659738ba62beded6ff6ce14a86a278fa4b34d088acf`.
25
+ - The maintained enhanced session uses 16 JavaScript files totaling 61,126 raw
26
+ / 22,663 aggregate gzip bytes, 359 raw bytes above `0.12.2`.
27
+ - `/help` remains complete HTML with 0 B JavaScript.
28
+ - No semantic primitive, compiler pass, core compiler line, runtime concept,
29
+ public API, error-boundary renderer, or browser file was added.
30
+
31
+ ### Validation
32
+
33
+ - Required Chrome proves retained fetch and body failures, accessible status,
34
+ restored link focus, retry, and native invalid-document/module/style fallback.
35
+ - Seven fresh Chrome profiles record a 1.8 ms navigation median with a 1.5-2.4
36
+ ms range. The host differs from `0.12.2`, so no latency change is claimed.
37
+ - The full 273-test suite, package smoke, registry metadata, and fresh
38
+ installation are release gates.
39
+
40
+ ### Limits
41
+
42
+ The retained-document policy covers classified transport failures. Invalid
43
+ documents and assets use native navigation; arbitrary corrupted generated mount
44
+ descriptors are outside this packet.
45
+
46
+ ### Upgrade
47
+
48
+ ```sh
49
+ npm install @kudzujs/core@^0.12.3
50
+ ```
51
+
52
+ ## 0.12.2 - Authentication And Permission Boundary
53
+
54
+ Kudzu 0.12.2 completes the project application's login, restoration,
55
+ permission-aware UI, server rejection, and logout journey using existing
56
+ application primitives.
57
+
58
+ ### Changed in 0.12.2
59
+
60
+ - Replaced the placeholder login route with a native constrained form and one
61
+ application-owned async submit handler.
62
+ - Added layout-owned token restoration, session validation, authenticated user
63
+ state, role-aware admin controls, and explicit logout.
64
+ - Added bearer authorization to project reads and mutations; the deterministic
65
+ server rejects missing tokens with 401 and member mutations with 403.
66
+ - Proved that protected static HTML is a UX shell while server authorization is
67
+ the security boundary.
68
+ - Updated `create-kudzu@0.1.115` to generate projects on
69
+ `@kudzujs/core@^0.12.2`.
70
+
71
+ ### Output Evidence
72
+
73
+ - The application emits 43 files, 123,476 raw / 45,305 aggregate gzip bytes,
74
+ and deploy digest
75
+ `81d0b3c5e0d1d1f72f29d219647601463f5317f215274e14a45fe5ba92eb033e`.
76
+ - The maintained enhanced session uses 16 JavaScript files totaling 60,767 raw
77
+ / 22,561 aggregate gzip bytes, 1,793 raw / 432 gzip bytes above `0.12.1`.
78
+ - The login route uses 12,093 raw / 5,795 aggregate gzip JavaScript bytes, while
79
+ `/help` remains complete HTML with 0 B JavaScript.
80
+ - No semantic primitive, compiler pass, core compiler line, runtime concept,
81
+ public API, auth runtime, or server was added to Kudzu.
82
+
83
+ ### Validation
84
+
85
+ - Required Chrome proves invalid and valid login, reload restoration, direct
86
+ anonymous and rejected entry, member/admin UI, server 401/403 responses,
87
+ token clearing, and logout.
88
+ - Seven fresh Chrome profiles record a 1.4 ms navigation median with a 1.2-1.5
89
+ ms range. The range overlaps `0.12.1`, so no latency change is claimed.
90
+ - The full suite, package smoke, registry metadata, and fresh installation are
91
+ release gates.
92
+
93
+ ### Limits
94
+
95
+ Client conditional rendering only controls presentation. Applications and
96
+ deployment hosts remain responsible for authorizing protected data and actions.
97
+
98
+ ### Upgrade
99
+
100
+ ```sh
101
+ npm install @kudzujs/core@^0.12.2
102
+ ```
103
+
3
104
  ## 0.12.1 - Shared Layout, History, Focus, And Scroll
4
105
 
5
106
  Kudzu 0.12.1 completes the accepted same-document project route group with
@@ -594,15 +594,66 @@ no measured AI-delivery cost effect.
594
594
  - **Done condition:** server authorization and client UX responsibilities are
595
595
  executable and explicit.
596
596
 
597
+ **Completion evidence:** the project application replaces its placeholder login
598
+ route with a native constrained form and one async handler. The shared layout
599
+ restores a stored token, validates the current user, exposes authenticated
600
+ identity and role state, and clears local state before replacement navigation on
601
+ rejection or logout. Required Chrome proves invalid and valid login, reload
602
+ restoration, anonymous and rejected direct protected entry, member/admin control
603
+ visibility, server 401/403 enforcement, token clearing, and logout. Client
604
+ conditions are recorded as presentation only; the deterministic API server
605
+ authorizes every protected read and mutation.
606
+
607
+ Existing native forms, state, layout ownership, effects, storage, fetch, and
608
+ native navigation are sufficient. This packet adds zero semantic primitives,
609
+ ModuleIR kinds, compiler passes, production compiler/runtime lines, runtime
610
+ concepts, normalization rules, adapter rules, public APIs, auth runtimes, or
611
+ servers. The fixture emits 43 files totaling 123,476 raw / 45,305 aggregate gzip
612
+ bytes with deploy SHA-256
613
+ `81d0b3c5e0d1d1f72f29d219647601463f5317f215274e14a45fe5ba92eb033e`.
614
+ The login route uses 12,093 raw / 5,795 gzip JavaScript bytes. The two-route
615
+ session uses 16 JavaScript files totaling 60,767 raw / 22,561 aggregate gzip
616
+ bytes. Seven fresh Chrome profiles record a 1.4 ms navigation median with a
617
+ 1.2/1.5 ms range; the range overlaps `0.12.1`, so no latency change is claimed.
618
+ `/help` remains 0 B JavaScript.
619
+
597
620
  ### `0.12.3`: Route Failure And Restoration Policy
598
621
 
599
622
  - **Purpose:** decide application-visible handling of navigation/data failures.
600
623
  - **Expected boundary:** native fallback and application-owned error UI first.
601
624
  - **Acceptance:** invalid document, asset failure, offline/error state, retry,
602
- focus restoration, and no half-replaced route.
625
+ focus restoration, and no half-replaced route for those precommit failures.
603
626
  - **Stop condition:** a generic React-style error-boundary renderer is required.
604
- - **Done condition:** every failure leaves a valid document and recoverable
605
- navigation path.
627
+ - **Done condition:** each classified transport, document-validation,
628
+ capability-loading, or stylesheet-loading failure leaves a valid document
629
+ and recoverable navigation path.
630
+
631
+ **Completion evidence:** required Chrome injects deterministic fetch and
632
+ response-body transport rejections through a pending prefetch and click retry,
633
+ then proves the current URL, route DOM, and retained layout remain unchanged.
634
+ The test moves focus away while the request is pending; the existing polite
635
+ navigation status announces the failure and restores the initiating link.
636
+ Activating that link again completes list-to-detail replacement and focuses the
637
+ destination heading.
638
+ Separate invalid-identity, missing-capability-module, and missing-stylesheet
639
+ responses fail before route disposal and recover through the existing native
640
+ document fallback. The maintained HTTP 500 project read still reports an
641
+ application-owned alert and succeeds on explicit retry.
642
+
643
+ Only `navigation-runtime.js` changes: fetch and response-body transport failures
644
+ receive one private error classification, while document validation and asset
645
+ failures keep their existing fallback. The source grows from 351 to 374 lines and adds no
646
+ semantic primitive, ModuleIR kind, compiler pass, core compiler line, runtime
647
+ concept, public API, error-boundary renderer, route registry, or additional
648
+ browser file. The application emits 43 files totaling 123,835 raw / 45,379
649
+ aggregate gzip bytes with deploy SHA-256
650
+ `fb9d24cc01791bf80b67b659738ba62beded6ff6ce14a86a278fa4b34d088acf`.
651
+ The two-route session remains 16 JavaScript files totaling 61,126 raw / 22,663
652
+ aggregate gzip bytes, 359 raw bytes above `0.12.2`; the unpaired,
653
+ environment-sensitive 102-byte gzip difference is not attributed to the patch.
654
+ `/help` remains 0 B JavaScript. Seven fresh Linux x64 Chrome 142 profiles record
655
+ a 1.8 ms median with a 1.5/2.4 ms range. No latency comparison is claimed
656
+ against the macOS arm64 Chrome 151 `0.12.2` samples.
606
657
 
607
658
  ### `0.12.4`: Nested Layout Evidence Decision
608
659
 
@@ -1150,5 +1201,8 @@ release transaction where possible or document and publish a forward-fix patch.
1150
1201
  | `0.11.3` | Released | Preserve the published optimistic rollback, duplicate prevention, navigation, and retry evidence. | None |
1151
1202
  | `0.11.4` | Released | Preserve the published bounded pagination, history, refresh, polling cleanup, and exact request-count evidence. | None |
1152
1203
  | `0.12.0` | Released | Preserve direct runtime entry, reload, rewrite, and native fallback evidence. | None |
1153
- | `0.12.1` | Active | Release the completed layout/history/focus/scroll evidence. | None |
1154
- | `0.12.2` onward | Blocked | Complete the `0.12.1` release transaction first. | Ordered patch boundary |
1204
+ | `0.12.1` | Released | Preserve the published layout/history/focus/scroll evidence. | None |
1205
+ | `0.12.2` | Released | Preserve the published authentication and permission evidence. | None |
1206
+ | `0.12.3` | Released | Preserve the published route failure, focused retry, native fallback, and precommit retention evidence. | None |
1207
+ | `0.12.4` | Active | Complete the nested layout evidence decision. | None |
1208
+ | `0.12.5` onward | Blocked | Complete the `0.12.4` release transaction first. | Ordered patch boundary |
@@ -66,7 +66,7 @@ Keep each patch behavior-preserving and independently reviewable. If a boundary
66
66
 
67
67
  ## Generator Versions
68
68
 
69
- `create-kudzu@0.1.114` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.12.1`.
69
+ `create-kudzu@0.1.116` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.12.3`.
70
70
 
71
71
  ## Release Boundary
72
72
 
@@ -28,7 +28,7 @@ document.addEventListener("click", event => {
28
28
  if (!eligibleClick(event, anchor)) return
29
29
  const url = new URL(anchor.href)
30
30
  event.preventDefault()
31
- navigate(url, true)
31
+ navigate(url, true, anchor)
32
32
  })
33
33
  document.addEventListener("pointerover", event => prefetchAnchor(event.target.closest?.("a[href]")))
34
34
  document.addEventListener("focusin", event => prefetchAnchor(event.target.closest?.("a[href]")))
@@ -111,7 +111,7 @@ function prune(anchors) {
111
111
  for (const key of documents.keys()) if (!retained.has(key)) documents.delete(key)
112
112
  }
113
113
 
114
- async function navigate(url, push) {
114
+ async function navigate(url, push, source) {
115
115
  await ready
116
116
  const record = matchRoute(url.pathname)
117
117
  if (!record) return fallback(url, push)
@@ -158,6 +158,11 @@ async function navigate(url, push) {
158
158
  styleUpdate?.rollback()
159
159
  if (pendingStyleUpdate === styleUpdate) pendingStyleUpdate = undefined
160
160
  if (current !== revision || error.name === "AbortError") return
161
+ if (push && error.name === "NavigationRequestError") {
162
+ status.textContent = "Navigation failed. Retry the link."
163
+ if (source?.isConnected) source.focus({ preventScroll: true })
164
+ return
165
+ }
161
166
  fallback(url, push)
162
167
  if (committed) return
163
168
  }
@@ -172,9 +177,20 @@ async function loadCapabilities(parsed) {
172
177
  }
173
178
 
174
179
  async function fetchDocument(url, record, signal) {
175
- const response = await fetch(url, { signal, redirect: "manual", headers: { accept: "text/html" } })
180
+ let response
181
+ try {
182
+ response = await fetch(url, { signal, redirect: "manual", headers: { accept: "text/html" } })
183
+ } catch (cause) {
184
+ throw requestError(cause)
185
+ }
176
186
  if (!response.ok || response.redirected || response.type === "opaqueredirect" || !response.headers.get("content-type")?.toLowerCase().includes("text/html")) throw new Error("Navigation response is not successful nonredirected HTML")
177
- const incoming = new DOMParser().parseFromString(await response.text(), "text/html")
187
+ let html
188
+ try {
189
+ html = await response.text()
190
+ } catch (cause) {
191
+ throw requestError(cause)
192
+ }
193
+ const incoming = new DOMParser().parseFromString(html, "text/html")
178
194
  const parsed = validate(incoming, record)
179
195
  return { incoming, parsed, capabilities: await loadCapabilities(parsed), record }
180
196
  }
@@ -315,6 +331,13 @@ function fallback(url, push) {
315
331
  else location.reload()
316
332
  }
317
333
 
334
+ function requestError(cause) {
335
+ if (cause?.name === "AbortError") return cause
336
+ const error = new Error("Navigation request failed", { cause })
337
+ error.name = "NavigationRequestError"
338
+ return error
339
+ }
340
+
318
341
  function between(start, end) {
319
342
  if (start.parentNode !== end.parentNode) throw new Error("Route markers must share a parent")
320
343
  const nodes = []
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",