@vmz/vmz 0.0.4 → 0.1.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/dist/build-assemble.d.ts +52 -0
- package/dist/build-assemble.js +191 -0
- package/dist/cdn-policy.d.ts +22 -4
- package/dist/cdn-policy.js +109 -10
- package/dist/cli.js +106 -24
- package/dist/delivery-profile.d.ts +74 -0
- package/dist/delivery-profile.js +279 -0
- package/dist/dev-session.js +2 -1
- package/dist/document-build.js +9 -4
- package/dist/document-enrich.js +8 -0
- package/dist/embedded-packaging.d.ts +22 -0
- package/dist/embedded-packaging.js +113 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/locale-check.js +11 -8
- package/dist/locale-cmd.js +2 -2
- package/dist/locale-route-emit.d.ts +34 -0
- package/dist/locale-route-emit.js +134 -0
- package/dist/locale-router.d.ts +20 -0
- package/dist/locale-router.js +68 -0
- package/dist/log.d.ts +2 -2
- package/dist/log.js +11 -3
- package/dist/pack.d.ts +40 -0
- package/dist/pack.js +108 -0
- package/dist/plugin-host.d.ts +1 -1
- package/dist/plugin-host.js +2 -2
- package/dist/production-test-pack.d.ts +0 -14
- package/dist/production-test-pack.js +23 -28
- package/dist/release-pack.js +12 -3
- package/dist/server-artifact.d.ts +140 -0
- package/dist/server-artifact.js +205 -0
- package/dist/server-language-backend.d.ts +89 -0
- package/dist/server-language-backend.js +121 -0
- package/dist/static-emit.d.ts +10 -1
- package/dist/static-emit.js +140 -26
- package/package.json +12 -12
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* B0 — Delivery profile authoring normalize + CLI --profile resolve.
|
|
3
|
+
* Pure data only; expands legacy site-delivery sugar into profiles[default].
|
|
4
|
+
*/
|
|
5
|
+
export declare const DELIVERY_PROFILE_AUTHORING_SCHEMA = "vmz.delivery.authoring.v0";
|
|
6
|
+
export declare const BUILD_PROFILE_SELECTION_SCHEMA = "vmz.build.profile_selection.v0";
|
|
7
|
+
/** Browser-era assembly kinds (04 B5). */
|
|
8
|
+
export declare const ASSEMBLIES: readonly string[];
|
|
9
|
+
export declare const SERVER_RUNTIMES: readonly string[];
|
|
10
|
+
/** Official built-in aliases when not overridden in config. */
|
|
11
|
+
export declare const BUILTIN_PROFILES: Readonly<{
|
|
12
|
+
'web-client': {
|
|
13
|
+
host: string;
|
|
14
|
+
assembly: string;
|
|
15
|
+
};
|
|
16
|
+
'web-static': {
|
|
17
|
+
host: string;
|
|
18
|
+
assembly: string;
|
|
19
|
+
};
|
|
20
|
+
'web-ssr': {
|
|
21
|
+
host: string;
|
|
22
|
+
assembly: string;
|
|
23
|
+
serverRuntime: string;
|
|
24
|
+
};
|
|
25
|
+
'web-hybrid': {
|
|
26
|
+
host: string;
|
|
27
|
+
assembly: string;
|
|
28
|
+
serverRuntime: string;
|
|
29
|
+
};
|
|
30
|
+
}>;
|
|
31
|
+
export declare function pickSiteAuthoring(raw: any): {
|
|
32
|
+
artifact: string;
|
|
33
|
+
sources: any;
|
|
34
|
+
};
|
|
35
|
+
export declare function normalizeDeliveryAuthoring(raw: any): {
|
|
36
|
+
ok: boolean;
|
|
37
|
+
table: {
|
|
38
|
+
schema: string;
|
|
39
|
+
default: string;
|
|
40
|
+
profiles: {};
|
|
41
|
+
sugar: boolean;
|
|
42
|
+
};
|
|
43
|
+
diagnostics?: undefined;
|
|
44
|
+
} | {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
diagnostics: any[];
|
|
47
|
+
table?: undefined;
|
|
48
|
+
};
|
|
49
|
+
export declare function selectBuildProfile(table: any, cliProfile?: string): {
|
|
50
|
+
ok: boolean;
|
|
51
|
+
diagnostics: {
|
|
52
|
+
code: string;
|
|
53
|
+
message: string;
|
|
54
|
+
}[];
|
|
55
|
+
selection?: undefined;
|
|
56
|
+
profile?: undefined;
|
|
57
|
+
} | {
|
|
58
|
+
ok: boolean;
|
|
59
|
+
selection: {
|
|
60
|
+
schema: string;
|
|
61
|
+
profileId: any;
|
|
62
|
+
host: any;
|
|
63
|
+
assembly: any;
|
|
64
|
+
serverRuntime: any;
|
|
65
|
+
hasSiteSources: boolean;
|
|
66
|
+
authoringDigest: any;
|
|
67
|
+
fromCli: boolean;
|
|
68
|
+
};
|
|
69
|
+
profile: any;
|
|
70
|
+
diagnostics?: undefined;
|
|
71
|
+
};
|
|
72
|
+
export declare function semanticIdsForAssembly(assembly: any): string[];
|
|
73
|
+
export declare function canonicalJson(value: any): string;
|
|
74
|
+
export declare function sha256Hex(text: any): string;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* B0 — Delivery profile authoring normalize + CLI --profile resolve.
|
|
3
|
+
* Pure data only; expands legacy site-delivery sugar into profiles[default].
|
|
4
|
+
*/
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
export const DELIVERY_PROFILE_AUTHORING_SCHEMA = 'vmz.delivery.authoring.v0';
|
|
8
|
+
export const BUILD_PROFILE_SELECTION_SCHEMA = 'vmz.build.profile_selection.v0';
|
|
9
|
+
/** Browser-era assembly kinds (04 B5). */
|
|
10
|
+
export const ASSEMBLIES = Object.freeze(['local-static', 'static-cdn', 'server-host', 'cdn+server', 'rust-embedded']);
|
|
11
|
+
export const SERVER_RUNTIMES = Object.freeze(['node', 'worker', 'deno', 'bun', 'rust-host']);
|
|
12
|
+
/** Official built-in aliases when not overridden in config. */
|
|
13
|
+
export const BUILTIN_PROFILES = Object.freeze({
|
|
14
|
+
'web-client': { host: 'browser', assembly: 'local-static' },
|
|
15
|
+
'web-static': { host: 'browser', assembly: 'static-cdn' },
|
|
16
|
+
'web-ssr': { host: 'browser', assembly: 'server-host', serverRuntime: 'node' },
|
|
17
|
+
'web-hybrid': { host: 'browser', assembly: 'cdn+server', serverRuntime: 'node' },
|
|
18
|
+
});
|
|
19
|
+
function isPlainObject(v) {
|
|
20
|
+
return v != null && typeof v === 'object' && !Array.isArray(v);
|
|
21
|
+
}
|
|
22
|
+
export function pickSiteAuthoring(raw) {
|
|
23
|
+
if (!isPlainObject(raw))
|
|
24
|
+
return null;
|
|
25
|
+
if (!Array.isArray(raw.sources) || raw.sources.length < 1)
|
|
26
|
+
return null;
|
|
27
|
+
if (typeof raw.artifact !== 'string' || !String(raw.artifact).trim())
|
|
28
|
+
return null;
|
|
29
|
+
const site = {
|
|
30
|
+
artifact: String(raw.artifact),
|
|
31
|
+
sources: raw.sources,
|
|
32
|
+
};
|
|
33
|
+
for (const k of [
|
|
34
|
+
'siteId',
|
|
35
|
+
'resolution',
|
|
36
|
+
'activation',
|
|
37
|
+
'expectedCompatibility',
|
|
38
|
+
'failure',
|
|
39
|
+
'failurePolicy',
|
|
40
|
+
'update',
|
|
41
|
+
'updatePolicy',
|
|
42
|
+
'rollback',
|
|
43
|
+
'rollbackPolicy',
|
|
44
|
+
'security',
|
|
45
|
+
'securityPolicy',
|
|
46
|
+
]) {
|
|
47
|
+
if (raw[k] !== undefined)
|
|
48
|
+
site[k] = raw[k];
|
|
49
|
+
}
|
|
50
|
+
return site;
|
|
51
|
+
}
|
|
52
|
+
function normalizeProfileEntry(entry, id, diagnostics) {
|
|
53
|
+
if (!isPlainObject(entry)) {
|
|
54
|
+
diagnostics.push({ code: 'delivery.profile.invalid', message: `profiles.${id} must be an object` });
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const host = String(entry.host || 'browser');
|
|
58
|
+
if (host !== 'browser') {
|
|
59
|
+
diagnostics.push({
|
|
60
|
+
code: 'delivery.profile.host',
|
|
61
|
+
message: `profiles.${id}.host: only 'browser' is supported before Browser Production (got ${host})`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const assembly = String(entry.assembly || '').trim();
|
|
65
|
+
if (!ASSEMBLIES.includes(assembly)) {
|
|
66
|
+
diagnostics.push({
|
|
67
|
+
code: 'delivery.profile.assembly',
|
|
68
|
+
message: `profiles.${id}.assembly must be one of ${ASSEMBLIES.join('|')} (got ${assembly || '(empty)'})`,
|
|
69
|
+
});
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
let serverRuntime = null;
|
|
73
|
+
if (assembly === 'server-host' || assembly === 'cdn+server') {
|
|
74
|
+
serverRuntime = String(entry.serverRuntime || 'node');
|
|
75
|
+
if (!SERVER_RUNTIMES.includes(serverRuntime)) {
|
|
76
|
+
diagnostics.push({
|
|
77
|
+
code: 'delivery.profile.serverRuntime',
|
|
78
|
+
message: `profiles.${id}.serverRuntime must be one of ${SERVER_RUNTIMES.join('|')}`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
let sources = null;
|
|
83
|
+
if (entry.sources != null) {
|
|
84
|
+
if (isPlainObject(entry.sources) && Array.isArray(entry.sources.sources)) {
|
|
85
|
+
sources = pickSiteAuthoring(entry.sources);
|
|
86
|
+
}
|
|
87
|
+
else if (Array.isArray(entry.sources)) {
|
|
88
|
+
sources = pickSiteAuthoring({
|
|
89
|
+
artifact: entry.artifact || entry.sourcesArtifact || id,
|
|
90
|
+
sources: entry.sources,
|
|
91
|
+
resolution: entry.resolution,
|
|
92
|
+
activation: entry.activation,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
diagnostics.push({
|
|
97
|
+
code: 'delivery.profile.sources',
|
|
98
|
+
message: `profiles.${id}.sources must be defineSite({...}) or a sources array with artifact`,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (entry.sources != null && sources == null) {
|
|
102
|
+
const already = diagnostics.some((d) => String(d.message || '').includes(`profiles.${id}`));
|
|
103
|
+
if (!already) {
|
|
104
|
+
diagnostics.push({
|
|
105
|
+
code: 'delivery.profile.sources.artifact',
|
|
106
|
+
message: `profiles.${id} site sources require artifact string`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
id,
|
|
113
|
+
host: 'browser',
|
|
114
|
+
assembly,
|
|
115
|
+
serverRuntime,
|
|
116
|
+
sources,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export function normalizeDeliveryAuthoring(raw) {
|
|
120
|
+
const diagnostics = [];
|
|
121
|
+
if (raw == null) {
|
|
122
|
+
const profiles = { ...BUILTIN_PROFILES };
|
|
123
|
+
const normalized = {};
|
|
124
|
+
for (const [id, entry] of Object.entries(profiles)) {
|
|
125
|
+
const n = normalizeProfileEntry(entry, id, diagnostics);
|
|
126
|
+
if (n)
|
|
127
|
+
normalized[id] = n;
|
|
128
|
+
}
|
|
129
|
+
const table = {
|
|
130
|
+
schema: DELIVERY_PROFILE_AUTHORING_SCHEMA,
|
|
131
|
+
default: 'web-ssr',
|
|
132
|
+
profiles: normalized,
|
|
133
|
+
sugar: false,
|
|
134
|
+
};
|
|
135
|
+
table.digest = sha256Hex(canonicalJson(table));
|
|
136
|
+
return { ok: true, table };
|
|
137
|
+
}
|
|
138
|
+
if (!isPlainObject(raw)) {
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
diagnostics: [{ code: 'delivery.invalid', message: 'delivery must be a plain object' }],
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
let profileInputs = {};
|
|
145
|
+
let defaultId = '';
|
|
146
|
+
let sugar = false;
|
|
147
|
+
if (isPlainObject(raw.profiles)) {
|
|
148
|
+
defaultId = String(raw.default || '').trim();
|
|
149
|
+
profileInputs = { ...BUILTIN_PROFILES, ...raw.profiles };
|
|
150
|
+
if (!defaultId) {
|
|
151
|
+
const keys = Object.keys(raw.profiles);
|
|
152
|
+
defaultId = keys[0] || 'web-ssr';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else if (Array.isArray(raw.sources) || raw.artifact != null || raw.assembly != null) {
|
|
156
|
+
sugar = true;
|
|
157
|
+
const site = pickSiteAuthoring(raw);
|
|
158
|
+
defaultId = String(raw.default || raw.artifact || 'web-ssr').trim() || 'web-ssr';
|
|
159
|
+
const assembly = typeof raw.assembly === 'string' && ASSEMBLIES.includes(raw.assembly) ? raw.assembly : site ? 'rust-embedded' : 'server-host';
|
|
160
|
+
profileInputs = {
|
|
161
|
+
...BUILTIN_PROFILES,
|
|
162
|
+
[defaultId]: {
|
|
163
|
+
host: raw.host || 'browser',
|
|
164
|
+
assembly,
|
|
165
|
+
serverRuntime: raw.serverRuntime || 'node',
|
|
166
|
+
...(site
|
|
167
|
+
? {
|
|
168
|
+
artifact: site.artifact,
|
|
169
|
+
sources: site.sources,
|
|
170
|
+
resolution: site.resolution,
|
|
171
|
+
activation: site.activation,
|
|
172
|
+
expectedCompatibility: site.expectedCompatibility,
|
|
173
|
+
failure: site.failure,
|
|
174
|
+
failurePolicy: site.failurePolicy,
|
|
175
|
+
update: site.update,
|
|
176
|
+
updatePolicy: site.updatePolicy,
|
|
177
|
+
rollback: site.rollback,
|
|
178
|
+
rollbackPolicy: site.rollbackPolicy,
|
|
179
|
+
security: site.security,
|
|
180
|
+
securityPolicy: site.securityPolicy,
|
|
181
|
+
}
|
|
182
|
+
: {}),
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
return {
|
|
188
|
+
ok: false,
|
|
189
|
+
diagnostics: [
|
|
190
|
+
{
|
|
191
|
+
code: 'delivery.shape',
|
|
192
|
+
message: 'delivery must declare profiles{} or legacy { artifact, sources }',
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const profiles = {};
|
|
198
|
+
for (const [id, entry] of Object.entries(profileInputs)) {
|
|
199
|
+
const n = normalizeProfileEntry(entry, id, diagnostics);
|
|
200
|
+
if (n)
|
|
201
|
+
profiles[id] = n;
|
|
202
|
+
}
|
|
203
|
+
if (!profiles[defaultId]) {
|
|
204
|
+
diagnostics.push({
|
|
205
|
+
code: 'delivery.default',
|
|
206
|
+
message: `delivery.default '${defaultId}' is not a known profile`,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (diagnostics.length)
|
|
210
|
+
return { ok: false, diagnostics };
|
|
211
|
+
const table = {
|
|
212
|
+
schema: DELIVERY_PROFILE_AUTHORING_SCHEMA,
|
|
213
|
+
default: defaultId,
|
|
214
|
+
profiles,
|
|
215
|
+
sugar,
|
|
216
|
+
};
|
|
217
|
+
table.digest = sha256Hex(canonicalJson(table));
|
|
218
|
+
return { ok: true, table };
|
|
219
|
+
}
|
|
220
|
+
export function selectBuildProfile(table, cliProfile = '') {
|
|
221
|
+
const id = String(cliProfile || '').trim() || table.default;
|
|
222
|
+
const profile = table.profiles[id];
|
|
223
|
+
if (!profile) {
|
|
224
|
+
return {
|
|
225
|
+
ok: false,
|
|
226
|
+
diagnostics: [
|
|
227
|
+
{
|
|
228
|
+
code: 'delivery.profile.unknown',
|
|
229
|
+
message: `unknown build --profile ${id} (known: ${Object.keys(table.profiles).join(', ')})`,
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const selection = {
|
|
235
|
+
schema: BUILD_PROFILE_SELECTION_SCHEMA,
|
|
236
|
+
profileId: id,
|
|
237
|
+
host: profile.host,
|
|
238
|
+
assembly: profile.assembly,
|
|
239
|
+
serverRuntime: profile.serverRuntime,
|
|
240
|
+
hasSiteSources: Boolean(profile.sources),
|
|
241
|
+
authoringDigest: table.digest,
|
|
242
|
+
fromCli: Boolean(String(cliProfile || '').trim()),
|
|
243
|
+
};
|
|
244
|
+
selection.digest = sha256Hex(canonicalJson(selection));
|
|
245
|
+
return { ok: true, selection, profile };
|
|
246
|
+
}
|
|
247
|
+
export function semanticIdsForAssembly(assembly) {
|
|
248
|
+
switch (assembly) {
|
|
249
|
+
case 'static-cdn':
|
|
250
|
+
return ['static-delivery', 'asset-graph'];
|
|
251
|
+
case 'server-host':
|
|
252
|
+
return ['server-host', 'asset-graph'];
|
|
253
|
+
case 'cdn+server':
|
|
254
|
+
return ['server-host', 'static-delivery', 'asset-graph'];
|
|
255
|
+
case 'rust-embedded':
|
|
256
|
+
return ['site-fallback', 'asset-graph'];
|
|
257
|
+
case 'local-static':
|
|
258
|
+
return ['asset-graph'];
|
|
259
|
+
default:
|
|
260
|
+
return [];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
export function canonicalJson(value) {
|
|
264
|
+
return JSON.stringify(sortKeys(value));
|
|
265
|
+
}
|
|
266
|
+
function sortKeys(value) {
|
|
267
|
+
if (Array.isArray(value))
|
|
268
|
+
return value.map(sortKeys);
|
|
269
|
+
if (value && typeof value === 'object') {
|
|
270
|
+
const out = {};
|
|
271
|
+
for (const k of Object.keys(value).sort())
|
|
272
|
+
out[k] = sortKeys(value[k]);
|
|
273
|
+
return out;
|
|
274
|
+
}
|
|
275
|
+
return value;
|
|
276
|
+
}
|
|
277
|
+
export function sha256Hex(text) {
|
|
278
|
+
return crypto.createHash('sha256').update(text, 'utf8').digest('hex');
|
|
279
|
+
}
|
package/dist/dev-session.js
CHANGED
|
@@ -51,8 +51,9 @@ export function createDevSession(options) {
|
|
|
51
51
|
}
|
|
52
52
|
function emitLocales() {
|
|
53
53
|
const localeEmit = emitLocaleRuntimeModules(project, outDir);
|
|
54
|
+
// Always surface locale diagnostics (warnings included) — missing /locales must not be silent.
|
|
55
|
+
log.diagnostics(localeEmit.diagnostics ?? []);
|
|
54
56
|
if (!localeEmit.ok || localeHasErrors({ diagnostics: localeEmit.diagnostics })) {
|
|
55
|
-
log.diagnostics(localeEmit.diagnostics ?? []);
|
|
56
57
|
log.error('locale runtime emit failed');
|
|
57
58
|
return false;
|
|
58
59
|
}
|
package/dist/document-build.js
CHANGED
|
@@ -164,11 +164,12 @@ function renderStaticHtml({ title, locale, route, nav, bodyHtml, headings, desig
|
|
|
164
164
|
/** @type {string[]} */
|
|
165
165
|
const cssHrefs = [];
|
|
166
166
|
if (hostChrome) {
|
|
167
|
-
//
|
|
168
|
-
|
|
167
|
+
// Integrated documents are served with pretty directory URLs. Root
|
|
168
|
+
// absolute assets remain correct for both emitted files and rewrites.
|
|
169
|
+
cssHrefs.push('/vmz.css');
|
|
169
170
|
}
|
|
170
171
|
if (designsHref)
|
|
171
|
-
cssHrefs.push(prefix + designsHref);
|
|
172
|
+
cssHrefs.push(hostChrome ? `/${designsHref}` : prefix + designsHref);
|
|
172
173
|
const cssLink = cssHrefs.map((href) => ` <link rel="stylesheet" href="${esc(href)}" />`).join('\n') + (cssHrefs.length ? '\n' : '');
|
|
173
174
|
const navItems = nav
|
|
174
175
|
.map((n) => {
|
|
@@ -200,13 +201,17 @@ ${cssLink}</head>
|
|
|
200
201
|
<div class="site site--docs">
|
|
201
202
|
<a class="skip-link" href="#main">Skip to content</a>
|
|
202
203
|
${header}
|
|
204
|
+
<div class="doc-body">
|
|
205
|
+
<aside class="doc-sidebar">
|
|
203
206
|
${docsNav}
|
|
204
207
|
${searchShellHtml}
|
|
205
|
-
|
|
208
|
+
</aside>
|
|
209
|
+
<div class="doc-content">
|
|
206
210
|
${toc}<main id="main">
|
|
207
211
|
${bodyHtml}
|
|
208
212
|
${playgroundShellHtml}
|
|
209
213
|
</main>
|
|
214
|
+
</div>
|
|
210
215
|
</div>
|
|
211
216
|
${hostChrome.footer}
|
|
212
217
|
</div>
|
package/dist/document-enrich.js
CHANGED
|
@@ -199,6 +199,14 @@ function resolveDocHref(href, fromPageKey, locale, routeBase, pageKeySet) {
|
|
|
199
199
|
pk = normalizePageKey(pk);
|
|
200
200
|
const keys = pageKeySet.get(locale) || new Set();
|
|
201
201
|
if (!keys.has(pk)) {
|
|
202
|
+
// A directory index and a leaf page share the same normalized PageKey shape.
|
|
203
|
+
// Prefer the regular sibling resolution above, then retry relative to the
|
|
204
|
+
// PageKey itself so `guide/optimizations/index.md` keeps its directory.
|
|
205
|
+
const indexJoined = path.posix.normalize(path.posix.join(fromPageKey || '.', pathPart));
|
|
206
|
+
const indexPk = normalizePageKey(indexJoined.replace(/^\.\//, ''));
|
|
207
|
+
if (keys.has(indexPk)) {
|
|
208
|
+
return { ok: true, locale, pageKey: indexPk, anchor, anchors: [] };
|
|
209
|
+
}
|
|
202
210
|
return { ok: false, reason: `no PageKey ${pk} in ${locale}` };
|
|
203
211
|
}
|
|
204
212
|
return { ok: true, locale, pageKey: pk, anchor, anchors: [] };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rust-embedded packaging adapter: resource index + baseline closure.
|
|
3
|
+
* Packaging only — does not invent route / MIME / fallback semantics.
|
|
4
|
+
*/
|
|
5
|
+
export declare const EMBEDDED_RESOURCE_INDEX_SCHEMA = "vmz.embedded.resource_index.v0";
|
|
6
|
+
/**
|
|
7
|
+
* Walk outDir and build path → digest → relative blob path map.
|
|
8
|
+
* Copies files into `dist/_vmz/embedded-baseline/` (whole release, no file-level mix).
|
|
9
|
+
* @param {string} outDir
|
|
10
|
+
* @param {{ siteId?: string, contractDigest?: string | null }} [opts]
|
|
11
|
+
*/
|
|
12
|
+
export declare function emitEmbeddedPackaging(outDir: any, opts?: {}): {
|
|
13
|
+
index: {
|
|
14
|
+
schema: string;
|
|
15
|
+
siteId: any;
|
|
16
|
+
contractDigest: any;
|
|
17
|
+
objectCount: number;
|
|
18
|
+
objects: any[];
|
|
19
|
+
};
|
|
20
|
+
indexPath: string;
|
|
21
|
+
baselineDir: string;
|
|
22
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rust-embedded packaging adapter: resource index + baseline closure.
|
|
3
|
+
* Packaging only — does not invent route / MIME / fallback semantics.
|
|
4
|
+
*/
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
export const EMBEDDED_RESOURCE_INDEX_SCHEMA = 'vmz.embedded.resource_index.v0';
|
|
10
|
+
/** Paths that must never enter the embedded baseline closure. */
|
|
11
|
+
const SKIP_NAMES = new Set([
|
|
12
|
+
'vmz-serve-host.mjs',
|
|
13
|
+
'vmz-serve-host.js',
|
|
14
|
+
'node_modules',
|
|
15
|
+
'.git',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Walk outDir and build path → digest → relative blob path map.
|
|
19
|
+
* Copies files into `dist/_vmz/embedded-baseline/` (whole release, no file-level mix).
|
|
20
|
+
* @param {string} outDir
|
|
21
|
+
* @param {{ siteId?: string, contractDigest?: string | null }} [opts]
|
|
22
|
+
*/
|
|
23
|
+
export function emitEmbeddedPackaging(outDir, opts = {}) {
|
|
24
|
+
const vmzDir = path.join(outDir, '_vmz');
|
|
25
|
+
const baselineDir = path.join(vmzDir, 'embedded-baseline');
|
|
26
|
+
fs.mkdirSync(baselineDir, { recursive: true });
|
|
27
|
+
/** @type {Array<{ path: string, digest: string, blob: string, bytes: number }>} */
|
|
28
|
+
const objects = [];
|
|
29
|
+
const root = path.resolve(outDir);
|
|
30
|
+
walkFiles(root, (abs) => {
|
|
31
|
+
const rel = toPosix(path.relative(root, abs));
|
|
32
|
+
if (!rel || rel.startsWith('_vmz/embedded-baseline'))
|
|
33
|
+
return;
|
|
34
|
+
if (rel.startsWith('_vmz/embedded-resource-index'))
|
|
35
|
+
return;
|
|
36
|
+
const base = path.basename(abs);
|
|
37
|
+
if (SKIP_NAMES.has(base))
|
|
38
|
+
return;
|
|
39
|
+
// Keep other _vmz manifests inside baseline (contract, capability table, etc.)
|
|
40
|
+
const buf = fs.readFileSync(abs);
|
|
41
|
+
const digest = sha256Hex(buf);
|
|
42
|
+
const blobRel = `objects/${digest.slice(0, 2)}/${digest}`;
|
|
43
|
+
const blobAbs = path.join(baselineDir, blobRel);
|
|
44
|
+
fs.mkdirSync(path.dirname(blobAbs), { recursive: true });
|
|
45
|
+
if (!fs.existsSync(blobAbs))
|
|
46
|
+
fs.writeFileSync(blobAbs, buf);
|
|
47
|
+
// Also mirror tree under baseline/tree for host convenience
|
|
48
|
+
const treeAbs = path.join(baselineDir, 'tree', rel);
|
|
49
|
+
fs.mkdirSync(path.dirname(treeAbs), { recursive: true });
|
|
50
|
+
fs.copyFileSync(abs, treeAbs);
|
|
51
|
+
objects.push({ path: rel, digest, blob: blobRel, bytes: buf.length });
|
|
52
|
+
});
|
|
53
|
+
objects.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
54
|
+
const index = {
|
|
55
|
+
schema: EMBEDDED_RESOURCE_INDEX_SCHEMA,
|
|
56
|
+
siteId: opts.siteId || null,
|
|
57
|
+
contractDigest: opts.contractDigest || null,
|
|
58
|
+
objectCount: objects.length,
|
|
59
|
+
objects,
|
|
60
|
+
};
|
|
61
|
+
index.indexDigest = sha256Hex(canonicalJson({ ...index, indexDigest: undefined }));
|
|
62
|
+
const indexPath = path.join(vmzDir, 'embedded-resource-index.json');
|
|
63
|
+
fs.writeFileSync(indexPath, `${JSON.stringify(index, null, 2)}\n`, 'utf8');
|
|
64
|
+
// Optional include_bytes entry point for Rust packaging adapters
|
|
65
|
+
const rsPath = path.join(vmzDir, 'embedded_site.rs');
|
|
66
|
+
fs.writeFileSync(rsPath, `// @generated by vmz — rust-embedded packaging adapter (do not edit)
|
|
67
|
+
// Index digest: ${index.indexDigest}
|
|
68
|
+
pub const EMBEDDED_RESOURCE_INDEX: &str = include_str!("embedded-resource-index.json");
|
|
69
|
+
`, 'utf8');
|
|
70
|
+
return { index, indexPath, baselineDir };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* @param {string} dir
|
|
74
|
+
* @param {(abs: string) => void} onFile
|
|
75
|
+
*/
|
|
76
|
+
function walkFiles(dir, onFile) {
|
|
77
|
+
if (!fs.existsSync(dir))
|
|
78
|
+
return;
|
|
79
|
+
for (const name of fs.readdirSync(dir)) {
|
|
80
|
+
if (SKIP_NAMES.has(name))
|
|
81
|
+
continue;
|
|
82
|
+
const abs = path.join(dir, name);
|
|
83
|
+
const st = fs.statSync(abs);
|
|
84
|
+
if (st.isDirectory()) {
|
|
85
|
+
if (name === 'embedded-baseline' && path.basename(path.dirname(abs)) === '_vmz')
|
|
86
|
+
continue;
|
|
87
|
+
walkFiles(abs, onFile);
|
|
88
|
+
}
|
|
89
|
+
else if (st.isFile()) {
|
|
90
|
+
onFile(abs);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function toPosix(p) {
|
|
95
|
+
return p.split(path.sep).join('/');
|
|
96
|
+
}
|
|
97
|
+
function sha256Hex(data) {
|
|
98
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
99
|
+
}
|
|
100
|
+
function canonicalJson(value) {
|
|
101
|
+
return JSON.stringify(sortKeys(value));
|
|
102
|
+
}
|
|
103
|
+
function sortKeys(value) {
|
|
104
|
+
if (Array.isArray(value))
|
|
105
|
+
return value.map(sortKeys);
|
|
106
|
+
if (value && typeof value === 'object') {
|
|
107
|
+
const out = {};
|
|
108
|
+
for (const k of Object.keys(value).sort())
|
|
109
|
+
out[k] = sortKeys(value[k]);
|
|
110
|
+
return out;
|
|
111
|
+
}
|
|
112
|
+
return value;
|
|
113
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -151,10 +151,17 @@ export { STATIC_DELIVERY_MANIFEST_SCHEMA, emitWebStatic, } from './static-emit.j
|
|
|
151
151
|
export { CONTENT_ADDRESSED_ASSETS_SCHEMA, emitContentAddressedAssets, resolveAssetByDigest, assertSharedAssetPath, contentAddressedAssetsDigest, } from './content-addressed-assets.js';
|
|
152
152
|
export { CDN_POLICY_MANIFEST_SCHEMA, CDN_ADAPTER_PROJECTION_SCHEMA, CACHE_HTML, CACHE_ASSET_IMMUTABLE, CACHE_META, buildCdnPolicyManifest, emitCdnPolicy, projectCdnAdapter, createLocalStaticHandler, listenLocalStaticHost, matchGlob, } from './cdn-policy.js';
|
|
153
153
|
export { SITE_DELIVERY_CONTRACT_SCHEMA, SITE_DELIVERY_RESOLUTION_SCHEMA, defineSite, normalizeSiteDelivery, normalizeSourceProbe, resolveSiteRelease, probeReleaseDirectory, emitSiteDelivery, } from './site-delivery.js';
|
|
154
|
+
export { EMBEDDED_RESOURCE_INDEX_SCHEMA, emitEmbeddedPackaging, } from './embedded-packaging.js';
|
|
155
|
+
export { SERVER_LANG_IDS, SERVER_LANG_ALIASES, SERVER_LANGUAGE_BACKENDS, resolveServerLanguage, assertLangRuntimePair, } from './server-language-backend.js';
|
|
156
|
+
export { DELIVERY_PROFILE_AUTHORING_SCHEMA, BUILD_PROFILE_SELECTION_SCHEMA, ASSEMBLIES, SERVER_RUNTIMES, BUILTIN_PROFILES, pickSiteAuthoring, normalizeDeliveryAuthoring, selectBuildProfile, semanticIdsForAssembly, } from './delivery-profile.js';
|
|
157
|
+
export { PACK_MANIFEST_SCHEMA, packFromDeploymentIr, ensureRuntimeCompanions } from './pack.js';
|
|
158
|
+
export { SERVER_ARTIFACT_SCHEMA, HTTP_CONTRACT_SCHEMA, SERVER_RUNTIME_ADAPTER_SCHEMA, emitServerArtifact, projectServerRuntimeAdapter, } from './server-artifact.js';
|
|
159
|
+
export { BUILD_PROOF_SCHEMA, ASSEMBLE_MANIFEST_SCHEMA, assembleDelivery, emitBuildProof, } from './build-assemble.js';
|
|
154
160
|
export { PRODUCTION_SCENARIO_PACK_SCHEMA, PRODUCTION_CI_PROFILE_SCHEMA, PRODUCTION_TEST_REPORT_SCHEMA, browserProductionScenarioPack, browserProductionCiProfile, normalizeScenarioPack, normalizeCiProfile, scenarioPackDigest, ciProfileDigest, buildProductionTestReport, productionTestReportDigest, emitProductionTestArtifacts, assertNoForbiddenRunners, } from './production-test-pack.js';
|
|
155
161
|
export { PRODUCTION_OBSERVABILITY_SCHEMA, PRODUCTION_TRACE_SCHEMA, REQUIRED_TRACE_FACETS, browserProductionObservability, normalizeObservability, redactSensitive, validateProductionTrace, buildCoveringProductionTrace, checkProductionBudgets, checkCapabilityClosure, applySecurityHeadersToCdnPolicy, measureDistBudgets, emitProductionObservability, observabilityDigest, } from './production-observability.js';
|
|
156
162
|
export { buildApplicationContext, buildFormatterContext, checkLocaleRuntime, checkSsrClientParity, createLocaleSession, formatMessageTemplate, formatterContextDigest, negotiateLocale, resolveMessageVariant, validateFormatterContext, } from './locale-runtime.js';
|
|
157
|
-
export { absoluteUrl, assertLocaleCacheKey, buildLocalePageMeta, buildLocaleRouteRealizationTable, checkLocaleRouter, commitLocaleRouteMetaTransition, localeAwareCacheKey, parseLocaleFromPath, planLocalePathNavigation, realizeRoutePath, resolveLinkHref, } from './locale-router.js';
|
|
163
|
+
export { absoluteUrl, assertLocaleCacheKey, buildLocalePageMeta, buildLocaleRouteRealizationTable, checkLocaleRouter, commitLocaleRouteMetaTransition, localeAwareCacheKey, localizeBodyLinks, localizeSameAppHref, parseLocaleFromPath, planLocalePathNavigation, realizeRoutePath, resolveLinkHref, } from './locale-router.js';
|
|
164
|
+
export { LOCALE_ROUTE_REALIZATION_ARTIFACT_SCHEMA, emitLocaleRouteRealization, } from './locale-route-emit.js';
|
|
158
165
|
export { assertHostMessageInvariant, assertServerErrorEnvelope, assertServerFormatContext, buildLocaleDeliveryResolution, checkLocaleDelivery, fallbackDigest, messageCatalogHash, proveMiniPackageMessages, validateNativeLocalePack, } from './locale-delivery.js';
|
|
159
166
|
export { checkLocaleConformance, diffLocaleCatalogs, explainLocaleMessage, extractHardcodedText, pseudoLocalizeCatalog, } from './locale-tooling.js';
|
|
160
167
|
export { applyPlugins, contentHash, defineConfig, definePlugin, loadVmzConfig, } from './plugin-host.js';
|
package/dist/index.js
CHANGED
|
@@ -333,10 +333,17 @@ export { STATIC_DELIVERY_MANIFEST_SCHEMA, emitWebStatic, } from './static-emit.j
|
|
|
333
333
|
export { CONTENT_ADDRESSED_ASSETS_SCHEMA, emitContentAddressedAssets, resolveAssetByDigest, assertSharedAssetPath, contentAddressedAssetsDigest, } from './content-addressed-assets.js';
|
|
334
334
|
export { CDN_POLICY_MANIFEST_SCHEMA, CDN_ADAPTER_PROJECTION_SCHEMA, CACHE_HTML, CACHE_ASSET_IMMUTABLE, CACHE_META, buildCdnPolicyManifest, emitCdnPolicy, projectCdnAdapter, createLocalStaticHandler, listenLocalStaticHost, matchGlob, } from './cdn-policy.js';
|
|
335
335
|
export { SITE_DELIVERY_CONTRACT_SCHEMA, SITE_DELIVERY_RESOLUTION_SCHEMA, defineSite, normalizeSiteDelivery, normalizeSourceProbe, resolveSiteRelease, probeReleaseDirectory, emitSiteDelivery, } from './site-delivery.js';
|
|
336
|
+
export { EMBEDDED_RESOURCE_INDEX_SCHEMA, emitEmbeddedPackaging, } from './embedded-packaging.js';
|
|
337
|
+
export { SERVER_LANG_IDS, SERVER_LANG_ALIASES, SERVER_LANGUAGE_BACKENDS, resolveServerLanguage, assertLangRuntimePair, } from './server-language-backend.js';
|
|
338
|
+
export { DELIVERY_PROFILE_AUTHORING_SCHEMA, BUILD_PROFILE_SELECTION_SCHEMA, ASSEMBLIES, SERVER_RUNTIMES, BUILTIN_PROFILES, pickSiteAuthoring, normalizeDeliveryAuthoring, selectBuildProfile, semanticIdsForAssembly, } from './delivery-profile.js';
|
|
339
|
+
export { PACK_MANIFEST_SCHEMA, packFromDeploymentIr, ensureRuntimeCompanions } from './pack.js';
|
|
340
|
+
export { SERVER_ARTIFACT_SCHEMA, HTTP_CONTRACT_SCHEMA, SERVER_RUNTIME_ADAPTER_SCHEMA, emitServerArtifact, projectServerRuntimeAdapter, } from './server-artifact.js';
|
|
341
|
+
export { BUILD_PROOF_SCHEMA, ASSEMBLE_MANIFEST_SCHEMA, assembleDelivery, emitBuildProof, } from './build-assemble.js';
|
|
336
342
|
export { PRODUCTION_SCENARIO_PACK_SCHEMA, PRODUCTION_CI_PROFILE_SCHEMA, PRODUCTION_TEST_REPORT_SCHEMA, browserProductionScenarioPack, browserProductionCiProfile, normalizeScenarioPack, normalizeCiProfile, scenarioPackDigest, ciProfileDigest, buildProductionTestReport, productionTestReportDigest, emitProductionTestArtifacts, assertNoForbiddenRunners, } from './production-test-pack.js';
|
|
337
343
|
export { PRODUCTION_OBSERVABILITY_SCHEMA, PRODUCTION_TRACE_SCHEMA, REQUIRED_TRACE_FACETS, browserProductionObservability, normalizeObservability, redactSensitive, validateProductionTrace, buildCoveringProductionTrace, checkProductionBudgets, checkCapabilityClosure, applySecurityHeadersToCdnPolicy, measureDistBudgets, emitProductionObservability, observabilityDigest, } from './production-observability.js';
|
|
338
344
|
export { buildApplicationContext, buildFormatterContext, checkLocaleRuntime, checkSsrClientParity, createLocaleSession, formatMessageTemplate, formatterContextDigest, negotiateLocale, resolveMessageVariant, validateFormatterContext, } from './locale-runtime.js';
|
|
339
|
-
export { absoluteUrl, assertLocaleCacheKey, buildLocalePageMeta, buildLocaleRouteRealizationTable, checkLocaleRouter, commitLocaleRouteMetaTransition, localeAwareCacheKey, parseLocaleFromPath, planLocalePathNavigation, realizeRoutePath, resolveLinkHref, } from './locale-router.js';
|
|
345
|
+
export { absoluteUrl, assertLocaleCacheKey, buildLocalePageMeta, buildLocaleRouteRealizationTable, checkLocaleRouter, commitLocaleRouteMetaTransition, localeAwareCacheKey, localizeBodyLinks, localizeSameAppHref, parseLocaleFromPath, planLocalePathNavigation, realizeRoutePath, resolveLinkHref, } from './locale-router.js';
|
|
346
|
+
export { LOCALE_ROUTE_REALIZATION_ARTIFACT_SCHEMA, emitLocaleRouteRealization, } from './locale-route-emit.js';
|
|
340
347
|
export { assertHostMessageInvariant, assertServerErrorEnvelope, assertServerFormatContext, buildLocaleDeliveryResolution, checkLocaleDelivery, fallbackDigest, messageCatalogHash, proveMiniPackageMessages, validateNativeLocalePack, } from './locale-delivery.js';
|
|
341
348
|
export { checkLocaleConformance, diffLocaleCatalogs, explainLocaleMessage, extractHardcodedText, pseudoLocalizeCatalog, } from './locale-tooling.js';
|
|
342
349
|
export { applyPlugins, contentHash, defineConfig, definePlugin, loadVmzConfig, } from './plugin-host.js';
|
package/dist/locale-check.js
CHANGED
|
@@ -250,10 +250,12 @@ export function checkLocales(opts) {
|
|
|
250
250
|
const manifestPathJson = path.join(localesRoot, 'locales.json');
|
|
251
251
|
const manifestPath = fs.existsSync(manifestPathJson5) ? manifestPathJson5 : fs.existsSync(manifestPathJson) ? manifestPathJson : null;
|
|
252
252
|
if (!fs.existsSync(localesRoot) || !manifestPath) {
|
|
253
|
+
// Discipline nudge: i18n is first-class — missing policy is never silent.
|
|
254
|
+
// Soft for now (warning); production profiles may elevate to error later.
|
|
253
255
|
diagnostics.push({
|
|
254
256
|
code: DIAG_MANIFEST_MISSING,
|
|
255
|
-
severity: '
|
|
256
|
-
message: 'locales/locales.json5 missing
|
|
257
|
+
severity: 'warning',
|
|
258
|
+
message: 'locales/locales.json5 missing — declare LocaleId policy under /locales (native i18n, not an afterthought)',
|
|
257
259
|
path: 'locales/locales.json5',
|
|
258
260
|
});
|
|
259
261
|
return emptyReport(projectRoot, diagnostics);
|
|
@@ -586,9 +588,10 @@ function paramSignature(params) {
|
|
|
586
588
|
.join(',');
|
|
587
589
|
}
|
|
588
590
|
function emptyReport(projectRoot, diagnostics) {
|
|
591
|
+
const hasErrors = (diagnostics || []).some((d) => d.severity === 'error');
|
|
589
592
|
return {
|
|
590
593
|
schema: LOCALE_CHECK_SCHEMA,
|
|
591
|
-
status: 'failed',
|
|
594
|
+
status: hasErrors ? 'failed' : 'ready',
|
|
592
595
|
root: projectRoot,
|
|
593
596
|
localesRoot: 'locales',
|
|
594
597
|
manifest: null,
|
|
@@ -706,15 +709,15 @@ export function emitLocaleTypedModules(report, outDir) {
|
|
|
706
709
|
* @returns {{ ok: boolean, written: string[], diagnostics: any[] }}
|
|
707
710
|
*/
|
|
708
711
|
export function emitLocaleRuntimeModules(projectRoot, distDir) {
|
|
709
|
-
const localesRoot = path.join(projectRoot, 'locales');
|
|
710
|
-
if (!fs.existsSync(localesRoot)) {
|
|
711
|
-
return { ok: true, written: [], diagnostics: [] };
|
|
712
|
-
}
|
|
713
712
|
const report = checkLocales({ projectRoot, checkUnused: false });
|
|
714
713
|
if (localeHasErrors(report)) {
|
|
715
714
|
return { ok: false, written: [], diagnostics: report.diagnostics || [] };
|
|
716
715
|
}
|
|
717
|
-
|
|
716
|
+
// Missing locales.json5 is warning-only for now — surface diagnostics, skip emit.
|
|
717
|
+
if (!report.manifest) {
|
|
718
|
+
return { ok: true, written: [], diagnostics: report.diagnostics || [] };
|
|
719
|
+
}
|
|
720
|
+
const defaultLocale = report.manifest.defaultLocale || 'zh-hans';
|
|
718
721
|
const byId = new Map((report.messageCatalog?.messages || []).map((m) => [m.messageId, m]));
|
|
719
722
|
/** @type {string[]} */
|
|
720
723
|
const written = [];
|
package/dist/locale-cmd.js
CHANGED
|
@@ -117,8 +117,8 @@ function cmdLocaleList(args) {
|
|
|
117
117
|
const projectRoot = resolveProject(args);
|
|
118
118
|
const report = checkLocales({ projectRoot, checkUnused: false });
|
|
119
119
|
if (!report.manifest) {
|
|
120
|
-
|
|
121
|
-
return 1;
|
|
120
|
+
console.warn('vmz warn vmz::locale::manifest_missing: locales/locales.json5 missing');
|
|
121
|
+
return localeHasErrors(report) ? 1 : 0;
|
|
122
122
|
}
|
|
123
123
|
for (const loc of report.manifest.locales) {
|
|
124
124
|
const mark = loc.id === report.manifest.defaultLocale ? ' (default)' : '';
|