@uniweb/build 1.5.1 → 1.6.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 +9 -9
- package/src/foundation/prose-styles.js +4 -4
- package/src/hosts/github-pages.js +1 -1
- package/src/site/build-site-data.js +51 -97
- package/src/site/deploy-config.js +1 -1
- package/src/site/file-transport.js +1 -2
- package/src/site/foundation-ref.js +8 -6
- package/src/uwx/data-schema.js +2 -2
- package/src/uwx/entity-document.js +0 -1
- package/src/uwx/folder.js +1 -1
- package/src/uwx/index.js +0 -2
- package/src/uwx/services-request.js +2 -4
- package/src/uwx/site.js +4 -4
- package/src/uwx/sync-package.js +1 -1
- package/src/uwx/sync-store.js +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/build",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Build tooling for the Uniweb Component Web Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -56,15 +56,15 @@
|
|
|
56
56
|
"js-yaml": "^4.1.0",
|
|
57
57
|
"sharp": "^0.35.3",
|
|
58
58
|
"yaml": "^2.5.0",
|
|
59
|
-
"@uniweb/
|
|
60
|
-
"@uniweb/
|
|
61
|
-
"@uniweb/
|
|
59
|
+
"@uniweb/semantic-parser": "~1.12.2",
|
|
60
|
+
"@uniweb/content-reader": "~1.5.4",
|
|
61
|
+
"@uniweb/theming": "~1.2.0",
|
|
62
62
|
"@uniweb/content-writer": "~1.3.0",
|
|
63
|
-
"@uniweb/
|
|
64
|
-
"@uniweb/
|
|
63
|
+
"@uniweb/projections": "~1.1.4",
|
|
64
|
+
"@uniweb/schemas": "~1.5.0"
|
|
65
65
|
},
|
|
66
66
|
"optionalDependencies": {
|
|
67
|
-
"@uniweb/runtime": "~1.1.
|
|
67
|
+
"@uniweb/runtime": "~1.1.11"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
70
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"@tailwindcss/vite": "^4.0.0",
|
|
74
74
|
"@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
|
|
75
75
|
"vite-plugin-svgr": "^4.0.0",
|
|
76
|
-
"@uniweb/
|
|
77
|
-
"@uniweb/
|
|
76
|
+
"@uniweb/core": "~1.3.1",
|
|
77
|
+
"@uniweb/runtime": "~1.1.11"
|
|
78
78
|
},
|
|
79
79
|
"peerDependenciesMeta": {
|
|
80
80
|
"vite": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prose without its stylesheet — the one foundation mistake that renders fine and looks wrong.
|
|
3
3
|
*
|
|
4
|
-
* kit's `<Prose>` (and `<Article>`, which is `<Prose>` in an `<article>`) draws content inside
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* kit's `<Prose>` (and `<Article>`, which is `<Prose>` in an `<article>`) draws content inside a
|
|
5
|
+
* `prose` container. The class styles nothing unless the foundation's stylesheet imports kit's
|
|
6
|
+
* prose layer, which is one line:
|
|
7
7
|
*
|
|
8
8
|
* @import "@uniweb/kit/prose-tokens.css";
|
|
9
9
|
*
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
/** kit's Prose module, wherever kit resolves from — the workspace or node_modules. */
|
|
21
21
|
const PROSE_MODULE = /[\\/]kit[\\/]src[\\/]styled[\\/]Prose[\\/]index\.jsx$/
|
|
22
22
|
|
|
23
|
-
/** A rule of
|
|
23
|
+
/** A rule of kit's prose layer, which every one of its selectors starts with. ⛔ Tailwind Typography's until 2026-10-19. */
|
|
24
24
|
const PROSE_RULE = /\.prose\b/
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* the branch history stays intact and revertible.
|
|
36
36
|
*
|
|
37
37
|
* UNIWEB_BASE is decided at workflow scaffold time based on the deploy
|
|
38
|
-
* target
|
|
38
|
+
* target, and becomes the site's base path:
|
|
39
39
|
*
|
|
40
40
|
* - With `domain`: bakes `UNIWEB_BASE: /` and emits a CNAME file under
|
|
41
41
|
* `<sitePath>/public/`. GitHub Pages serves the custom domain at
|
|
@@ -2,19 +2,24 @@
|
|
|
2
2
|
* Site data builder — runs the data pipeline without vite.
|
|
3
3
|
*
|
|
4
4
|
* `siteContentPlugin` (`./plugin.js`) emits site data inside vite's
|
|
5
|
-
* `generateBundle` hook
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* `generateBundle` hook, on the bundle lane, where vite builds a JS bundle for
|
|
6
|
+
* a static host. `uniweb build --link`, which `uniweb publish` runs, needs no
|
|
7
|
+
* bundle: what `publish` sends a backend carries no JS. The content goes over
|
|
8
|
+
* the sync wire, read from the site's source files (`../uwx/`), and the site
|
|
9
|
+
* names its foundation by registered version.
|
|
10
|
+
*
|
|
11
|
+
* ⛔ *Until 2026-10-19 this said a Uniweb-hosted site "is rendered by the worker
|
|
12
|
+
* using its own runtime" — a statement about a host, which framework cannot
|
|
13
|
+
* make (the note under `site-content.json` below).*
|
|
10
14
|
*
|
|
11
15
|
* This function is the shared data-emission core used by the link-mode
|
|
12
16
|
* pipeline. The vite plugin keeps its own emission for the bundle-mode
|
|
13
17
|
* path (where the static-host extras — sitemap, robots, search-index,
|
|
14
18
|
* `_pages/*` for split content — are actually consumed). Both paths use
|
|
15
19
|
* the same underlying building blocks (`collectSiteContent`,
|
|
16
|
-
* `processQueries`,
|
|
17
|
-
*
|
|
20
|
+
* `processQueries`, etc.), so behavior stays consistent without forcing
|
|
21
|
+
* one path through the other's lifecycle. Media processing — WebP copies,
|
|
22
|
+
* video posters, PDF thumbnails — is the bundle path's alone (below).
|
|
18
23
|
*/
|
|
19
24
|
|
|
20
25
|
import { writeFile, readFile, mkdir, cp } from 'node:fs/promises'
|
|
@@ -25,8 +30,6 @@ import { resolveDefaultLocale, DATA_DIR } from '@uniweb/core'
|
|
|
25
30
|
import { collectSiteContent } from './content-collector.js'
|
|
26
31
|
import { processQueries, writeQueryFiles } from './query-processor.js'
|
|
27
32
|
import { resolveRecordsDir } from './entity-pool.js'
|
|
28
|
-
import { processAssets, rewriteSiteContentPaths } from './asset-processor.js'
|
|
29
|
-
import { processAdvancedAssets } from './advanced-processors.js'
|
|
30
33
|
import {
|
|
31
34
|
renderSiteIndex,
|
|
32
35
|
renderPageMarkdown,
|
|
@@ -39,11 +42,17 @@ import {
|
|
|
39
42
|
} from '@uniweb/projections'
|
|
40
43
|
|
|
41
44
|
/**
|
|
42
|
-
* Build the site data
|
|
45
|
+
* Build the site data for `uniweb build --link`, which `uniweb publish` runs.
|
|
46
|
+
* `publish` reads two things back from `distDir`: the files of the queries that
|
|
47
|
+
* have no data schema, which it uploads, and the languages to make live.
|
|
43
48
|
*
|
|
44
49
|
* Emits to `distDir`:
|
|
45
50
|
* - `site-content.json` — full content tree, sections always inlined.
|
|
46
|
-
*
|
|
51
|
+
* `publish` reads the languages to make live from it and from the
|
|
52
|
+
* `<locale>/site-content.json` files beside it (`languagesFromContent`);
|
|
53
|
+
* the content itself goes over the sync wire, built from source.
|
|
54
|
+
* ⛔ *Until 2026-10-19 this said the deploy CLI shipped this file as
|
|
55
|
+
* `payload.locales[default]`.*
|
|
47
56
|
*
|
|
48
57
|
* ⛔ Ship FULL sections; never strip them per the split-content rule.
|
|
49
58
|
* A stripped manifest is what prerender emits for static-host bundles,
|
|
@@ -54,27 +63,30 @@ import {
|
|
|
54
63
|
* does with the payload. Removed 2026-08-18: the description was
|
|
55
64
|
* accurate about one deployment and false about another, and both were
|
|
56
65
|
* live at once — so naming "the worker" was wrong even though the
|
|
57
|
-
* sentence was true somewhere.
|
|
58
|
-
* knowledge
|
|
59
|
-
*
|
|
66
|
+
* sentence was true somewhere. The framework has no host client and no
|
|
67
|
+
* knowledge of hosts; we cannot tell consumers apart and must not write
|
|
68
|
+
* as though we can.
|
|
60
69
|
*
|
|
61
70
|
* ⇒ The rule stands on its own: we do not know which consumers
|
|
62
71
|
* re-derive, so we always ship enough for the ones that do.
|
|
63
|
-
* - `data/<
|
|
64
|
-
*
|
|
72
|
+
* - `data/<query>.json` (+ each record's own file, `data/<query>/<$name>.json`) —
|
|
73
|
+
* same shape `processQueries` produces today. `publish` uploads the files of
|
|
74
|
+
* the queries that have no data schema (`collectSchemalessData`).
|
|
65
75
|
* - `records/<path under the records directory>` — the records' co-located assets, where
|
|
66
76
|
* the compiled records point.
|
|
67
|
-
* - `assets/<media>` — processed images / video posters / PDF
|
|
68
|
-
* thumbnails. Filtered by the deploy CLI to MEDIA only at upload time.
|
|
69
77
|
*
|
|
70
78
|
* Does NOT emit:
|
|
79
|
+
* - `assets/<media>` — no media is processed here, and a media ref in
|
|
80
|
+
* `site-content.json` stays the site's own path. `publish` uploads a
|
|
81
|
+
* site's media from the site's own files (the CLI's `uploadSiteMedia`), so
|
|
82
|
+
* processed copies would be built for nothing. ⛔ *Until 2026-10-19 this
|
|
83
|
+
* lane made WebP copies, video posters and PDF thumbnails into
|
|
84
|
+
* `dist/assets/` on every publish, and rewrote the refs to them.*
|
|
71
85
|
* - HTML, JS, CSS, source maps, `_importmap/*` — static-host bundle
|
|
72
86
|
* artifacts; a host on this lane renders pages itself.
|
|
73
87
|
* - `_pages/<route>.json` — only meaningful for static-host bundles,
|
|
74
88
|
* where they are served as files.
|
|
75
|
-
* - `sitemap.xml`, `robots.txt` — static-host bundle territory.
|
|
76
|
-
* are simply absent from Uniweb-hosted sites today: nothing in platform
|
|
77
|
-
* generates them, at publish time or at request time.
|
|
89
|
+
* - `sitemap.xml`, `robots.txt` — static-host bundle territory.
|
|
78
90
|
* - ANY search index — neither the single-file `search-index.json` nor the
|
|
79
91
|
* split `_search/{locale}/*.json`. This lane emitted both until
|
|
80
92
|
* 2026-08-01 and emits neither now; see step 5 for why. A host that
|
|
@@ -91,14 +103,7 @@ import {
|
|
|
91
103
|
* @param {string} params.distDir - Absolute path to the dist output directory.
|
|
92
104
|
* @param {string} [params.foundationPath] - Absolute path to the foundation
|
|
93
105
|
* directory, when one exists locally. Used by `collectSiteContent` to
|
|
94
|
-
* resolve theme
|
|
95
|
-
* @param {Object} [params.assets] - Asset processing options.
|
|
96
|
-
* @param {boolean} [params.assets.process=true]
|
|
97
|
-
* @param {boolean} [params.assets.convertToWebp=true]
|
|
98
|
-
* @param {number} [params.assets.quality=80]
|
|
99
|
-
* @param {string} [params.assets.outputDir='assets']
|
|
100
|
-
* @param {boolean} [params.assets.videoPosters=true]
|
|
101
|
-
* @param {boolean} [params.assets.pdfThumbnails=true]
|
|
106
|
+
* resolve the defaults of the theme variables it declares (its `main.js` `vars`).
|
|
102
107
|
* @param {string} [params.basePath='/'] - Base path prefix for collection URLs.
|
|
103
108
|
* @returns {Promise<{ siteContent: Object, distDir: string }>}
|
|
104
109
|
*/
|
|
@@ -106,7 +111,6 @@ export async function buildSiteData({
|
|
|
106
111
|
siteRoot,
|
|
107
112
|
distDir,
|
|
108
113
|
foundationPath,
|
|
109
|
-
assets = {},
|
|
110
114
|
basePath = '/',
|
|
111
115
|
}) {
|
|
112
116
|
if (!siteRoot) throw new Error('buildSiteData: siteRoot is required')
|
|
@@ -114,21 +118,13 @@ export async function buildSiteData({
|
|
|
114
118
|
|
|
115
119
|
const resolvedSiteRoot = resolve(siteRoot)
|
|
116
120
|
const resolvedDistDir = resolve(distDir)
|
|
117
|
-
const assetsOpts = {
|
|
118
|
-
process: assets.process !== false,
|
|
119
|
-
convertToWebp: assets.convertToWebp !== false,
|
|
120
|
-
quality: assets.quality || 80,
|
|
121
|
-
outputDir: assets.outputDir || 'assets',
|
|
122
|
-
videoPosters: assets.videoPosters !== false,
|
|
123
|
-
pdfThumbnails: assets.pdfThumbnails !== false,
|
|
124
|
-
}
|
|
125
121
|
|
|
126
122
|
await mkdir(resolvedDistDir, { recursive: true })
|
|
127
123
|
|
|
128
124
|
// 1. Collect content (pages, sections, theme, config, assets manifest).
|
|
129
125
|
// No vite needed — collectSiteContent is a plain async function.
|
|
130
|
-
// dropUnpublished: link mode is
|
|
131
|
-
//
|
|
126
|
+
// dropUnpublished: link mode is the build `publish` runs, so it reads
|
|
127
|
+
// the site as published — hidden pages and their subtree pruned.
|
|
132
128
|
let siteContent = await collectSiteContent(resolvedSiteRoot, { foundationPath, dropUnpublished: true, base: basePath, strict: true })
|
|
133
129
|
|
|
134
130
|
// 2. Compile content collections (file-based markdown/yaml/json).
|
|
@@ -166,69 +162,27 @@ export async function buildSiteData({
|
|
|
166
162
|
}
|
|
167
163
|
}
|
|
168
164
|
|
|
169
|
-
// 3.
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
let finalContent = siteContent
|
|
173
|
-
|
|
174
|
-
const assetCount = Object.keys(siteContent.assets).length
|
|
175
|
-
if (assetCount > 0) {
|
|
176
|
-
const { pathMapping, files } = await processAssets(siteContent.assets, {
|
|
177
|
-
outputDir: resolvedDistDir,
|
|
178
|
-
assetsSubdir: assetsOpts.outputDir,
|
|
179
|
-
convertToWebp: assetsOpts.convertToWebp,
|
|
180
|
-
quality: assetsOpts.quality,
|
|
181
|
-
basePath,
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
const advancedEnabled = assetsOpts.videoPosters || assetsOpts.pdfThumbnails
|
|
185
|
-
if (advancedEnabled) {
|
|
186
|
-
const { posterMapping, thumbnailMapping } = await processAdvancedAssets(
|
|
187
|
-
siteContent.assets,
|
|
188
|
-
{
|
|
189
|
-
outputDir: resolvedDistDir,
|
|
190
|
-
assetsSubdir: assetsOpts.outputDir,
|
|
191
|
-
videoPosters: assetsOpts.videoPosters,
|
|
192
|
-
pdfThumbnails: assetsOpts.pdfThumbnails,
|
|
193
|
-
quality: assetsOpts.quality,
|
|
194
|
-
basePath,
|
|
195
|
-
hasExplicitPoster: siteContent.hasExplicitPoster || new Set(),
|
|
196
|
-
hasExplicitPreview: siteContent.hasExplicitPreview || new Set(),
|
|
197
|
-
}
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
finalContent = rewriteSiteContentPaths(siteContent, pathMapping, files)
|
|
201
|
-
if (Object.keys(posterMapping).length > 0 || Object.keys(thumbnailMapping).length > 0) {
|
|
202
|
-
finalContent._assetMeta = {
|
|
203
|
-
posters: posterMapping,
|
|
204
|
-
thumbnails: thumbnailMapping,
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
finalContent = rewriteSiteContentPaths(siteContent, pathMapping, files)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
} else {
|
|
212
|
-
// Drop the assets manifest from the output when processing is off
|
|
213
|
-
// (matches the vite plugin's behavior — manifest is internal).
|
|
214
|
-
finalContent = { ...siteContent }
|
|
215
|
-
delete finalContent.assets
|
|
216
|
-
}
|
|
165
|
+
// 3. No media processing (header, "Does NOT emit"). The collector's asset
|
|
166
|
+
// manifest is internal, so it is dropped — as the vite plugin drops it
|
|
167
|
+
// when processing is off.
|
|
168
|
+
let finalContent = { ...siteContent }
|
|
169
|
+
delete finalContent.assets
|
|
217
170
|
|
|
218
|
-
// Strip internal-only properties that don't serialize
|
|
219
|
-
//
|
|
220
|
-
// build's split-content emit consumed them already).
|
|
171
|
+
// Strip internal-only properties that don't serialize (Sets don't
|
|
172
|
+
// JSON-roundtrip): the collector records them for media processing.
|
|
221
173
|
delete finalContent.hasExplicitPoster
|
|
222
174
|
delete finalContent.hasExplicitPreview
|
|
223
175
|
|
|
224
176
|
// ⛔ `config.icons` is a HOST-owned slot on this lane — drop it.
|
|
225
177
|
//
|
|
226
|
-
// This
|
|
227
|
-
//
|
|
228
|
-
//
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
//
|
|
178
|
+
// This is the build for a backend (link mode is what `uniweb publish` runs),
|
|
179
|
+
// and `config` is site.yml spread whole, so an author's `icons.cdnUrl` would
|
|
180
|
+
// otherwise sit in a slot the host is supposed to fill. The icon base is a
|
|
181
|
+
// property of the DEPLOYMENT, identical for every site a given backend
|
|
182
|
+
// serves — not something one site gets to choose [Diego, 2026-08-17].
|
|
183
|
+
// ⛔ *Until 2026-10-19 this said the payload "only ever goes to a backend":
|
|
184
|
+
// `publish` reads it for its languages, and sends the content over the sync
|
|
185
|
+
// wire, which never had this exposure (below).*
|
|
232
186
|
//
|
|
233
187
|
// The reason it cannot be a site's call is that the base and the NAMESPACE
|
|
234
188
|
// are coupled: icon filenames are minted by whoever built the corpus, so
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* by name. Read-only — never writes. See deploy-config-writer.js for
|
|
6
6
|
* the write path.
|
|
7
7
|
*
|
|
8
|
-
* On-disk shape
|
|
8
|
+
* On-disk shape:
|
|
9
9
|
* default: production
|
|
10
10
|
* targets:
|
|
11
11
|
* production: { host, backend?, ...host-specific config }
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* (`@uniweb/runtime/ssr::loadPageData`) asks for what a page's render will read, by the rule the
|
|
6
6
|
* render itself uses, and dispatches every request through one function the caller supplies. A host
|
|
7
7
|
* gives it the network; this lane gives it `dist/` and `public/`. So the build asks the same
|
|
8
|
-
* question as every other lane and only the answering differs
|
|
9
|
-
* `kb/framework/plans/what-a-page-needs.md`.
|
|
8
|
+
* question as every other lane, and only the answering differs.
|
|
10
9
|
*
|
|
11
10
|
* ⛔ **A remote `url:` is still the browser's lane by default.** Nothing here decides that: the
|
|
12
11
|
* author's `prerender:` does, and the step is run with `prerender: 'author'` so a deferred request
|
|
@@ -70,9 +70,11 @@ export function parseCatalogRef(value) {
|
|
|
70
70
|
* - `'local'` — workspace-local source (sibling directory, file: dep, or
|
|
71
71
|
* `../../foundations/<name>/`). The build inlines or runtime-links it
|
|
72
72
|
* depending on the operating mode.
|
|
73
|
-
* - `'url'` — loaded by URL at runtime
|
|
74
|
-
*
|
|
75
|
-
*
|
|
73
|
+
* - `'url'` — loaded by URL at runtime: an `https://…` URL, or the object
|
|
74
|
+
* form's `url`. A catalog ref (`@org/name@ver`) is refused, since where one
|
|
75
|
+
* is served is the host's to say — except under `uniweb dev`, which is
|
|
76
|
+
* handed the answer (`served`). ⛔ *Until 2026-10-19 this listed a catalog
|
|
77
|
+
* ref as a URL shape, "resolved against the registry CDN".*
|
|
76
78
|
*
|
|
77
79
|
* Versionless registry refs (`@org/name`) are rejected with a specific error —
|
|
78
80
|
* they were a silent fall-through before. Versionless names that don't match
|
|
@@ -181,9 +183,9 @@ export function detectFoundationType(foundation, siteRoot, { served = null } = {
|
|
|
181
183
|
// resolve through the local checks below (file: dep,
|
|
182
184
|
// workspace sibling) when the developer is iterating locally on a
|
|
183
185
|
// foundation that will eventually be published as `@org/name@ver`.
|
|
184
|
-
//
|
|
185
|
-
// site.yml: foundation: '@
|
|
186
|
-
// package.json: "@
|
|
186
|
+
// For example:
|
|
187
|
+
// site.yml: foundation: '@acme/marketing'
|
|
188
|
+
// package.json: "@acme/marketing": "file:../../foundations/marketing"
|
|
187
189
|
// The file: dep check below picks it up. If no local resolution exists
|
|
188
190
|
// either, the function throws below with a "missing version" hint.
|
|
189
191
|
|
package/src/uwx/data-schema.js
CHANGED
|
@@ -78,7 +78,7 @@ export function openMapFromRows(rows) {
|
|
|
78
78
|
/**
|
|
79
79
|
* A `text` field marked as rich content (`format: markdown` or `html`): the
|
|
80
80
|
* file-based body target. Round-trips as the raw source string — what the retired
|
|
81
|
-
* `richtext` kind used to be.
|
|
81
|
+
* `richtext` kind used to be.
|
|
82
82
|
*/
|
|
83
83
|
export function isMarkupTextField(field) {
|
|
84
84
|
return field?.type === 'text' && CONTENT_TEXT_FORMATS.has(field?.format)
|
|
@@ -89,7 +89,7 @@ export function isMarkupTextField(field) {
|
|
|
89
89
|
* authored as markdown on the file side, carried as a ProseMirror document on the
|
|
90
90
|
* sync wire (the common language with the visual app). The single predicate the
|
|
91
91
|
* sync producer/projector use to decide md⇄ProseMirror conversion + structural-map
|
|
92
|
-
* localization.
|
|
92
|
+
* localization.
|
|
93
93
|
*/
|
|
94
94
|
export function isProseMirrorField(field) {
|
|
95
95
|
return field?.type === 'json' && field?.format === 'richtext'
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
* then, and ⛔ nothing reads that spelling — no production backend existed to keep a
|
|
37
37
|
* window for [Diego, 2026-09-24]. The value comes back as it is, so a caller can still
|
|
38
38
|
* tell an id from a name and say which it met.
|
|
39
|
-
* Record: `kb/framework/build/uwx-format.md` § *The data schema an entity names*.
|
|
40
39
|
*
|
|
41
40
|
* @param {object} doc - an entity `$`-document
|
|
42
41
|
* @returns {string|null}
|
package/src/uwx/folder.js
CHANGED
|
@@ -75,7 +75,7 @@ export const FOLDER_ENTITY_KEY = '@folder'
|
|
|
75
75
|
// registry of the backend we talk to. ⛔ Neither is an identity across backends: each
|
|
76
76
|
// has its own registry [Diego, 2026-09-24]. (A TODO here asked
|
|
77
77
|
// for the id until then; the agreement settled it the other way.) The key was `model`
|
|
78
|
-
// until the same date.
|
|
78
|
+
// until the same date.
|
|
79
79
|
function refLeaf(entity) {
|
|
80
80
|
const leaf = { kind: 'ref', name: entity.slug }
|
|
81
81
|
if (entity.uuid) leaf.entry = { schema: entity.model, entity: entity.uuid }
|
package/src/uwx/index.js
CHANGED
|
@@ -106,7 +106,6 @@ export { emitSyncPackages } from './sync-package.js'
|
|
|
106
106
|
export { restoreAssetRefs, servedFingerprint } from './asset-map.js'
|
|
107
107
|
// `sync.json` — what each backend minted, keyed by origin. Absorbs `assets.json`
|
|
108
108
|
// above, `site.yml`'s identity keys and three maps out of the sync cache.
|
|
109
|
-
// Spec: kb/framework/reference/sync-json.md
|
|
110
109
|
export {
|
|
111
110
|
SYNC_STORE_FILE,
|
|
112
111
|
readSyncStore,
|
|
@@ -122,7 +121,6 @@ export {
|
|
|
122
121
|
normalizeOrigin as normalizeBackendOrigin,
|
|
123
122
|
} from './sync-store.js'
|
|
124
123
|
// A site's services request — `site.yml::services`, applied over the site's own rows.
|
|
125
|
-
// Spec: kb/framework/reference/site-services-request.md
|
|
126
124
|
export {
|
|
127
125
|
RUNTIME_KEYS,
|
|
128
126
|
readServicesRequest,
|
|
@@ -43,8 +43,6 @@
|
|
|
43
43
|
* Pure functions, shared by the static build (`content-collector.js`), the producer
|
|
44
44
|
* (`site.js`), pull (`site-project.js`) and the CLI's push, publish and doctor.
|
|
45
45
|
*
|
|
46
|
-
* Spec: kb/framework/reference/site-services-request.md
|
|
47
|
-
*
|
|
48
46
|
* @module
|
|
49
47
|
*/
|
|
50
48
|
|
|
@@ -456,8 +454,8 @@ export function servicesFromDocument({ rows, local } = {}) {
|
|
|
456
454
|
* The `services` Section a push sends: every service `site.yml` lists, as it says it, and
|
|
457
455
|
* OFF for every service this copy holds that the file does not list.
|
|
458
456
|
*
|
|
459
|
-
* ⭐ A PUSH STATES, AND THE BACKEND DECIDES PER SERVICE [Diego, 2026-10-07
|
|
460
|
-
*
|
|
457
|
+
* ⭐ A PUSH STATES, AND THE BACKEND DECIDES PER SERVICE [Diego, 2026-10-07]. Every
|
|
458
|
+
* service is on or off, off by default.
|
|
461
459
|
*
|
|
462
460
|
* - A service the file lists goes WHOLE — its switch, and the entry as its `config` — so
|
|
463
461
|
* a setting removed from the file is removed.
|
package/src/uwx/site.js
CHANGED
|
@@ -1104,13 +1104,13 @@ function queriesNested(declarations, uuids = null, scope = null, keyTyped = null
|
|
|
1104
1104
|
// ── `services` + `secrets` — what a site asks of its host ─────────────────────────
|
|
1105
1105
|
//
|
|
1106
1106
|
// ⭐ THE `services` SECTION IS THE OWNER'S REQUEST, AUTHORED IN `site.yml::services` — a
|
|
1107
|
-
// map from service name to `true`, `false` or the service's settings
|
|
1108
|
-
//
|
|
1107
|
+
// map from service name to `true`, `false` or the service's settings. A push STATES:
|
|
1108
|
+
// every service the
|
|
1109
1109
|
// file lists, as it says it, and OFF for every service this copy holds that the file no
|
|
1110
1110
|
// longer lists (`statedServices`). The services it holds are named in that backend's
|
|
1111
1111
|
// entry in `sync.json`, `{ name: $uuid }`, written by pull and by a push that succeeded;
|
|
1112
1112
|
// one it never saw is not sent, and the site keeps it. The backend decides per service
|
|
1113
|
-
// from the versions the push sends [Diego, 2026-10-07
|
|
1113
|
+
// from the versions the push sends [Diego, 2026-10-07].
|
|
1114
1114
|
// ⛔ *Until then the Section went as a FULL LIST — the site's rows, read just before the
|
|
1115
1115
|
// push, with the file's changed asks applied — because the backend replaced the Section
|
|
1116
1116
|
// with what it was sent; and from 2026-09-20 to 2026-10-06 the rows lived only in
|
|
@@ -1734,5 +1734,5 @@ export function writeSiteEntityUuid(siteRoot, backend, uuid) {
|
|
|
1734
1734
|
// ⛔ `writeSiteBackend` and `site.yml::$backend` are GONE (2026-09-20). The scope is
|
|
1735
1735
|
// no longer a value recorded beside the uuid — it is the KEY the identity is stored
|
|
1736
1736
|
// under (`sync.json::backends.<origin>`), so there is nothing to record and nothing
|
|
1737
|
-
// that can disagree with it.
|
|
1737
|
+
// that can disagree with it.
|
|
1738
1738
|
|
package/src/uwx/sync-package.js
CHANGED
|
@@ -53,7 +53,7 @@ const withBaseVersion = (baseVersions, itemBaseVersions, { every = false } = {})
|
|
|
53
53
|
// present AND for items the files dropped. A push deletes only the items it holds a
|
|
54
54
|
// version for, and only while the site left them unchanged — so a dropped item's
|
|
55
55
|
// version is what makes leaving it out a deletion, and without it the item is kept
|
|
56
|
-
// [Diego, 2026-10-07; backend's gate
|
|
56
|
+
// [Diego, 2026-10-07; backend's gate]. The
|
|
57
57
|
// caller holds a version only for an item it has seen (`heldTokens`, cli), so none is
|
|
58
58
|
// ever sent for an item the backend holds and this copy does not.
|
|
59
59
|
// ⛔ Until then this narrowed to the units the document carried: a dropped page was
|
package/src/uwx/sync-store.js
CHANGED
|
@@ -11,9 +11,6 @@
|
|
|
11
11
|
* ⭐ **If it changed, something got synced.** Nothing else writes it — which is the
|
|
12
12
|
* whole reason it is separate from `deploy.yml`, whose diff means "a target changed".
|
|
13
13
|
*
|
|
14
|
-
* Spec: `kb/framework/reference/sync-json.md`. Why it exists at all:
|
|
15
|
-
* `kb/framework/plans/backend-scoped-project-state.md`.
|
|
16
|
-
*
|
|
17
14
|
* ## Why it is keyed by ORIGIN, all the way down
|
|
18
15
|
*
|
|
19
16
|
* A project may sync with any number of backends. Nothing can be shared between
|