@uniweb/runtime 0.28.6 → 0.28.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/runtime",
3
- "version": "0.28.6",
3
+ "version": "0.28.7",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -36,7 +36,7 @@
36
36
  "node": ">=20.19"
37
37
  },
38
38
  "dependencies": {
39
- "@uniweb/core": "^0.35.1",
39
+ "@uniweb/core": "^0.35.2",
40
40
  "@uniweb/theming": "^0.2.0"
41
41
  },
42
42
  "devDependencies": {
@@ -44,7 +44,7 @@
44
44
  "esbuild": "^0.21.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.27.0",
45
45
  "vite": "^7.3.1",
46
46
  "vitest": "^4.1.7",
47
- "@uniweb/build": "0.74.2"
47
+ "@uniweb/build": "0.74.3"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "react": "^19.0.0",
@@ -157,16 +157,25 @@ export default function PageRenderer() {
157
157
 
158
158
  // ─── Compute navigation targets (before hooks, no early returns) ───
159
159
 
160
- // The redirect the URL names, as the resolver gives it: an author's `redirect:` as written; a
161
- // page with no content to its first descendant with content, as THIS locale shows it (the
162
- // decision canonical, the destination localized — `localeUrl`, the language switcher's rule);
163
- // or the locale served unprefixed, asked for with its prefix, to the path without it.
160
+ // The redirect the URL names, as the resolver gives it: an author's `redirect:` — a page of the
161
+ // site as THIS locale shows it, anything else as written; a page with no content to its first
162
+ // descendant with content, in this locale too (the decision canonical, the destination localized —
163
+ // `localeUrl`, the language switcher's rule); or the locale served unprefixed, asked for with its
164
+ // prefix, to the path without it.
164
165
  // ⛔ This component worked the first two out for itself until 2026-09-30, and the static build
165
166
  // and every host each had a copy.
166
167
  const redirectLocation = resolution?.kind === 'redirect' ? resolution.location : null
167
168
 
169
+ // ⭐ A page served from elsewhere (`rewrite:`) is the HOST's to proxy, before the app loads.
170
+ // Reached by in-app navigation, it is loaded for real so the host can. Reached as the document's
171
+ // own first load (`location.key === 'default'`), the host served the app instead — it does not
172
+ // proxy — so there is no page here: the not-found page, as a static build emits none for it.
173
+ // ⛔ Until 2026-09-30 both reloaded, and on a host that does not proxy that reload never ended.
174
+ const isRewrite = resolution?.kind === 'rewrite'
175
+ const rewriteNotProxied = isRewrite && location.key === 'default'
176
+
168
177
  // If no page found, try the 404 page (do NOT fall back to activePage/homepage)
169
- const isNotFound = !page && !redirectLocation
178
+ const isNotFound = (!page && !redirectLocation) || rewriteNotProxied
170
179
  if (isNotFound) {
171
180
  page = website?.getNotFoundPage?.() || null
172
181
  }
@@ -205,10 +214,8 @@ export default function PageRenderer() {
205
214
 
206
215
  if (redirectLocation) return null
207
216
 
208
- // Rewrite pages are served by an external site — the host handles routing.
209
- // In SPA mode this shouldn't be reached (host proxies before JS loads),
210
- // but if it is (e.g., dev mode), do a full page reload to let the host handle it.
211
- if (resolution?.kind === 'rewrite') {
217
+ // An in-app navigation to a rewrite route: load it for real, so a host that proxies can.
218
+ if (isRewrite && !rewriteNotProxied) {
212
219
  window.location.reload()
213
220
  return null
214
221
  }
@@ -5,11 +5,13 @@
5
5
  * ⭐ THE ONE PLACE THE NUMBER IS STATED. A host loads the SITE'S pinned runtime as a
6
6
  * dynamically-loaded artifact — never an import — so it cannot link-check what it
7
7
  * calls; it feature-detects, and an export that is missing looks exactly like an old
8
- * runtime. The backend evaluates a site's runtime at publish and holds this floor as
9
- * a constant of its own [Diego, 2026-09-04: "We will set a runtime version floor that
10
- * guarantees they are there"], composing it as `max(absoluteFloor, foundationFloors)`.
11
- * That constant is copied from here, and `tests/isolate-api.test.js` is what keeps
12
- * this file honest: every export of `src/ssr.js` must appear below with the version
8
+ * runtime. The backend evaluates a site's runtime at publish against this floor [Diego,
9
+ * 2026-09-04: "We will set a runtime version floor that guarantees they are there"],
10
+ * composing it as `max(floor, foundationFloors)`. It reads the floor from the runtime
11
+ * channel's index (`minUsable`), which every channel publish writes from this file —
12
+ * since 2026-09-05, when that replaced a constant copied from here by hand. (This said
13
+ * the backend held a copied constant until 2026-09-30.) `tests/isolate-api.test.js` is
14
+ * what keeps this file honest: every export of `src/ssr.js` must appear below with the version
13
15
  * it first shipped in, and every name below must still be exported — by the source
14
16
  * and by the built `dist/ssr.js` when it is present. Forgetting to stamp a new export
15
17
  * fails HERE, in the repo where the change happens; a rename fails here too.
@@ -57,7 +59,9 @@
57
59
  * 3. replace `UNRELEASED` with the version that publish produced — the floor
58
60
  * moves here, and the runtime channel's `minUsable` follows at the
59
61
  * next channel publish;
60
- * 4. tell backend, which holds the number and must ratchet it.
62
+ * 4. nothing to copy by hand: the backend reads the floor from the channel index, so
63
+ * a raise reaches it at the channel publish AFTER the commit that makes it. (This
64
+ * step said "tell backend, which holds the number" until 2026-09-30.)
61
65
  *
62
66
  * ⚖️ **Step 3 is a real obligation, not bookkeeping**: an export left
63
67
  * `UNRELEASED` after it ships keeps the floor below its own API forever, so a
@@ -107,11 +111,11 @@ export const ISOLATE_API = Object.freeze({
107
111
  // the whole corpus, for a host that indexes rather than renders
108
112
  collectSiteRecords: '0.17.0',
109
113
  // what a URL names — a page, a redirect, a page served from elsewhere, or nothing
110
- resolveRoute: UNRELEASED,
111
- routeIndex: UNRELEASED,
112
- localeOfPath: UNRELEASED,
113
- localeUrl: UNRELEASED,
114
- RESOLUTION_STATUS: UNRELEASED,
114
+ resolveRoute: '0.28.6',
115
+ routeIndex: '0.28.6',
116
+ localeOfPath: '0.28.6',
117
+ localeUrl: '0.28.6',
118
+ RESOLUTION_STATUS: '0.28.6',
115
119
  })
116
120
 
117
121
  /**