uniweb 0.48.4 → 0.48.6
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/partials/agents.md +24 -20
- package/src/backend/asset-download.js +31 -4
- package/src/backend/site-media.js +12 -1
- package/src/backend/site-sync.js +47 -1
- package/src/commands/publish.js +12 -0
- package/src/commands/push.js +5 -0
- package/src/framework-index.json +7 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.6",
|
|
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.24.
|
|
45
|
-
"@uniweb/kit": "^0.18.
|
|
46
|
-
"@uniweb/
|
|
47
|
-
"@uniweb/
|
|
44
|
+
"@uniweb/core": "^0.24.4",
|
|
45
|
+
"@uniweb/kit": "^0.18.2",
|
|
46
|
+
"@uniweb/semantic-parser": "^1.4.0",
|
|
47
|
+
"@uniweb/runtime": "^0.19.5"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
+
"@uniweb/build": "^0.44.5",
|
|
50
51
|
"@uniweb/content-reader": "^1.2.4",
|
|
51
|
-
"@uniweb/semantic-parser": "^1.4.0"
|
|
52
|
-
"@uniweb/build": "^0.44.3"
|
|
52
|
+
"@uniweb/semantic-parser": "^1.4.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -86,7 +86,7 @@ Documentation paths in this guide are given bare — `development/creating-compo
|
|
|
86
86
|
| Theming and styling | `authoring/theming.md` |
|
|
87
87
|
| Authoring collections | `authoring/collections.md` |
|
|
88
88
|
| Where-object predicate format | `authoring/predicates.md` |
|
|
89
|
-
|
|
|
89
|
+
| Data sources / custom transports | `development/data-sources.md` |
|
|
90
90
|
| Building components | `development/creating-components.md` |
|
|
91
91
|
| Schemas in practice | `development/schemas-in-practice.md` |
|
|
92
92
|
| Workspace layouts and their wiring | `development/project-structures.md` |
|
|
@@ -1843,7 +1843,7 @@ fetcher:
|
|
|
1843
1843
|
|
|
1844
1844
|
**Failures are visible, not empty:** a fetch that failed leaves its key ABSENT from `content.data` and names the message on `block.dataError[key]`; it is never delivered as `[]`, which means "no records". The page still renders — a section reads `dataError` to tell the two apart.
|
|
1845
1845
|
|
|
1846
|
-
When a plain `url:` is enough and when a transport is the answer: `development/
|
|
1846
|
+
When a plain `url:` is enough and when a transport is the answer: `development/data-sources.md`.
|
|
1847
1847
|
|
|
1848
1848
|
Full model: `reference/data-fetching.md`. Where-object format with examples: `authoring/predicates.md`.
|
|
1849
1849
|
|
|
@@ -1895,16 +1895,18 @@ section type, same arrangement as `fetcher:` and `search:`.
|
|
|
1895
1895
|
|
|
1896
1896
|
A form gets its destination from the first of these that applies:
|
|
1897
1897
|
|
|
1898
|
-
1.
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1898
|
+
1. **One the host supplies** — `services.submit` in the served payload. Where the
|
|
1899
|
+
host handles submissions, that is the destination and nothing in `site.yml`
|
|
1900
|
+
overrides it — so a site published to Uniweb Cloud normally needs **no
|
|
1901
|
+
`submit:` at all**.
|
|
1902
|
+
2. **`submit:` in `site.yml`** — an endpoint you name yourself, for a host that
|
|
1903
|
+
does not handle submissions, or a static site.
|
|
1902
1904
|
3. **Neither** — there is no destination, and the form says so instead of
|
|
1903
1905
|
guessing at one.
|
|
1904
1906
|
|
|
1905
1907
|
That is the general arrangement, not a forms-only one. A host declares
|
|
1906
1908
|
everything it offers under `services`, keyed by name, and every service resolves
|
|
1907
|
-
by the same rule —
|
|
1909
|
+
by the same rule — the host's offer, then your declaration, then neither.
|
|
1908
1910
|
|
|
1909
1911
|
⭐ **Before you render UI for a service, ask whether the site has it** — one predicate per service,
|
|
1910
1912
|
no arguments: `isSearchEnabled()`, `isSubmitEnabled()`, `isApiEnabled()`, `isAssistantEnabled()`,
|
|
@@ -2097,7 +2099,7 @@ tracking:
|
|
|
2097
2099
|
```
|
|
2098
2100
|
|
|
2099
2101
|
A host may also supply one under `services.tracking`, and the usual precedence
|
|
2100
|
-
applies:
|
|
2102
|
+
applies: the host's, then yours, then neither.
|
|
2101
2103
|
|
|
2102
2104
|
⚠️ **The endpoint has to accept the framework's own format** — a batched
|
|
2103
2105
|
`{ "events": [ … ] }` POST, documented in `reference/site-configuration.md`. It
|
|
@@ -2166,17 +2168,18 @@ tracking:
|
|
|
2166
2168
|
⭐ **`emit` needs no endpoint of its own.** Where a host provides one, the site
|
|
2167
2169
|
declares only what it wants sent and the address comes from the host. The two
|
|
2168
2170
|
are read key by key, so naming `emit` alone overrides nothing else the host
|
|
2169
|
-
declared.
|
|
2170
|
-
|
|
2171
|
+
declared. An `endpoint:` of your own is used wherever the host supplies no
|
|
2172
|
+
collector — on a host without one, and on none — and where the host supplies
|
|
2173
|
+
one, the host's is used.
|
|
2171
2174
|
|
|
2172
|
-
`minimal` is `page_view` alone. `standard` is the default when
|
|
2173
|
-
own `
|
|
2175
|
+
`minimal` is `page_view` alone. `standard` is the default when the collector is
|
|
2176
|
+
your own. `all` is a standing yes, so an event added in a later framework
|
|
2174
2177
|
release is included without you changing anything — which is exactly why
|
|
2175
2178
|
`standard` exists as well: it is a curated set that a release cannot grow behind
|
|
2176
2179
|
your back.
|
|
2177
2180
|
|
|
2178
2181
|
⭐ **Saying nothing means two different things, and which one depends on who
|
|
2179
|
-
supplies the address.** A site
|
|
2182
|
+
supplies the address.** A site sending to its own `endpoint:` gets `standard`. A site
|
|
2180
2183
|
on a **host-supplied** collector gets **whatever that host declares it
|
|
2181
2184
|
collects** — it has no address of its own, so the arrangement is that the host
|
|
2182
2185
|
does analytics for it, and the set grows when the host starts collecting
|
|
@@ -2324,10 +2327,10 @@ For cases the factory doesn't cover, write handlers directly using `Loom`, `inst
|
|
|
2324
2327
|
## Part 4b — When the site is also an app
|
|
2325
2328
|
|
|
2326
2329
|
Everything above is a site: content the author writes, built into pages. Some sites
|
|
2327
|
-
also have **
|
|
2328
|
-
create and edit.
|
|
2330
|
+
also have **an `api` service** — accounts, per-visitor data, records their members
|
|
2331
|
+
create and edit. `@uniweb/api` is its client.
|
|
2329
2332
|
|
|
2330
|
-
⛔ **Only reach for this when the site actually has one.** A site
|
|
2333
|
+
⛔ **Only reach for this when the site actually has one.** A site without one is
|
|
2331
2334
|
the normal case, and a foundation that assumes one breaks on every other site it is
|
|
2332
2335
|
used with.
|
|
2333
2336
|
|
|
@@ -2344,7 +2347,7 @@ import { useSession, SignedIn, SignedOut } from '@uniweb/api'
|
|
|
2344
2347
|
if (!isApiEnabled()) return <StaticVersion /> // synchronous — nothing to await
|
|
2345
2348
|
```
|
|
2346
2349
|
|
|
2347
|
-
⛔ **When
|
|
2350
|
+
⛔ **When the site has no `api` service, draw nothing** — not a disabled control, and not an
|
|
2348
2351
|
explanation. Same rule as `services` in Part 4: which capabilities a site's operator
|
|
2349
2352
|
set up is none of a visitor's business, and "sign-in unavailable" reads as breakage
|
|
2350
2353
|
when it is simply a feature this site does not have. Render the version of your
|
|
@@ -2357,8 +2360,8 @@ const { status, records } = useRecords({ schema: '@/session' })
|
|
|
2357
2360
|
```
|
|
2358
2361
|
|
|
2359
2362
|
⭐ **`absent` and an empty `ready` are different answers, and confusing them is the
|
|
2360
|
-
mistake to avoid.** `absent` = there is no live source (no
|
|
2361
|
-
in) → render the site's authored content. `ready` with `records: []` = the
|
|
2363
|
+
mistake to avoid.** `absent` = there is no live source (no `api` service, or nobody signed
|
|
2364
|
+
in) → render the site's authored content. `ready` with `records: []` = the service
|
|
2362
2365
|
answered and there is nothing there → render your empty state. Showing "nothing yet"
|
|
2363
2366
|
for the first tells a visitor their content is gone when it was never requested.
|
|
2364
2367
|
|
|
@@ -2444,6 +2447,7 @@ uniweb add ci --target foundation # Publish a foundation for free at permanent v
|
|
|
2444
2447
|
# (GitHub Pages → foundations/<name>/<version>/entry.js)
|
|
2445
2448
|
|
|
2446
2449
|
uniweb push / pull / clone / status # Git-style content sync with the Uniweb backend
|
|
2450
|
+
uniweb refresh / sync # Catch up (git + backend, never pushes) / catch up, then push
|
|
2447
2451
|
uniweb push --org @acme # First push/publish of a site: who owns it (see below)
|
|
2448
2452
|
uniweb register [--scope @org] # Register a foundation + its data schemas to the registry
|
|
2449
2453
|
uniweb login / logout # Start or clear the backend session the verbs above reuse
|
|
@@ -2513,7 +2517,7 @@ Foundations have their own free path too: `uniweb add ci --target foundation` pu
|
|
|
2513
2517
|
- **Git is the reviewed, durable record** — you `pull` content back, read it with `git diff`, and commit.
|
|
2514
2518
|
- **Authors never push or pull.** For them, content simply updates, whether the change came from another author or from a developer's CLI.
|
|
2515
2519
|
|
|
2516
|
-
**
|
|
2520
|
+
**Nobody's work is overwritten without asking.** `uniweb push` is refused if the site changed on the backend since your last pull — usually an author editing in the app — and reports what changed; nothing is written. Edits to different sections never collide. `uniweb pull` overwrites rather than merges, so it refuses while you have uncommitted changes. The recovery for both is `uniweb pull --merge` (or `uniweb refresh`, which runs `git pull` first): changes to different parts of a file combine silently, and a genuine overlap leaves conflict markers and a non-zero exit — so `uniweb pull --merge && uniweb push` never ships markers. `--force` is the deliberate overwrite (on `push` it replaces the backend's changes, on `pull` it discards yours); don't use it to get past a refusal. `uniweb sync` is `refresh` then `push`; neither publishes.
|
|
2517
2521
|
|
|
2518
2522
|
**The Cloud also provides a real backend for structured data:** a database for every registered data schema, and a CMS that edits both static page content and dynamic data entities typed by those schemas. That's the piece that makes it viable for teams and client work — the client manages records, not markdown files.
|
|
2519
2523
|
|
|
@@ -34,7 +34,11 @@
|
|
|
34
34
|
import { mkdirSync, existsSync, writeFileSync } from 'node:fs'
|
|
35
35
|
import { dirname, join } from 'node:path'
|
|
36
36
|
import { ASSET_SLOTS } from '@uniweb/semantic-parser'
|
|
37
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
readAssetMap,
|
|
39
|
+
updateAssetMap,
|
|
40
|
+
servedFingerprint
|
|
41
|
+
} from '@uniweb/build/uwx'
|
|
38
42
|
|
|
39
43
|
/**
|
|
40
44
|
* Collect every `{ id, ext, url }` an entity document references.
|
|
@@ -43,7 +47,7 @@ import { readAssetMap, updateAssetMap } from '@uniweb/build/uwx'
|
|
|
43
47
|
* carrying the reference — so a ProseMirror image node's attrs and a section
|
|
44
48
|
* background's media object are both found by one walk.
|
|
45
49
|
*/
|
|
46
|
-
export function collectAssetRefs(document) {
|
|
50
|
+
export function collectAssetRefs(document, map = {}) {
|
|
47
51
|
const found = new Map() // id → { id, ext, url }
|
|
48
52
|
const visit = (node) => {
|
|
49
53
|
if (Array.isArray(node)) return node.forEach(visit)
|
|
@@ -59,6 +63,28 @@ export function collectAssetRefs(document) {
|
|
|
59
63
|
for (const v of Object.values(node)) visit(v)
|
|
60
64
|
}
|
|
61
65
|
visit(document)
|
|
66
|
+
// A BARE-STRING reference (`info.preview`, `seo.image`, a section param) has no
|
|
67
|
+
// object to carry identity beside it. The map recognizes it by the fingerprint the
|
|
68
|
+
// push recorded for its serve URL — see `servedFingerprint` in @uniweb/build/uwx.
|
|
69
|
+
const byServed = new Map()
|
|
70
|
+
for (const v of Object.values(map || {})) {
|
|
71
|
+
if (v?.served && v.id && !byServed.has(v.served)) byServed.set(v.served, v)
|
|
72
|
+
}
|
|
73
|
+
if (byServed.size) {
|
|
74
|
+
const visitStrings = (node) => {
|
|
75
|
+
if (typeof node === 'string') {
|
|
76
|
+
if (!node.startsWith('/') && !/^https?:\/\//i.test(node)) return
|
|
77
|
+
const entry = byServed.get(servedFingerprint(node))
|
|
78
|
+
if (entry && !found.has(entry.id))
|
|
79
|
+
found.set(entry.id, { id: entry.id, ext: entry.ext || '', url: node })
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
if (Array.isArray(node)) return node.forEach(visitStrings)
|
|
83
|
+
if (node && typeof node === 'object')
|
|
84
|
+
for (const v of Object.values(node)) visitStrings(v)
|
|
85
|
+
}
|
|
86
|
+
visitStrings(document)
|
|
87
|
+
}
|
|
62
88
|
return [...found.values()]
|
|
63
89
|
}
|
|
64
90
|
|
|
@@ -89,11 +115,12 @@ export async function downloadMissingAssets({
|
|
|
89
115
|
warn = () => {}
|
|
90
116
|
}) {
|
|
91
117
|
const doFetch = fetchImpl || ((u) => globalThis.fetch(u))
|
|
92
|
-
|
|
118
|
+
// Read first: a bare-string reference is only recognizable through the map.
|
|
119
|
+
const map = readAssetMap(siteDir)
|
|
120
|
+
const refs = collectAssetRefs(document, map)
|
|
93
121
|
const out = { downloaded: [], present: [], failed: [], skipped: [] }
|
|
94
122
|
if (!refs.length) return out
|
|
95
123
|
|
|
96
|
-
const map = readAssetMap(siteDir)
|
|
97
124
|
const byId = new Map()
|
|
98
125
|
for (const [ref, v] of Object.entries(map)) if (v?.id) byId.set(v.id, ref)
|
|
99
126
|
|
|
@@ -16,6 +16,7 @@ import { createHash } from 'node:crypto'
|
|
|
16
16
|
import { existsSync, readFileSync } from 'node:fs'
|
|
17
17
|
import { basename } from 'node:path'
|
|
18
18
|
import { resolveAssetPath } from '@uniweb/build/site'
|
|
19
|
+
import { servedFingerprint } from '@uniweb/build/uwx'
|
|
19
20
|
import { contentTypeFor } from '../utils/code-upload.js'
|
|
20
21
|
import { humanBytes } from '../utils/bytes.js'
|
|
21
22
|
|
|
@@ -79,7 +80,17 @@ export async function uploadSiteMedia(
|
|
|
79
80
|
for (const ref of refs) {
|
|
80
81
|
const entry = result.assetsByLocalUrl[ref]
|
|
81
82
|
if (!entry) continue
|
|
82
|
-
|
|
83
|
+
// `served` — a fingerprint of the address, never the address. It is how a pull
|
|
84
|
+
// recognizes this asset where the reference is a bare string with no room for an
|
|
85
|
+
// id beside it (`info.preview`, `seo.image`, a section param); `assets.json`'s
|
|
86
|
+
// header says why a hash and not the URL.
|
|
87
|
+
if (entry.id) {
|
|
88
|
+
ids[ref] = {
|
|
89
|
+
id: entry.id,
|
|
90
|
+
ext: entry.ext || '',
|
|
91
|
+
...(entry.serveUrl ? { served: servedFingerprint(entry.serveUrl) } : {})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
83
94
|
// The backend's canonical serve URL, READ — never composed. An entry without
|
|
84
95
|
// one is an asset we cannot address, and inventing a location for it is the
|
|
85
96
|
// exact failure this lane exists to avoid: a guessed host is SILENTLY wrong,
|
package/src/backend/site-sync.js
CHANGED
|
@@ -29,7 +29,8 @@ import {
|
|
|
29
29
|
collectUnitUuids,
|
|
30
30
|
collectFolderItemUuids,
|
|
31
31
|
collectQueryUuids,
|
|
32
|
-
readAssetMap
|
|
32
|
+
readAssetMap,
|
|
33
|
+
removeYamlScalar
|
|
33
34
|
} from '@uniweb/build/uwx'
|
|
34
35
|
|
|
35
36
|
// First entity `$`-document out of a `.uwx` we produced or the backend served.
|
|
@@ -323,6 +324,51 @@ export function clearRemoteSyncStateIfUnbound(siteDir) {
|
|
|
323
324
|
return stale
|
|
324
325
|
}
|
|
325
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Drop the `site.yml` values that describe ONE PARTICULAR backend site, when this
|
|
329
|
+
* project is bound to none (no `$uuid`) — a brand-new site, or the state our own
|
|
330
|
+
* "clear `$uuid` to re-publish as a new site" recovery puts you in:
|
|
331
|
+
*
|
|
332
|
+
* · `$url` — where the PREVIOUS site was live. The new one is not live anywhere
|
|
333
|
+
* yet; its first publish records its own.
|
|
334
|
+
* · `preview` in the APP's form — a timestamp naming the previous site's generated
|
|
335
|
+
* card image, which is keyed by that site's uuid and would dangle on this one.
|
|
336
|
+
*
|
|
337
|
+
* ⛔ An AUTHOR's preview is theirs and stays: a URL, or a path to an image in the
|
|
338
|
+
* project, is as good for the new site as for the old.
|
|
339
|
+
*
|
|
340
|
+
* The site.yml sibling of `clearRemoteSyncStateIfUnbound`, called beside it for the
|
|
341
|
+
* same reason — before the create mints a uuid and makes the project look bound.
|
|
342
|
+
*
|
|
343
|
+
* @param {string} siteDir
|
|
344
|
+
* @returns {string[]} the keys removed
|
|
345
|
+
*/
|
|
346
|
+
export function dropSiteBoundValues(siteDir) {
|
|
347
|
+
const file = join(siteDir, 'site.yml')
|
|
348
|
+
let y
|
|
349
|
+
try {
|
|
350
|
+
y = yaml.load(readFileSync(file, 'utf8'))
|
|
351
|
+
} catch {
|
|
352
|
+
return []
|
|
353
|
+
}
|
|
354
|
+
if (!y || typeof y !== 'object' || typeof y.$uuid === 'string') return []
|
|
355
|
+
const dropped = []
|
|
356
|
+
if (y.$url !== undefined && removeYamlScalar(file, '$url')) dropped.push('$url')
|
|
357
|
+
if (
|
|
358
|
+
y.preview !== undefined &&
|
|
359
|
+
!isAuthoredPreview(y.preview) &&
|
|
360
|
+
removeYamlScalar(file, 'preview')
|
|
361
|
+
) {
|
|
362
|
+
dropped.push('preview')
|
|
363
|
+
}
|
|
364
|
+
return dropped
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// An author's preview is an address — a URL, or a site-root / relative path. Anything
|
|
368
|
+
// else is the app's generated-image token.
|
|
369
|
+
const isAuthoredPreview = (v) =>
|
|
370
|
+
typeof v === 'string' && (/^https?:\/\//i.test(v) || /^\.{0,2}\//.test(v))
|
|
371
|
+
|
|
326
372
|
export function readSyncCache(siteDir) {
|
|
327
373
|
return readMap(siteDir, 'hashes')
|
|
328
374
|
}
|
package/src/commands/publish.js
CHANGED
|
@@ -87,6 +87,7 @@ import {
|
|
|
87
87
|
readFolderItemUuids,
|
|
88
88
|
ensureSiteExists,
|
|
89
89
|
clearRemoteSyncStateIfUnbound,
|
|
90
|
+
dropSiteBoundValues,
|
|
90
91
|
pushSyncPackages,
|
|
91
92
|
resolveSiteOrgForCreate
|
|
92
93
|
} from '../backend/site-sync.js'
|
|
@@ -578,6 +579,12 @@ export async function publish(args = []) {
|
|
|
578
579
|
`Cleared stale sync state from a previous site (${droppedState.join(', ')}).`
|
|
579
580
|
)
|
|
580
581
|
}
|
|
582
|
+
const droppedValues = dropSiteBoundValues(siteDir)
|
|
583
|
+
if (droppedValues.length) {
|
|
584
|
+
say.dim(
|
|
585
|
+
`Dropped the previous site's ${droppedValues.join(' and ')} from site.yml.`
|
|
586
|
+
)
|
|
587
|
+
}
|
|
581
588
|
|
|
582
589
|
// 3b. Make sure the SITE EXISTS before a single byte is uploaded.
|
|
583
590
|
//
|
|
@@ -1106,6 +1113,11 @@ export async function publish(args = []) {
|
|
|
1106
1113
|
say.dim(` site.yml lists ${unserved.join(', ')}, and ${unserved.length === 1 ? 'it was' : 'they were'} not published.`)
|
|
1107
1114
|
}
|
|
1108
1115
|
if (serveUrl) console.log(` ${c.cyan}${serveUrl}${c.reset}`)
|
|
1116
|
+
// ⛔ No site.yml write for where it went live. The backend records the reply's
|
|
1117
|
+
// `url` on `info.url` at every publish, and pull brings it into `site.yml::$url`
|
|
1118
|
+
// like any other key. A copy written here was a second writer that had to match
|
|
1119
|
+
// the backend's byte for byte (the address printed above is made absolute, so it
|
|
1120
|
+
// did not), and it left site.yml modified — which a plain `pull` refuses over.
|
|
1109
1121
|
if (result.deploy_uuid) say.dim(`deploy: ${result.deploy_uuid}`)
|
|
1110
1122
|
return { exitCode: 0 }
|
|
1111
1123
|
}
|
package/src/commands/push.js
CHANGED
|
@@ -89,6 +89,7 @@ import {
|
|
|
89
89
|
ensureItemUuids,
|
|
90
90
|
ensureSiteExists,
|
|
91
91
|
clearRemoteSyncStateIfUnbound,
|
|
92
|
+
dropSiteBoundValues,
|
|
92
93
|
pushSyncPackages,
|
|
93
94
|
resolveSiteOrgForCreate
|
|
94
95
|
} from '../backend/site-sync.js'
|
|
@@ -303,6 +304,10 @@ export async function push(args = [], deps = {}) {
|
|
|
303
304
|
`Cleared stale sync state from a previous site (${dropped.join(', ')}).`
|
|
304
305
|
)
|
|
305
306
|
}
|
|
307
|
+
const stale = dropSiteBoundValues(siteDir)
|
|
308
|
+
if (stale.length) {
|
|
309
|
+
note(`Dropped the previous site's ${stale.join(' and ')} from site.yml.`)
|
|
310
|
+
}
|
|
306
311
|
}
|
|
307
312
|
const priorHashes = readSyncCache(siteDir)
|
|
308
313
|
// Per-item identity, without which the backend reads every record as new and
|
package/src/framework-index.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-10T23:52:15.147Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/api": {
|
|
6
|
-
"version": "0.3.
|
|
6
|
+
"version": "0.3.1",
|
|
7
7
|
"path": "framework/api",
|
|
8
8
|
"deps": [
|
|
9
9
|
"@uniweb/core"
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
12
|
"@uniweb/build": {
|
|
13
|
-
"version": "0.44.
|
|
13
|
+
"version": "0.44.5",
|
|
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.24.
|
|
37
|
+
"version": "0.24.4",
|
|
38
38
|
"path": "framework/core",
|
|
39
39
|
"deps": [
|
|
40
40
|
"@uniweb/semantic-parser",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
]
|
|
55
55
|
},
|
|
56
56
|
"@uniweb/kit": {
|
|
57
|
-
"version": "0.18.
|
|
57
|
+
"version": "0.18.2",
|
|
58
58
|
"path": "framework/kit",
|
|
59
59
|
"deps": [
|
|
60
60
|
"@uniweb/core",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
]
|
|
83
83
|
},
|
|
84
84
|
"@uniweb/runtime": {
|
|
85
|
-
"version": "0.19.
|
|
85
|
+
"version": "0.19.5",
|
|
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.12.
|
|
113
|
+
"version": "0.12.5",
|
|
114
114
|
"path": "framework/templates",
|
|
115
115
|
"deps": []
|
|
116
116
|
},
|