@uniweb/build 0.33.0 → 0.35.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 +7 -7
- package/src/site/data-fetcher.js +48 -6
- package/src/uwx/site.js +13 -2
- package/src/validate-data.js +9 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/build",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Build tooling for the Uniweb Component Web Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"js-yaml": "^4.1.0",
|
|
60
60
|
"sharp": "^0.35.3",
|
|
61
61
|
"yaml": "^2.5.0",
|
|
62
|
-
"@uniweb/
|
|
63
|
-
"@uniweb/projections": "^0.5.4",
|
|
62
|
+
"@uniweb/projections": "^0.5.6",
|
|
64
63
|
"@uniweb/theming": "^0.1.15",
|
|
65
|
-
"@uniweb/content-reader": "^1.2.4",
|
|
66
64
|
"@uniweb/semantic-parser": "^1.4.0",
|
|
67
|
-
"@uniweb/content-writer": "^0.3.4"
|
|
65
|
+
"@uniweb/content-writer": "^0.3.4",
|
|
66
|
+
"@uniweb/content-reader": "^1.2.4",
|
|
67
|
+
"@uniweb/schemas": "^0.2.13"
|
|
68
68
|
},
|
|
69
69
|
"optionalDependencies": {
|
|
70
|
-
"@uniweb/runtime": "^0.13.
|
|
70
|
+
"@uniweb/runtime": "^0.13.7"
|
|
71
71
|
},
|
|
72
72
|
"peerDependencies": {
|
|
73
73
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@tailwindcss/vite": "^4.0.0",
|
|
77
77
|
"@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
|
|
78
78
|
"vite-plugin-svgr": "^4.0.0",
|
|
79
|
-
"@uniweb/core": "^0.
|
|
79
|
+
"@uniweb/core": "^0.18.0"
|
|
80
80
|
},
|
|
81
81
|
"peerDependenciesMeta": {
|
|
82
82
|
"vite": {
|
package/src/site/data-fetcher.js
CHANGED
|
@@ -253,11 +253,11 @@ export function applyPostProcessing(data, config) {
|
|
|
253
253
|
const RECOGNIZED_FETCH_KEYS = {
|
|
254
254
|
refine: new Set(['refine', 'inherit', 'detail', 'limit', 'sort', 'where', 'filter']),
|
|
255
255
|
query: new Set([
|
|
256
|
-
'query', 'schema', 'prerender', 'merge', 'transform',
|
|
256
|
+
'query', 'as', 'schema', 'prerender', 'merge', 'transform',
|
|
257
257
|
'where', 'limit', 'sort', 'detailPage', 'filter',
|
|
258
258
|
]),
|
|
259
259
|
source: new Set([
|
|
260
|
-
'path', 'url', 'schema', 'prerender', 'merge', 'transform', 'detail',
|
|
260
|
+
'path', 'url', 'as', 'schema', 'prerender', 'merge', 'transform', 'detail',
|
|
261
261
|
'detailPage', 'where', 'limit', 'sort', 'filter',
|
|
262
262
|
]),
|
|
263
263
|
}
|
|
@@ -288,11 +288,13 @@ export function parseFetchConfig(fetch) {
|
|
|
288
288
|
|
|
289
289
|
// Simple string: "/data/team.json"
|
|
290
290
|
if (typeof fetch === 'string') {
|
|
291
|
-
const
|
|
291
|
+
const inferred = inferSchemaFromPath(fetch)
|
|
292
292
|
return {
|
|
293
293
|
path: fetch,
|
|
294
294
|
url: undefined,
|
|
295
|
-
|
|
295
|
+
// Both spellings — see the note in the named-query branch below.
|
|
296
|
+
as: inferred,
|
|
297
|
+
schema: inferred,
|
|
296
298
|
prerender: true,
|
|
297
299
|
merge: false,
|
|
298
300
|
transform: undefined,
|
|
@@ -349,9 +351,46 @@ export function parseFetchConfig(fetch) {
|
|
|
349
351
|
warnUnknownFetchKeys(fetch, 'query')
|
|
350
352
|
if (fetch.filter !== undefined) warnFilterDeprecated()
|
|
351
353
|
return {
|
|
354
|
+
// ⭐ **`query` IS EMITTED, and that is what makes the two producers agree.**
|
|
355
|
+
// The sync lane has always emitted it (`uwx/site.js`) and this one did not,
|
|
356
|
+
// for the same declaration — so `resolveQuerySource` fired on a published
|
|
357
|
+
// site and never on a `--link`-deployed one. Measured 2026-09-02 against a
|
|
358
|
+
// host declaring `config.records`:
|
|
359
|
+
//
|
|
360
|
+
// --link endpoint undefined, path /data/articles.json ← the STATIC file
|
|
361
|
+
// publish endpoint /_api/q/articles ← the live lane
|
|
362
|
+
//
|
|
363
|
+
// Same site, same declaration, two verbs, two data sources. Publishing to a
|
|
364
|
+
// platform that declares a live lane is supposed to READ from it — the
|
|
365
|
+
// compiled `/data/*.json` is the escape hatch for entities with no known
|
|
366
|
+
// data schema, which never sync, not a second way to serve the ones that do.
|
|
367
|
+
//
|
|
368
|
+
// ⚠️ Not in the cache key: `deriveCacheKey` hashes {path,url,endpoint,schema,
|
|
369
|
+
// transform}, so adding this moves no cached entry.
|
|
370
|
+
query: fetch.query,
|
|
352
371
|
path: queryDataUrl(fetch.query),
|
|
353
372
|
url: undefined,
|
|
354
|
-
|
|
373
|
+
// ⭐ **`as`, not `schema`.** The BINDING KEY — the `content.data.<key>` a
|
|
374
|
+
// component reads — defaults to the query name. It was called `schema`
|
|
375
|
+
// until 2026-09-02, which collided with the MODEL REF of the same name on a
|
|
376
|
+
// `queries` declaration; `fetch.schema` is still accepted as input so
|
|
377
|
+
// existing content keeps working, and is never emitted.
|
|
378
|
+
// ⛔ **BOTH SPELLINGS ARE EMITTED, and this is not the overload coming back.**
|
|
379
|
+
// `bindingKey()` reads `as ?? schema`, so NEW core needs only `as`. But a
|
|
380
|
+
// published site renders at ITS OWN pinned runtime version, and every
|
|
381
|
+
// runtime shipped to date bundles a core whose resolver does
|
|
382
|
+
// `if (!cfg?.schema) continue` — so an `as`-only payload served by an older
|
|
383
|
+
// runtime is SKIPPED ENTIRELY. No data, nothing thrown, nothing logged.
|
|
384
|
+
//
|
|
385
|
+
// ⭐ The compatibility runs the OTHER WAY from `bindingKey`'s: that one is
|
|
386
|
+
// old payloads meeting new code, this one is new payloads meeting old code,
|
|
387
|
+
// and only the first was covered. Caught by frontend before it shipped.
|
|
388
|
+
//
|
|
389
|
+
// ⇒ Emit both until every serving runtime carries `bindingKey`, then drop
|
|
390
|
+
// `schema` here. Until then a reader may see this as redundant; it is a
|
|
391
|
+
// compatibility duplicate and the comment is what tells them apart.
|
|
392
|
+
as: fetch.as || fetch.schema || fetch.query,
|
|
393
|
+
schema: fetch.as || fetch.schema || fetch.query,
|
|
355
394
|
prerender: fetch.prerender ?? true,
|
|
356
395
|
merge: fetch.merge ?? false,
|
|
357
396
|
transform: fetch.transform,
|
|
@@ -371,6 +410,7 @@ export function parseFetchConfig(fetch) {
|
|
|
371
410
|
const {
|
|
372
411
|
path,
|
|
373
412
|
url,
|
|
413
|
+
as,
|
|
374
414
|
schema,
|
|
375
415
|
prerender = url ? false : true,
|
|
376
416
|
merge = false,
|
|
@@ -393,7 +433,9 @@ export function parseFetchConfig(fetch) {
|
|
|
393
433
|
return {
|
|
394
434
|
path,
|
|
395
435
|
url,
|
|
396
|
-
|
|
436
|
+
// Both spellings — see the note in the named-query branch above.
|
|
437
|
+
as: as ?? schema ?? inferSchemaFromPath(path || url),
|
|
438
|
+
schema: as ?? schema ?? inferSchemaFromPath(path || url),
|
|
397
439
|
prerender,
|
|
398
440
|
merge,
|
|
399
441
|
transform,
|
package/src/uwx/site.js
CHANGED
|
@@ -251,7 +251,11 @@ function buildPageData(config, ctx) {
|
|
|
251
251
|
//
|
|
252
252
|
// `schema` (the query name) is BOTH the content.data key and part of the
|
|
253
253
|
// dataStore cache key (deriveCacheKey hashes {path,url,endpoint,schema,…};
|
|
254
|
-
// the shorthand is ignored). Mirrors the static build's parseFetchConfig
|
|
254
|
+
// the shorthand is ignored). Mirrors the static build's parseFetchConfig —
|
|
255
|
+
// ⚠️ which it did NOT until 2026-09-02. This line emitted `query` and that
|
|
256
|
+
// one did not, for the same declaration, so `resolveQuerySource` fired on a
|
|
257
|
+
// published site and never on a `--link`-deployed one: same site, two verbs,
|
|
258
|
+
// two data sources. The claim was here the whole time; the mirroring was not.
|
|
255
259
|
// ⭐ `query`, END TO END — no crossing. An earlier version emitted `collection`
|
|
256
260
|
// here on the belief that this field was the backend's to name. MEASURED
|
|
257
261
|
// otherwise: framework already ships `transform`, `detailPage`, `merge` and
|
|
@@ -259,7 +263,14 @@ function buildPageData(config, ctx) {
|
|
|
259
263
|
// validating — so `fetch` is a blob they carry and framework owns its
|
|
260
264
|
// vocabulary. ⇒ There was nothing to coordinate, and inventing a coordination
|
|
261
265
|
// is how a name stays wrong.
|
|
262
|
-
|
|
266
|
+
// ⛔ `as`, the BINDING KEY — not to be confused with `schema` at
|
|
267
|
+
// DECL_EMITTED_ABOVE / `setIf(data,'schema',d.schema)` below, which is a
|
|
268
|
+
// queries decl's MODEL REF and keeps its name. One word meant both until
|
|
269
|
+
// 2026-09-02; this is the half that moved.
|
|
270
|
+
// Both spellings, deliberately — an `as`-only payload is skipped entirely by
|
|
271
|
+
// any runtime older than `bindingKey` (`if (!cfg?.schema) continue`), with no
|
|
272
|
+
// data and no error. Drop `schema` when every serving runtime carries it.
|
|
273
|
+
fetch = { query, path: queryDataUrl(query), as: query, schema: query, ...rest }
|
|
263
274
|
}
|
|
264
275
|
setIf(data, 'fetch', fetch)
|
|
265
276
|
if (isDynamic) {
|
package/src/validate-data.js
CHANGED
|
@@ -104,7 +104,7 @@ export async function validateDataInputs({ siteRoot, foundationPath }) {
|
|
|
104
104
|
if (!type) return
|
|
105
105
|
const bindings = foundation[type]?.data
|
|
106
106
|
for (const input of collectInputs(section, page.fetch, config.fetch)) {
|
|
107
|
-
const key = input.schema // the content.data KEY
|
|
107
|
+
const key = input.as ?? input.schema // the content.data KEY; `schema` is its pre-2026-09-02 name
|
|
108
108
|
|
|
109
109
|
if (input.url) {
|
|
110
110
|
deferred.push({ route: page.route, section: type, key, reason: 'remote url: source', url: input.url })
|
|
@@ -437,8 +437,14 @@ async function loadStandardSchemas() {
|
|
|
437
437
|
function collectInputs(section, pageFetch, siteFetch) {
|
|
438
438
|
const byKey = new Map()
|
|
439
439
|
for (const f of [siteFetch, pageFetch, section.fetch]) {
|
|
440
|
-
|
|
441
|
-
|
|
440
|
+
// ⛔ The binding key is `as`; `schema` is its pre-2026-09-02 name and still
|
|
441
|
+
// arrives on stored payloads. A gate on the old name alone silently yields
|
|
442
|
+
// NOTHING here — no inputs collected, no violations found, a green run — which
|
|
443
|
+
// is exactly how this was caught: the integration test went from flagging the
|
|
444
|
+
// seeded violations to flagging none.
|
|
445
|
+
const key = f?.as ?? f?.schema
|
|
446
|
+
if (f && (f.path || f.url) && typeof key === 'string') {
|
|
447
|
+
byKey.set(key, f)
|
|
442
448
|
}
|
|
443
449
|
}
|
|
444
450
|
return [...byKey.values()]
|