uniweb 1.13.3 → 1.14.1

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",
3
- "version": "1.13.3",
3
+ "version": "1.14.1",
4
4
  "description": "Create structured Vite + React sites with content/code separation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,15 +41,15 @@
41
41
  "js-yaml": "^4.1.0",
42
42
  "prompts": "^2.4.2",
43
43
  "tar": "^7.0.0",
44
- "@uniweb/core": "~1.3.0",
44
+ "@uniweb/core": "~1.3.1",
45
+ "@uniweb/schemas": "~1.5.1",
45
46
  "@uniweb/semantic-parser": "~1.12.2",
46
- "@uniweb/schemas": "~1.5.0",
47
47
  "@uniweb/content-writer": "~1.3.0"
48
48
  },
49
49
  "peerDependencies": {
50
- "@uniweb/build": "~1.5.2",
51
50
  "@uniweb/content-reader": "~1.5.4",
52
- "@uniweb/semantic-parser": "~1.12.2"
51
+ "@uniweb/semantic-parser": "~1.12.2",
52
+ "@uniweb/build": "~1.6.1"
53
53
  },
54
54
  "peerDependenciesMeta": {
55
55
  "@uniweb/build": {
@@ -7,8 +7,7 @@
7
7
  * - ⭐ **The services** — `site.yml::services`, a map by service name *[Diego,
8
8
  * 2026-10-06]*. A push STATES them — the file's, and off for each held one it no
9
9
  * longer lists — and the backend decides per service from the versions sent
10
- * (`statedServices`, `@uniweb/build/uwx`; spec:
11
- * kb/framework/reference/site-services-request.md). All this module does for them
10
+ * (`statedServices`, `@uniweb/build/uwx`). All this module does for them
12
11
  * is say what the file asks that will not be sent (`announceServices`).
13
12
  * - **The language selection** — `site.yml::publishLanguages` — told apart from the
14
13
  * status quo by a fingerprint banked in `deploy.yml` (`reconcile`, `bankLanguages`).
@@ -245,7 +245,7 @@ function writtenAsSent(sent, written) {
245
245
  * every item, not only units. The site-content entity sends every version this copy
246
246
  * holds, for items present and items the files dropped (`withBaseVersion`), and the
247
247
  * backend deletes only the items a push holds a version for, while the site left them
248
- * unchanged [Diego: "yes, apply it to pages too"; kb/framework/plans/services-exchange.md].
248
+ * unchanged [Diego: "yes, apply it to pages too"].
249
249
  * A version banked for an item this copy never saw would therefore delete it. The map
250
250
  * returned is the WHOLE set this copy now holds, in every Section but `secrets`
251
251
  * (`siteItemsByKey`), and it replaces the one held before:
@@ -510,8 +510,6 @@ export function keepModels(siteDir, backend, models) {
510
510
  // ⛔ **Keyed by backend ORIGIN.** Every map describes ONE backend: hashes are what we
511
511
  // last sent *to it*, base versions are the versions *it* had. Shared across backends
512
512
  // they report every entity as changed against the second one.
513
- //
514
- // Spec: kb/framework/reference/backend-cache-json.md
515
513
  function backendCachePath(siteDir) {
516
514
  return join(siteDir, '.uniweb', 'backend-cache.json')
517
515
  }
@@ -2100,8 +2098,7 @@ export async function rebankRecordHashes(siteDir, backend, keys) {
2100
2098
  * reply, never inferred from what we sent.
2101
2099
  *
2102
2100
  * The field is `template`, carrying `designated` or `undesignated`, and it is ABSENT
2103
- * when the designation did not move (backend, collab framework↔backend #6, 2026-09-23;
2104
- * kb/framework/reference/template-designation-on-push.md E6).
2101
+ * when the designation did not move (backend, 2026-09-23).
2105
2102
  *
2106
2103
  * ⛔ TWO STATES, NOT THREE — and silence means "unchanged", never "failed". A push that
2107
2104
  * asks to designate where the backend will not is REFUSED WHOLE, and that refusal
@@ -13,17 +13,24 @@
13
13
  * Full vite + post-vite pipeline. Produces a static-host JS bundle
14
14
  * (`dist/index.html`, `dist/entry.js`, `_importmap/*`, `_pages/*` for
15
15
  * split mode, sitemap/robots/search-index, prerendered HTML when
16
- * configured). Foundation is loaded by URL when site.yml's foundation
17
- * is a registry ref; statically inlined when it's a workspace-local
18
- * ref (the self-contained case).
16
+ * configured). The foundation is statically inlined when site.yml names a
17
+ * workspace-local one (the self-contained case), and loaded by URL when
18
+ * it names a URL, or under VITE_FOUNDATION_MODE=runtime. A catalog ref
19
+ * (`@org/name@version`) is refused (`detectFoundationType`).
19
20
  *
20
21
  * --link (internal; called by `uniweb publish`)
21
- * Data-only pipeline. No vite. Emits ONLY what Uniweb hosting
22
- * needs: `dist/site-content.json` (with full sections),
23
- * `dist/<lang>/site-content.json` per non-default locale,
24
- * `dist/data/*.json` (collections), and `dist/assets/<media>` (images,
25
- * fonts, video posters). The backend stitches runtime + foundation per
26
- * request — the site's JS bundle would be dead weight.
22
+ * Data-only pipeline. No vite, and no media processing. Emits
23
+ * `dist/site-content.json` (with full sections),
24
+ * `dist/<lang>/site-content.json` per non-default locale and
25
+ * `dist/data/*.json` (queries). `publish` reads two things back — the
26
+ * files of the queries that have no data schema, and the languages to
27
+ * make live — sends the content over the sync wire, from source, and
28
+ * uploads media from the site's own files. What it sends carries no JS,
29
+ * so a bundle would be dead weight.
30
+ *
31
+ * ⛔ *Until 2026-10-19 this said a registry ref was loaded by URL, that
32
+ * --link emitted "ONLY what Uniweb hosting needs", and that "the backend
33
+ * stitches runtime + foundation per request".*
27
34
  *
28
35
  * Bare `uniweb build` for a site defaults to --bundle (the historical
29
36
  * behavior). This is mostly useful for inspecting the build output during
@@ -565,32 +572,36 @@ function resolveFoundationDir(projectDir, siteConfig) {
565
572
  }
566
573
 
567
574
  /**
568
- * Build a site in link mode — data only, no vite.
575
+ * Build a site in link mode — data only, no vite. `uniweb publish` runs it.
569
576
  *
570
- * Emits exactly what `uniweb publish` ships to Uniweb hosting:
577
+ * Emits:
571
578
  * dist/site-content.json (full sections inlined)
572
579
  * dist/<lang>/site-content.json per non-default locale
573
580
  * dist/data/<query>.json (+ a file per record, dist/data/<query>/<name>.json)
574
- * dist/assets/<media> (processed images, video posters, PDF thumbnails)
575
581
  *
576
- * Does NOT emit HTML, JS, CSS, source maps, _importmap chunks, or
577
- * static-host extras (sitemap, robots, search-index, _pages/*) — none
578
- * of these are consumed on the link-mode deploy path. The worker
579
- * generates HTML at request time and re-derives split-content per-page
580
- * files from the full payload it receives.
582
+ * `publish` reads two things back: the files of the queries that have no data
583
+ * schema, which it uploads, and the languages to make live. The content goes
584
+ * over the sync wire, read from source, and the site's media is uploaded from
585
+ * the site's own files.
586
+ *
587
+ * Does NOT emit HTML, JS, CSS, source maps, _importmap chunks, processed media
588
+ * (dist/assets/), or static-host extras (sitemap, robots, search-index,
589
+ * _pages/*) — `publish` reads none of them. ⛔ *It processed media into
590
+ * dist/assets/ — WebP copies, video posters, PDF thumbnails — until 2026-10-19.*
581
591
  *
582
592
  * The `buildLocalizedContent` step is the same call bundle mode makes
583
593
  * post-vite, so multi-locale sites get identical per-locale outputs in
584
- * either mode. Collection translation (`buildLocalizedRecords`)
585
- * also runs here so deploy ships translated collection JSONs.
594
+ * either mode. Record translation (`buildLocalizedRecords`) also runs here,
595
+ * writing each locale's query files to dist/<lang>/data/.
596
+ *
597
+ * History: when `deploy` uploaded `dist/site-content.json` to a backend, it
598
+ * read the bundle pipeline's copy, which prerender rewrites into a lightweight
599
+ * manifest (sections stripped) when split-content is active — and the host
600
+ * that received it mis-detected split and served blank pages. Routing deploy
601
+ * through this path, which skips prerender and keeps full sections, fixed it.
586
602
  *
587
- * Bug surfaced + fixed by routing deploy through this path: the bundle
588
- * pipeline's prerender step rewrites `dist/site-content.json` into a
589
- * lightweight manifest (sections stripped) when split-content is active,
590
- * and deploy was reading that stripped version, causing the worker to
591
- * mis-detect split and serve blank pages. Link mode skips prerender
592
- * entirely; `dist/site-content.json` keeps full sections; the worker
593
- * splits correctly.
603
+ * ⛔ *Until 2026-10-19 this said it emitted "exactly what `uniweb publish`
604
+ * ships to Uniweb hosting", and described what the worker does with it.*
594
605
  */
595
606
  async function buildSiteLink(projectDir, options = {}) {
596
607
  const { siteConfig = null } = options
@@ -600,30 +611,29 @@ async function buildSiteLink(projectDir, options = {}) {
600
611
  const { buildSiteData } = await import('@uniweb/build/site')
601
612
  const distDir = join(projectDir, 'dist')
602
613
 
603
- // Resolve the local foundation path so collectSiteContent can pick up
604
- // theme variable defaults from `foundation.js::theme.vars`. When the
605
- // foundation is purely a registry ref (no local sibling), this stays
614
+ // Resolve the local foundation path so collectSiteContent can pick up the
615
+ // defaults of the theme variables it declares (its `main.js` `vars`). When
616
+ // the foundation is purely a registry ref (no local sibling), this stays
606
617
  // null and theme defaults come from theme.yml only.
607
618
  const foundationDir = resolveFoundationDir(projectDir, siteConfig)
608
619
 
609
620
  // Link mode does NOT (re)build the foundation. It reads only the
610
- // foundation's SOURCE config (foundation.js::theme.vars, passed as
611
- // foundationPath below) for theme defaults, and ships NO foundation code —
612
- // the backend serves the foundation from the registry by the `foundation:`
613
- // ref. (Bundle mode is the one that needs a current dist/entry.js — see
614
- // buildSite — so the ensureFoundationFresh cascade lives there, not here.)
621
+ // foundation's SOURCE declarations (passed as foundationPath below) for
622
+ // theme defaults, and ships NO foundation code — the site names its
623
+ // foundation by registered version. (Bundle mode is the one that needs a
624
+ // current dist/entry.js — see buildSite — so the ensureFoundationFresh
625
+ // cascade lives there, not here.)
615
626
 
616
627
  await buildSiteData({
617
628
  siteRoot: projectDir,
618
629
  distDir,
619
- foundationPath: foundationDir,
620
- assets: siteConfig?.build?.assets || {}
630
+ foundationPath: foundationDir
621
631
  })
622
632
  success(`Wrote ${join('dist', 'site-content.json')}`)
623
633
 
624
634
  // Per-locale variants — same call bundle mode makes post-vite. Both
625
- // modes produce identical `dist/<lang>/site-content.json` outputs so
626
- // the deploy CLI walks the same path shape regardless of mode.
635
+ // modes produce identical `dist/<lang>/site-content.json` outputs, and
636
+ // `publish` reads which languages were built from them.
627
637
  const i18nConfig = await loadI18nConfig(projectDir, siteConfig)
628
638
  if (i18nConfig && i18nConfig.locales.length > 0) {
629
639
  log('')
@@ -1092,12 +1102,10 @@ export async function build(args = []) {
1092
1102
  // For sites, read config to determine prerender default
1093
1103
  const siteConfig = readSiteConfig(projectDir)
1094
1104
 
1095
- // Link mode: data-only pipeline, no vite. The deployed Uniweb-edge
1096
- // site never consumes the JS bundle, so we skip producing it.
1097
- // Worker generates HTML at request time using its own runtime +
1098
- // the foundation served from the registry. See
1099
- // `framework/build/src/site/build-site-data.js` for what gets
1100
- // emitted (and what doesn't).
1105
+ // Link mode: data-only pipeline, no vite — what `publish` sends a
1106
+ // backend carries no JS, so no bundle is built. See `buildSiteLink`
1107
+ // above, and `@uniweb/build`'s `src/site/build-site-data.js`, for what
1108
+ // is emitted (and what isn't).
1101
1109
  if (linkFlag) {
1102
1110
  if (prerenderFlag) {
1103
1111
  error(
@@ -89,7 +89,7 @@ function isFoundation(dir) {
89
89
  * ⛔ THE PATH IS `dist/meta/schema.json`, and it read `dist/schema.json` from
90
90
  * 2026-02-06 until 2026-09-15 — a file the build has never written. So this
91
91
  * returned `null` every time, and its one caller (the extension `vars`/layouts
92
- * warning, which `framework/CLAUDE.md` gotcha #18 says doctor performs) could
92
+ * warning) could
93
93
  * not fire at all.
94
94
  *
95
95
  * ⭐ THE CLASS IS WORTH MORE THAN THE BUG: a wrong PATH returns empty, it does
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-10-19T18:20:17.536Z",
3
+ "generatedAt": "2026-10-19T21:44:22.528Z",
4
4
  "packages": {
5
5
  "@uniweb/api": {
6
- "version": "1.6.0"
6
+ "version": "1.6.1"
7
7
  },
8
8
  "@uniweb/build": {
9
- "version": "1.5.2"
9
+ "version": "1.6.1"
10
10
  },
11
11
  "@uniweb/content-reader": {
12
12
  "version": "1.5.4"
@@ -15,7 +15,7 @@
15
15
  "version": "1.3.0"
16
16
  },
17
17
  "@uniweb/core": {
18
- "version": "1.3.0"
18
+ "version": "1.3.1"
19
19
  },
20
20
  "@uniweb/frame-bridge": {
21
21
  "version": "1.0.2"
@@ -24,25 +24,25 @@
24
24
  "version": "1.0.4"
25
25
  },
26
26
  "@uniweb/kit": {
27
- "version": "1.5.1"
27
+ "version": "1.5.2"
28
28
  },
29
29
  "@uniweb/loom": {
30
30
  "version": "1.1.0"
31
31
  },
32
32
  "@uniweb/press": {
33
- "version": "1.1.2"
33
+ "version": "1.1.3"
34
34
  },
35
35
  "@uniweb/projections": {
36
36
  "version": "1.1.4"
37
37
  },
38
38
  "@uniweb/runtime": {
39
- "version": "1.1.10"
39
+ "version": "1.1.11"
40
40
  },
41
41
  "@uniweb/scene": {
42
42
  "version": "1.0.1"
43
43
  },
44
44
  "@uniweb/schemas": {
45
- "version": "1.5.0"
45
+ "version": "1.5.1"
46
46
  },
47
47
  "@uniweb/scholar": {
48
48
  "version": "1.1.0"
@@ -60,7 +60,7 @@
60
60
  "version": "1.2.0"
61
61
  },
62
62
  "@uniweb/unipress": {
63
- "version": "1.1.9"
63
+ "version": "1.1.10"
64
64
  }
65
65
  },
66
66
  "templates": {
@@ -37,7 +37,7 @@ export function stripVersionRange(spec) {
37
37
  * How far a bump moves, in the terms our versioning actually uses.
38
38
  *
39
39
  * ⭐ **The MINOR slot is the breaking one — in 1.x as in 0.x** *[ruled
40
- * 2026-10-11]*. `scripts/framework/publish.js` derives a package's bump from its own
40
+ * 2026-10-11]*. The framework's release derives a package's bump from its own
41
41
  * commits: a breaking marker means minor, everything else patch. So
42
42
  * `^0.14.1 → ^0.16.0` is two breaking releases and `^0.15.0 → ^0.15.2` is not —
43
43
  * and until 2026-09-02 `update` printed both as `behind`, in the same colour,
@@ -5,9 +5,8 @@
5
5
  * `rename`, `add`). A naive `JSON.stringify(obj, null, 2)` reflows the
6
6
  * *entire* file whenever the project happened to use tabs or 4-space
7
7
  * indentation — turning a one-key version bump into a hundred-line diff
8
- * (and a needless merge-conflict surface). `framework/CLAUDE.md` calls
9
- * this out as an anti-pattern for human commits; the tooling shouldn't do
10
- * it either. These helpers detect the file's existing indentation and
8
+ * (and a needless merge-conflict surface). That is an anti-pattern in a
9
+ * human commit, and the tooling shouldn't do it either. These helpers detect the file's existing indentation and
11
10
  * trailing-newline convention and preserve both.
12
11
  */
13
12
 
@@ -4,8 +4,6 @@
4
4
  * ⭐ **`site.yml` holds nothing a backend minted, as of 2026-09-20.** It carried
5
5
  * `$uuid`, `$org` and `$backend`; all three moved to
6
6
  * `sync.json::backends.<origin>.site`, keyed by the backend that minted them.
7
- * Spec: `kb/framework/reference/sync-json.md`. Why:
8
- * `kb/framework/plans/backend-scoped-project-state.md`.
9
7
  *
10
8
  * ## ⛔ What is GONE, and why nothing replaces it
11
9
  *