@uniweb/build 0.18.4 → 0.18.5
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 +8 -8
- package/src/uwx/index.js +1 -0
- package/src/uwx/site-project.js +10 -0
- package/src/uwx/site.js +106 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/build",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.5",
|
|
4
4
|
"description": "Build tooling for the Uniweb Component Web Platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -59,16 +59,16 @@
|
|
|
59
59
|
"js-yaml": "^4.1.0",
|
|
60
60
|
"sharp": "^0.35.3",
|
|
61
61
|
"yaml": "^2.5.0",
|
|
62
|
-
"@uniweb/schemas": "^0.2.10",
|
|
63
62
|
"@uniweb/theming": "^0.1.15",
|
|
64
|
-
"@uniweb/projections": "^0.2.
|
|
65
|
-
"@uniweb/content-writer": "^0.3.3"
|
|
63
|
+
"@uniweb/projections": "^0.2.8",
|
|
64
|
+
"@uniweb/content-writer": "^0.3.3",
|
|
65
|
+
"@uniweb/schemas": "^0.2.10"
|
|
66
66
|
},
|
|
67
67
|
"optionalDependencies": {
|
|
68
|
+
"@uniweb/runtime": "^0.11.5",
|
|
69
|
+
"@uniweb/semantic-parser": "^1.2.2",
|
|
68
70
|
"@uniweb/content-reader": "^1.2.2",
|
|
69
|
-
"@uniweb/schemas": "^0.2.10"
|
|
70
|
-
"@uniweb/runtime": "^0.11.4",
|
|
71
|
-
"@uniweb/semantic-parser": "^1.2.1"
|
|
71
|
+
"@uniweb/schemas": "^0.2.10"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@tailwindcss/vite": "^4.0.0",
|
|
78
78
|
"@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
|
|
79
79
|
"vite-plugin-svgr": "^4.0.0",
|
|
80
|
-
"@uniweb/core": "^0.8.
|
|
80
|
+
"@uniweb/core": "^0.8.5"
|
|
81
81
|
},
|
|
82
82
|
"peerDependenciesMeta": {
|
|
83
83
|
"vite": {
|
package/src/uwx/index.js
CHANGED
package/src/uwx/site-project.js
CHANGED
|
@@ -106,6 +106,16 @@ const INFO_TO_SITE_YML = {
|
|
|
106
106
|
// render time and never enters `info`.
|
|
107
107
|
submit: 'submit',
|
|
108
108
|
agents: 'agents',
|
|
109
|
+
// Authored-only, like `submit` above — a host's assistant endpoint is offered
|
|
110
|
+
// through `config.services` and resolved at render time, so it never enters
|
|
111
|
+
// `info` and a pull cannot launder it into authored config.
|
|
112
|
+
//
|
|
113
|
+
// ⚠️ One asymmetry worth knowing: push STRIPS credential-shaped keys, so a
|
|
114
|
+
// block that carried an `apiKey` comes back without it and the pull rewrites
|
|
115
|
+
// the author's file minus that line. That is intended — the key must not be
|
|
116
|
+
// there and the push already warned — but it is the one case where a pull
|
|
117
|
+
// removes something the author typed.
|
|
118
|
+
assistant: 'assistant',
|
|
109
119
|
paths: 'paths',
|
|
110
120
|
data: 'data',
|
|
111
121
|
template: 'template',
|
package/src/uwx/site.js
CHANGED
|
@@ -68,6 +68,46 @@ function setIf(obj, key, value) {
|
|
|
68
68
|
if (value !== undefined) obj[key] = value
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// Credential-shaped keys, mirroring the set the delivery edge strips on the
|
|
72
|
+
// reading side. Deliberately the SAME list rather than a stricter one, so the
|
|
73
|
+
// two guards are visibly twins and a key added to one is obviously owed to the
|
|
74
|
+
// other.
|
|
75
|
+
const CREDENTIAL_KEYS = ['apiKey', 'api_key', 'key', 'token', 'secret']
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Drop credential-shaped keys out of an authored service block.
|
|
79
|
+
*
|
|
80
|
+
* An authored block crosses into backend storage here and is served from there
|
|
81
|
+
* in a published payload — which is world-readable. So a credential in
|
|
82
|
+
* `site.yml` is not merely untidy, it is disclosed. The host's secret store is
|
|
83
|
+
* the only right home, resolved at request time.
|
|
84
|
+
*
|
|
85
|
+
* Warns rather than throwing: the fix belongs to the author, a failed push
|
|
86
|
+
* helps nobody, and the block is still useful without the key. Returns the
|
|
87
|
+
* value untouched when there is nothing to strip, so `setIf`'s absent-vs-empty
|
|
88
|
+
* behaviour is unchanged — a block that carried ONLY a credential arrives as
|
|
89
|
+
* `{}` rather than vanishing, keeping the mistake visible where the author
|
|
90
|
+
* looks for it.
|
|
91
|
+
*
|
|
92
|
+
* @param {*} block - the authored value, any shape
|
|
93
|
+
* @param {string} label - the site.yml key, for the warning
|
|
94
|
+
* @returns {*} the block, minus anything credential-shaped
|
|
95
|
+
*/
|
|
96
|
+
function stripCredentials(block, label) {
|
|
97
|
+
if (!block || typeof block !== 'object' || Array.isArray(block)) return block
|
|
98
|
+
const found = CREDENTIAL_KEYS.filter(key => key in block)
|
|
99
|
+
if (found.length === 0) return block
|
|
100
|
+
|
|
101
|
+
console.warn(
|
|
102
|
+
`uwx/site: dropped ${found.join(', ')} from \`${label}:\` — authored config is published ` +
|
|
103
|
+
'world-readable, so a credential belongs in the host secret store, never in site.yml.'
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
const cleaned = { ...block }
|
|
107
|
+
for (const key of found) delete cleaned[key]
|
|
108
|
+
return cleaned
|
|
109
|
+
}
|
|
110
|
+
|
|
71
111
|
// page_sections and layout_sections share this content shape.
|
|
72
112
|
// processMarkdownFile only destructures type/component/preset/input/props/
|
|
73
113
|
// fetch/data/id out of frontmatter, so `background:` and `theme:` stay
|
|
@@ -700,6 +740,22 @@ export async function siteProjectToDocument(siteRoot, opts = {}) {
|
|
|
700
740
|
// excluded branch becomes both discoverable AND summarized by the index.
|
|
701
741
|
// (The CLI lane reads site.yml directly and honors it either way.)
|
|
702
742
|
setIf(info, 'agents', siteYml.agents)
|
|
743
|
+
// `assistant` — the site's own declaration for an AI assistant: where it
|
|
744
|
+
// lives (`endpoint`, read by kit's `resolveService`) plus authored settings a
|
|
745
|
+
// host reads (`system` persona, model hints). Same family as
|
|
746
|
+
// `search`/`submit`, and here for the reason spelled out above them — the
|
|
747
|
+
// bundle lane spreads all of site.yml while this one is an allowlist, so
|
|
748
|
+
// without this line the block works on a static host and vanishes silently
|
|
749
|
+
// on the synced lane.
|
|
750
|
+
//
|
|
751
|
+
// ⚠️ That is not hypothetical: this replaces `intelligence.yml`, a SEPARATE
|
|
752
|
+
// file, which needed a bespoke line in each lane and got one in only the
|
|
753
|
+
// bundle lane — so an authored persona never reached a hosted site at all.
|
|
754
|
+
// A key inside site.yml cannot repeat that, because only this lane needs a
|
|
755
|
+
// line. (kb/framework/architecture/assistant-config.md)
|
|
756
|
+
//
|
|
757
|
+
// ⛔ Credentials are stripped, not trusted — see `stripCredentials`.
|
|
758
|
+
setIf(info, 'assistant', stripCredentials(siteYml.assistant, 'assistant'))
|
|
703
759
|
setIf(info, 'paths', siteYml.paths)
|
|
704
760
|
setIf(info, 'data', siteYml.data ?? siteYml.fetch)
|
|
705
761
|
// `app` — the deployment's `@uniweb/app-spec` reference (a bare uuid string),
|
|
@@ -804,3 +860,53 @@ export async function emitSiteSyncPackage(siteRoot, opts = {}) {
|
|
|
804
860
|
export function writeSiteEntityUuid(siteRoot, uuid) {
|
|
805
861
|
return upsertYamlScalar(join(siteRoot, 'site.yml'), '$uuid', uuid)
|
|
806
862
|
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Record the org the site was CREATED under (`site.yml::$org`), beside `$uuid`.
|
|
866
|
+
*
|
|
867
|
+
* The org is consumed at exactly one moment — the `as_org` on the create that
|
|
868
|
+
* mints `$uuid` — and after that the uuid carries the ownership binding. So this
|
|
869
|
+
* is not a knob the backend re-reads; it is the answer to *"whose workspace is
|
|
870
|
+
* this site's storage charged to?"*, which `$uuid` alone cannot answer and which
|
|
871
|
+
* otherwise costs a backend round-trip (or is simply unknowable from the repo).
|
|
872
|
+
*
|
|
873
|
+
* Stored as the BARE handle, never `@handle`: `upsertYamlScalar` writes the value
|
|
874
|
+
* verbatim, and `@` is a reserved YAML indicator, so a plain scalar may not start
|
|
875
|
+
* with one — `$org: @acme` is a parse error. The bare form is also the canonical
|
|
876
|
+
* one everywhere else (`deriveScope` returns it, `createOrg` echoes it as
|
|
877
|
+
* `org.handle`, `validateHandle` validates it); the `@` is display sugar the
|
|
878
|
+
* reader re-adds.
|
|
879
|
+
*
|
|
880
|
+
* Safe to add to `site.yml` because the sync lane is an explicit allowlist
|
|
881
|
+
* (`info.*` above is built key by key), so this never rides the wire.
|
|
882
|
+
*
|
|
883
|
+
* ⛔ NOT `deploy.yml`, though that file already holds the bound `backend` and the
|
|
884
|
+
* two look like the same class of fact. Four reasons, and the first is the one that
|
|
885
|
+
* settles it:
|
|
886
|
+
*
|
|
887
|
+
* 1. CARDINALITY. `deploy.yml` is multi-TARGET and `backend` sits *under* a target,
|
|
888
|
+
* so its shape says "this may vary per target." An org may not: one site has one
|
|
889
|
+
* owning org, fixed at create and preserved on replace. `$org` is a property of
|
|
890
|
+
* `$uuid`, which is singular and lives here — filing it under a target would
|
|
891
|
+
* encode a freedom that does not exist.
|
|
892
|
+
* 2. WHO WRITES. Three paths mint a site (`ensureSiteExists`, the media-less push's
|
|
893
|
+
* content-lane create, and `clone` seeding an existing one) and **none of them
|
|
894
|
+
* write `deploy.yml`** — only `deploy` and `publish` call `recordLastDeploy`. The
|
|
895
|
+
* record would exist or not depending on which verb the developer reached for.
|
|
896
|
+
* 3. SUPPRESSIBLE. `recordLastDeploy` is a no-op under `autoSave: off` / `--no-save`.
|
|
897
|
+
* Turning off deploy *receipts* would silently drop an *ownership* record.
|
|
898
|
+
* 4. SEMANTICS. `deploy.yml` describes the act of shipping (`lastDeploy` is a
|
|
899
|
+
* receipt) and is optional entirely. But `push` creates a site and never
|
|
900
|
+
* publishes — a site can exist, be owned, and accrue storage charges without
|
|
901
|
+
* ever being deployed. Ownership does not belong in a record of a deploy that
|
|
902
|
+
* may not have happened.
|
|
903
|
+
*
|
|
904
|
+
* `backend` answers *where this ships*; `$org` answers *whose this is*.
|
|
905
|
+
*
|
|
906
|
+
* @param {string} siteRoot
|
|
907
|
+
* @param {string} handle - the bare org handle (no leading `@`)
|
|
908
|
+
* @returns {boolean} true if site.yml changed
|
|
909
|
+
*/
|
|
910
|
+
export function writeSiteOrg(siteRoot, handle) {
|
|
911
|
+
return upsertYamlScalar(join(siteRoot, 'site.yml'), '$org', handle)
|
|
912
|
+
}
|