uniweb 0.49.0 → 0.51.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/package.json +6 -6
- package/partials/agents.md +9 -9
- package/src/commands/publish.js +6 -6
- package/src/framework-index.json +10 -10
- package/templates/site/site.yml.hbs +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.0",
|
|
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": "^0.
|
|
45
|
-
"@uniweb/kit": "^0.18.
|
|
44
|
+
"@uniweb/core": "^0.26.1",
|
|
45
|
+
"@uniweb/kit": "^0.18.4",
|
|
46
46
|
"@uniweb/semantic-parser": "^1.4.0",
|
|
47
|
-
"@uniweb/runtime": "^0.20.
|
|
47
|
+
"@uniweb/runtime": "^0.20.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@uniweb/build": "^0.45.0",
|
|
51
50
|
"@uniweb/content-reader": "^1.2.4",
|
|
52
|
-
"@uniweb/semantic-parser": "^1.4.0"
|
|
51
|
+
"@uniweb/semantic-parser": "^1.4.0",
|
|
52
|
+
"@uniweb/build": "^0.47.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -697,7 +697,7 @@ What can actually *read* it depends on where you deploy, because reading it need
|
|
|
697
697
|
|
|
698
698
|
The artifacts **your build emits** to describe the public site never name them — `llms.txt`, the per-page `.md` projections, and the search index all describe pages a visitor reads, and a knowledge page's prose was written for the assistant instead. Two settings **outrank** `knowledge:`, so a contradiction resolves toward the narrower reach: `agents.exclude` in `site.yml`, and any `_`-prefixed route segment. *(A host that derives these artifacts itself, rather than serving the ones your build produced, applies its own rules — ask your host what it does with `knowledge:` before relying on it there.)*
|
|
699
699
|
|
|
700
|
-
Don't confuse it with the visibility flags: `hidden: true` is a **draft** (not published at all), `hideIn` only controls **nav placement** (still reachable by URL), and `knowledge: true` is a **different audience** (never rendered for anyone).
|
|
700
|
+
Don't confuse it with the visibility flags: `hidden: true` is a **draft** (not published at all), `hideIn` only controls **nav placement** (still reachable by URL), and `knowledge: true` is a **different audience** (never rendered for anyone). ⛔ `hidden: true` on `pages/404/` means a **draft 404** — it is not published and the site falls back to the generic `404.html`; an authored 404 needs no flag, since it is never listed in navigation anyway.
|
|
701
701
|
|
|
702
702
|
**A site can be nothing but knowledge — that is a real and useful shape.** A site is a set of routes; it does not have to have HTML pages. Mark the root `knowledge: true` and every page inherits it, so the site renders nothing at all and exists to *be* an agent: a `/_agent/chat` URL that a web app, a mobile app, or someone else's backend sends requests to.
|
|
703
703
|
|
|
@@ -874,12 +874,12 @@ team:
|
|
|
874
874
|
|
|
875
875
|
You can keep the same declarations under `queries:` in `site.yml` instead, if you would rather have one file.
|
|
876
876
|
|
|
877
|
-
**Show a query on a page** with `
|
|
877
|
+
**Show a query on a page** with `query:` in `page.yml` or a section's frontmatter (the whole result), or `fetch:` for anything more — a `limit`, a `where`. A list — `query: [team, articles]` — declares several, each arriving under its own `content.data` key. `query:` takes names only; `data:`, its old name, is now an error.
|
|
878
878
|
|
|
879
879
|
```yaml
|
|
880
880
|
# pages/blog/page.yml | # a section on the homepage
|
|
881
881
|
title: Blog | ---
|
|
882
|
-
|
|
882
|
+
query: recent | type: ArticleTeaser
|
|
883
883
|
| fetch: { query: recent, limit: 3 }
|
|
884
884
|
| ---
|
|
885
885
|
```
|
|
@@ -888,7 +888,7 @@ data: recent | type: ArticleTeaser
|
|
|
888
888
|
|
|
889
889
|
```
|
|
890
890
|
pages/blog/
|
|
891
|
-
├── page.yml # title: Blog /
|
|
891
|
+
├── page.yml # title: Blog / query: recent
|
|
892
892
|
├── list.md
|
|
893
893
|
└── [slug]/
|
|
894
894
|
├── page.yml
|
|
@@ -897,7 +897,7 @@ pages/blog/
|
|
|
897
897
|
|
|
898
898
|
`entities/article/design-tips.md` becomes `/blog/design-tips`. The section inside `[slug]/` needs no special markdown — the matched record is delivered to it. Generated pages are excluded from navigation menus.
|
|
899
899
|
|
|
900
|
-
**Which query the URL narrows — the page's route query:** the `[slug]` page's own `
|
|
900
|
+
**Which query the URL narrows — the page's route query:** the `[slug]` page's own `query:`, else its parent page's (the usual shape, above), else `site.yml`'s; if none declares one, the query its sections all declare. The first query of that level wins. Every section the route query reaches gets the one record; a section declaring a *different* query of its own gets that query as declared. The folder name says what the URL segment matches: `[slug]` the record's handle (`$name`, which compiled records carry — equal to their `slug`), `[uuid]` its `$uuid`, any other `[name]` the record's own field of that name — and when that field holds several values, **any member** matches (the record's own link is its first value). Routing by a field that is not unique picks one record and which one is not guaranteed; the build warns. A folder inside `[slug]/` (`[slug]/cv/` → `/blog/:slug/cv`) is a parametric page too, reading the record when `[slug]/page.yml` declares the query. `[dir]` and `[path]` are refused as folder names, and so is any folder inside `[...path]/`.
|
|
901
901
|
|
|
902
902
|
> **The record arrives as a single-element array under the query key** — `content.data.recent[0]`, not `content.data.article`. The runtime never coerces it to an object and never synthesizes a singular key. See *Data* in Part 4.
|
|
903
903
|
|
|
@@ -977,7 +977,7 @@ function MyComponent({ content, params, block }) {
|
|
|
977
977
|
}
|
|
978
978
|
```
|
|
979
979
|
|
|
980
|
-
Frontmatter becomes `params`, minus the keys the framework consumes outright: `type`, `preset`, `input`, `props`, `
|
|
980
|
+
Frontmatter becomes `params`, minus the keys the framework consumes outright: `type`, `preset`, `input`, `props`, `query`, `fetch`, `id` (a `data:` key is refused — it was `query:`'s old name). `props:` is the one that isn't dropped but merged *into* params.
|
|
981
981
|
|
|
982
982
|
**Framework fields you'd expect to be stripped are not.** `background`, `theme`, `source`, `where`, and `vars` are acted on by the runtime *and* passed through — so `params.theme` is readable when a component needs logic beyond CSS tokens (a light vs. dark logo, say). Components ignore the keys they don't use, the same way they ignore unused `content.data` keys.
|
|
983
983
|
|
|
@@ -1608,7 +1608,7 @@ export default function Grid({ block, params }) {
|
|
|
1608
1608
|
|
|
1609
1609
|
Each child is a regular section with its own type, params, and content — and you're in the middle: wrap each child, filter by type, reorder, add container classes. The author decides *what* goes in the grid; your component decides *how* it renders. Tomorrow the author can swap a child for a different section type with no code change, and your components stay reusable wherever child sections are accepted.
|
|
1610
1610
|
|
|
1611
|
-
**Data and child blocks:** page-level `
|
|
1611
|
+
**Data and child blocks:** page-level `query:` (or `fetch:`) is available to all blocks including children, and each child resolves data independently through the page → site hierarchy. If a child needs data no ancestor declares, give it its own in its frontmatter (`query: articles`, or `fetch:`). Its `meta.js` `data:` declares the shape it reads, never where the data comes from — it fetches nothing.
|
|
1612
1612
|
|
|
1613
1613
|
**SSG:** insets, `<ChildBlocks>`, and `<Visual>` all render correctly during prerender. Inset components using React hooks internally trigger prerender warnings — expected and harmless; the page renders correctly client-side.
|
|
1614
1614
|
|
|
@@ -1773,7 +1773,7 @@ Content-less containers appear as group nodes (`hasContent: false`) — use `nav
|
|
|
1773
1773
|
|
|
1774
1774
|
### Data
|
|
1775
1775
|
|
|
1776
|
-
A component on a page with a `
|
|
1776
|
+
A component on a page with a `query:` or `fetch:` declaration automatically receives that data in `content.data.{key}` — no opt-in in `meta.js`.
|
|
1777
1777
|
|
|
1778
1778
|
**Bound collections always arrive as arrays.** On a list page, `content.data.articles` is the full collection. On a parametric page (`[slug]/`), the matched record is delivered under the *same* key as a single-element array — the detail section reads `content.data.articles[0]`. When nothing matches, the key is `[]`. The runtime never coerces to a single object and never synthesizes a singular key.
|
|
1779
1779
|
|
|
@@ -1831,7 +1831,7 @@ A backend with its own base URL, headers, wire or query language is a **transpor
|
|
|
1831
1831
|
# site.yml
|
|
1832
1832
|
fetcher:
|
|
1833
1833
|
transports:
|
|
1834
|
-
articles: acme # a foundation-registered transport handles `
|
|
1834
|
+
articles: acme # a foundation-registered transport handles `query: articles`
|
|
1835
1835
|
events: default # explicitly route back to the default fetcher
|
|
1836
1836
|
acme: # binding config that transport reads
|
|
1837
1837
|
apiKey: pk_public_123
|
package/src/commands/publish.js
CHANGED
|
@@ -772,12 +772,12 @@ export async function publish(args = []) {
|
|
|
772
772
|
// released version on the wire is required when site.yml uses an unversioned
|
|
773
773
|
// local ref; injectInfo overrides info.foundation. A registry/URL ref → fnd.ref
|
|
774
774
|
// is null → the site.yml ref is forwarded verbatim (already pinned).
|
|
775
|
-
// ⛔ DO NOT STAMP `info
|
|
776
|
-
//
|
|
777
|
-
//
|
|
778
|
-
//
|
|
779
|
-
//
|
|
780
|
-
//
|
|
775
|
+
// ⛔ DO NOT STAMP A FILE MAP INTO `info` HERE. `injectInfo` WINS the merge
|
|
776
|
+
// (`sync-package.js`: `{...siteDoc.info, ...injectInfo}`), so any name stamped
|
|
777
|
+
// here silently replaces what the author's document carries under it, and the
|
|
778
|
+
// store validator accepts it — nothing errors at any layer. This was written
|
|
779
|
+
// about `info.data`, which carried the site's `fetch:` block until 2026-09-09;
|
|
780
|
+
// that moved to `settings.fetch`, and the warning holds for any name.
|
|
781
781
|
//
|
|
782
782
|
// A file map needs a name nothing else claims (`static_data` / `data_files`
|
|
783
783
|
// were proposed) AND a consumer that reads it — neither settled. See
|
package/src/framework-index.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-12T17:05:58.363Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/api": {
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.3",
|
|
7
7
|
"path": "framework/api",
|
|
8
8
|
"deps": [
|
|
9
9
|
"@uniweb/core"
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
12
|
"@uniweb/build": {
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.47.0",
|
|
14
14
|
"path": "framework/build",
|
|
15
15
|
"deps": [
|
|
16
16
|
"@uniweb/content-reader",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"deps": []
|
|
35
35
|
},
|
|
36
36
|
"@uniweb/core": {
|
|
37
|
-
"version": "0.
|
|
37
|
+
"version": "0.26.1",
|
|
38
38
|
"path": "framework/core",
|
|
39
39
|
"deps": [
|
|
40
40
|
"@uniweb/semantic-parser",
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
"deps": []
|
|
48
48
|
},
|
|
49
49
|
"@uniweb/icons": {
|
|
50
|
-
"version": "0.4.
|
|
50
|
+
"version": "0.4.17",
|
|
51
51
|
"path": "framework/icons",
|
|
52
52
|
"deps": [
|
|
53
53
|
"@uniweb/core"
|
|
54
54
|
]
|
|
55
55
|
},
|
|
56
56
|
"@uniweb/kit": {
|
|
57
|
-
"version": "0.18.
|
|
57
|
+
"version": "0.18.4",
|
|
58
58
|
"path": "framework/kit",
|
|
59
59
|
"deps": [
|
|
60
60
|
"@uniweb/core",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"deps": []
|
|
75
75
|
},
|
|
76
76
|
"@uniweb/projections": {
|
|
77
|
-
"version": "0.6.
|
|
77
|
+
"version": "0.6.2",
|
|
78
78
|
"path": "framework/projections",
|
|
79
79
|
"deps": [
|
|
80
80
|
"@uniweb/content-writer",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
]
|
|
83
83
|
},
|
|
84
84
|
"@uniweb/runtime": {
|
|
85
|
-
"version": "0.20.
|
|
85
|
+
"version": "0.20.3",
|
|
86
86
|
"path": "framework/runtime",
|
|
87
87
|
"deps": [
|
|
88
88
|
"@uniweb/core",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"deps": []
|
|
111
111
|
},
|
|
112
112
|
"@uniweb/templates": {
|
|
113
|
-
"version": "0.
|
|
113
|
+
"version": "0.13.0",
|
|
114
114
|
"path": "framework/templates",
|
|
115
115
|
"deps": []
|
|
116
116
|
},
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"deps": []
|
|
121
121
|
},
|
|
122
122
|
"@uniweb/unipress": {
|
|
123
|
-
"version": "0.9.
|
|
123
|
+
"version": "0.9.14",
|
|
124
124
|
"path": "framework/unipress",
|
|
125
125
|
"deps": [
|
|
126
126
|
"@uniweb/build",
|
|
@@ -49,8 +49,8 @@ index: home
|
|
|
49
49
|
# sort: date desc
|
|
50
50
|
# limit: 10
|
|
51
51
|
#
|
|
52
|
-
# Pages and sections then name a query: `
|
|
53
|
-
# `fetch: { query: recent }
|
|
52
|
+
# Pages and sections then name a query: `query: recent`, or
|
|
53
|
+
# `fetch: { query: recent, limit: 3 }` for anything more.
|
|
54
54
|
#
|
|
55
55
|
# You can also keep queries here instead of in queries.yml:
|
|
56
56
|
#
|
|
@@ -61,7 +61,7 @@ index: home
|
|
|
61
61
|
#
|
|
62
62
|
# fetch:
|
|
63
63
|
# - url: https://api.example.com/team # Remote JSON
|
|
64
|
-
#
|
|
64
|
+
# as: team # Access as content.data.team
|
|
65
65
|
# - path: /data/config.json # Local file from public/
|
|
66
66
|
|
|
67
67
|
# ─── Extensions ────────────────────────────────────────────────────────────────
|