@uniweb/runtime 1.1.15 → 1.1.17

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": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Minimal runtime for loading Uniweb foundations",
5
5
  "type": "module",
6
6
  "exports": {
@@ -36,15 +36,15 @@
36
36
  "node": ">=22.12"
37
37
  },
38
38
  "dependencies": {
39
- "@uniweb/theming": "~1.2.1",
40
- "@uniweb/core": "~1.4.0"
39
+ "@uniweb/core": "~1.4.2",
40
+ "@uniweb/theming": "~1.2.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@vitejs/plugin-react": "^4.5.2",
44
44
  "esbuild": "^0.21.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.27.0 || ^0.28.0",
45
45
  "vite": "^7.3.1",
46
46
  "vitest": "^4.1.7",
47
- "@uniweb/build": "1.7.1"
47
+ "@uniweb/build": "1.8.2"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "react": "^19.0.0",
@@ -5,6 +5,8 @@
5
5
  * with CSS loading in parallel.
6
6
  */
7
7
 
8
+ import { foundationCssUrl } from '@uniweb/core/page-shell'
9
+
8
10
  /**
9
11
  * Resolve a foundation/extension URL so that absolute-path forms
10
12
  * (`/_module/...`) anchor to the document's origin, not to the importing
@@ -75,11 +77,11 @@ export async function loadFoundationCSS(url) {
75
77
  */
76
78
  export async function loadFoundation(source) {
77
79
  const rawUrl = typeof source === 'string' ? source : source.url
78
- // Auto-derive CSS URL from JS URL by convention: entry.js → assets/style.css.
80
+ // Auto-derive CSS URL from JS URL by the one convention, entry.js → assets/style.css
81
+ // (`foundationCssUrl`, which a page's shell links the primary's stylesheet by too).
79
82
  // Pre-Phase-5 foundations were named foundation.js + assets/foundation.css;
80
83
  // those keep working when an explicit `cssUrl` is passed in `source`.
81
- const rawCssUrl = typeof source === 'object' ? source.cssUrl
82
- : rawUrl.replace(/[^/]+\.js$/, 'assets/style.css')
84
+ const rawCssUrl = typeof source === 'object' ? source.cssUrl : foundationCssUrl(rawUrl)
83
85
 
84
86
  // Phase 5: when the runtime is loaded from a different host than the
85
87
  // document (e.g. runtime served from cdn.uniweb.app, page on
@@ -42,11 +42,14 @@
42
42
  * at publish time and never hand-edited.
43
43
  *
44
44
  * ⚠️ **The tempting fix is the dangerous one.** Stamping the current version
45
- * (`0.16.0`) would satisfy every check and be **false**: backend reads
46
- * `minUsable` from the channel index and refuses to serve a site below it,
47
- * so a floor of 0.16.0 would promise an export that 0.16.0 does not contain —
45
+ * (`0.16.0`) would satisfy every check and be **false**: a backend reads
46
+ * `minUsable` from the channel index and publishes no site at a runtime below
47
+ * it, so a floor of 0.16.0 would promise an export that 0.16.0 does not contain —
48
48
  * and a host at the floor is entitled to skip feature detection. That is a
49
49
  * guarantee broken in the one direction the floor exists to prevent.
50
+ * ⛔ *This said a backend "refuses to serve a site below it" until 2026-10-24.*
51
+ * The floor bounds what is published next. A site already pinned below it is
52
+ * served as it is, until it is republished.
50
53
  *
51
54
  * ⇒ **`UNRELEASED` says the true thing: this export exists in the tree and in no
52
55
  * published version.** It is stamped like any other name, so nothing rides out
@@ -119,6 +122,12 @@ export const ISOLATE_API = Object.freeze({
119
122
  RESOLUTION_STATUS: '0.28.6',
120
123
  // a redirect the host answers itself, with the visitor's query and fragment on it
121
124
  carryQuery: '1.0.1',
125
+ // the `__DATA__` element a host writes into a page's shell, and the escaping it uses
126
+ dataScript: '1.1.16',
127
+ jsonForScript: '1.1.16',
128
+ // the page's whole shell, and the foundation stylesheet convention it links by
129
+ pageShell: '1.1.16',
130
+ foundationCssUrl: '1.1.16',
122
131
  })
123
132
 
124
133
  /**
package/src/setup.js CHANGED
@@ -355,10 +355,16 @@ export async function decodeData() {
355
355
  const raw = el.textContent
356
356
 
357
357
  // Plain JSON (uncompressed)
358
+ // ⛔ A payload that is there and does not parse is said as such: the boot then finds no
359
+ // configuration, and "No site configuration found" alone sent a reader looking for a payload
360
+ // that was present. Measured 2026-10-23: a host escaped `<!--` as `<\!--`, which JSON has no
361
+ // escape for, and every page stayed its server render with nothing naming the cause. JSON
362
+ // inside a <script> escapes `<` as `<` (`build/src/prerender.js`).
358
363
  if (el.type === 'application/json') {
359
364
  try {
360
365
  return JSON.parse(raw)
361
- } catch {
366
+ } catch (err) {
367
+ console.error(`[Runtime] __DATA__ is not valid JSON, so the site cannot start: ${err.message}`)
362
368
  return null
363
369
  }
364
370
  }
@@ -35,6 +35,7 @@ import { layoutStickiness, sectionStickyProps, sectionScrollMargin, zoneProps }
35
35
  import { DefaultLayout } from './default-layout.js'
36
36
  import { renderAppearanceBootScript } from './appearance.js'
37
37
  import { documentTitle } from './document-title.js'
38
+ import { escapeHtml } from '@uniweb/core/page-shell'
38
39
 
39
40
  // Re-export L2 helpers so the public `@uniweb/runtime/ssr` surface
40
41
  // carries everything an SSR consumer needs from one entry point.
@@ -546,9 +547,12 @@ export async function prefetchIcons(siteContent, uniweb, onProgress = () => {})
546
547
  )
547
548
 
548
549
  const succeeded = results.filter(r => r.status === 'fulfilled').length
549
- const failed = results.filter(r => r.status === 'rejected').length
550
- if (failed > 0) {
551
- const msg = `Fetched ${succeeded}/${icons.length} icons (${failed} failed)`
550
+ const failedRefs = icons.filter((_, i) => results[i].status === 'rejected')
551
+ if (failedRefs.length > 0) {
552
+ // Named, so an author can fix the reference. ⛔ Until 2026-10-24 this said only "(1 failed)",
553
+ // and a missing icon on a live page took a search through every reference to find.
554
+ const shown = failedRefs.slice(0, 10).join(', ') + (failedRefs.length > 10 ? ', …' : '')
555
+ const msg = `Fetched ${succeeded}/${icons.length} icons (${failedRefs.length} failed: ${shown})`
552
556
  console.warn(`[prerender] ${msg}`)
553
557
  onProgress(` ${msg}`)
554
558
  }
@@ -655,18 +659,9 @@ export function renderPage(page, website) {
655
659
  // HTML injection
656
660
  // ============================================================================
657
661
 
658
- /**
659
- * Escape HTML special characters.
660
- */
661
- export function escapeHtml(str) {
662
- if (!str) return ''
663
- return String(str)
664
- .replace(/&/g, '&amp;')
665
- .replace(/</g, '&lt;')
666
- .replace(/>/g, '&gt;')
667
- .replace(/"/g, '&quot;')
668
- .replace(/'/g, '&#39;')
669
- }
662
+ // Escape HTML special characters — the one implementation, which a page's shell writes with too
663
+ // (`@uniweb/core/page-shell`). Still exported from here, as it has been since 0.6.14.
664
+ export { escapeHtml }
670
665
 
671
666
  /**
672
667
  * Inject prerendered content into an HTML shell.
package/src/ssr.js CHANGED
@@ -100,3 +100,20 @@ export { collectSiteRecords } from './collect-records.js'
100
100
  // Appearance. injectPageContent() already emits this for every prerendered
101
101
  // page; exported for lanes that assemble a shell without a per-page render.
102
102
  export { renderAppearanceBootScript } from './appearance.js'
103
+
104
+ // ⭐ THE `__DATA__` ELEMENT A HOST WRITES INTO A PAGE'S SHELL — the boot payload as JSON a
105
+ // `<script>` cannot end or misparse (every `<` as `<`), carrying only the served page's
106
+ // sections when the content names where the others are (`config.pageHashes`). The rule a static
107
+ // build writes its own page data by (`@uniweb/core/data-script`). ⛔ A host wrote `__DATA__` with
108
+ // its own escaping until 2026-10-23, escaping `<!--` as `<\!--` — a JavaScript-string escape that
109
+ // is invalid JSON — and no page of the site it served could start (`decodeData`).
110
+ // `jsonForScript` is the escaping alone, for any other JSON a host writes into a `<script>`.
111
+ export { dataScript, jsonForScript } from '@uniweb/core/data-script'
112
+
113
+ // ⭐ THE PAGE'S SHELL — the whole HTML a page starts as, from what only the host holds (its
114
+ // addresses, the runtime's manifest, the content it read): the head, an empty `#root`, and
115
+ // `__DATA__`. Page assembly is framework's [Diego, 2026-10-23]. In an isolate it is the `shell`
116
+ // `createPageRenderer` renders into, versioned with the runtime; a host links the same function
117
+ // (`@uniweb/core/page-shell`) for a page it serves without rendering. `foundationCssUrl` is the
118
+ // one convention for a foundation's stylesheet, which the loader and the shell both follow.
119
+ export { pageShell, foundationCssUrl } from '@uniweb/core/page-shell'