@vmz/vmz 0.0.2 → 0.0.4
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/README.md +19 -13
- package/dist/application-cmd.d.ts +1 -2
- package/dist/application-cmd.js +9 -10
- package/dist/bundler-adapter.d.ts +2 -3
- package/dist/bundler-adapter.js +2 -3
- package/dist/cdn-policy.d.ts +178 -0
- package/dist/cdn-policy.js +344 -0
- package/dist/cli.d.ts +10 -2
- package/dist/cli.js +179 -16
- package/dist/content-addressed-assets.d.ts +69 -0
- package/dist/content-addressed-assets.js +206 -0
- package/dist/dev-session.d.ts +2 -2
- package/dist/dev-session.js +51 -16
- package/dist/document-build.js +1 -2
- package/dist/document-check.d.ts +1 -1
- package/dist/document-check.js +4 -4
- package/dist/document-cmd.d.ts +1 -2
- package/dist/document-cmd.js +2 -3
- package/dist/document-designs.js +31 -3
- package/dist/document-enrich.js +2 -3
- package/dist/document-evidence.d.ts +4 -4
- package/dist/document-evidence.js +20 -12
- package/dist/document-integrate.d.ts +0 -1
- package/dist/document-integrate.js +0 -1
- package/dist/document-interactive.d.ts +11 -11
- package/dist/document-interactive.js +12 -13
- package/dist/document-locale.d.ts +1 -1
- package/dist/document-locale.js +1 -1
- package/dist/document-markdown.d.ts +1 -2
- package/dist/document-markdown.js +13 -7
- package/dist/document-scan.d.ts +4 -4
- package/dist/document-scan.js +4 -4
- package/dist/document-schema.d.ts +28 -29
- package/dist/document-schema.js +28 -29
- package/dist/explain-cmd.js +3 -3
- package/dist/index.d.ts +349 -789
- package/dist/index.js +109 -85
- package/dist/invocation.d.ts +68 -0
- package/dist/invocation.js +169 -0
- package/dist/locale-check.d.ts +19 -3
- package/dist/locale-check.js +130 -6
- package/dist/locale-cmd.js +6 -7
- package/dist/locale-delivery.d.ts +38 -38
- package/dist/locale-delivery.js +39 -40
- package/dist/locale-router.d.ts +39 -40
- package/dist/locale-router.js +39 -40
- package/dist/locale-runtime.d.ts +39 -39
- package/dist/locale-runtime.js +44 -45
- package/dist/locale-schema.d.ts +1 -2
- package/dist/locale-schema.js +1 -2
- package/dist/locale-tooling.d.ts +13 -13
- package/dist/locale-tooling.js +14 -15
- package/dist/log.d.ts +1 -1
- package/dist/log.js +1 -1
- package/dist/packages.d.ts +1 -2
- package/dist/packages.js +1 -2
- package/dist/plugin-host.d.ts +11 -3
- package/dist/plugin-host.js +21 -5
- package/dist/port.d.ts +10 -0
- package/dist/port.js +46 -0
- package/dist/production-observability.d.ts +286 -0
- package/dist/production-observability.js +469 -0
- package/dist/production-test-pack.d.ts +158 -0
- package/dist/production-test-pack.js +452 -0
- package/dist/refactor-cmd.d.ts +1 -1
- package/dist/refactor-cmd.js +6 -6
- package/dist/release-cmd.d.ts +8 -0
- package/dist/release-cmd.js +126 -0
- package/dist/release-pack.d.ts +96 -0
- package/dist/release-pack.js +337 -0
- package/dist/resolve-native-cli.d.ts +14 -0
- package/dist/resolve-native-cli.js +84 -0
- package/dist/resolve.d.ts +1 -2
- package/dist/resolve.js +1 -2
- package/dist/site-delivery.d.ts +134 -0
- package/dist/site-delivery.js +345 -0
- package/dist/static-emit.d.ts +136 -0
- package/dist/static-emit.js +463 -0
- package/dist/test-cmd.d.ts +2 -2
- package/dist/test-cmd.js +37 -17
- package/dist/watch-diff.d.ts +1 -1
- package/dist/watch-diff.js +1 -1
- package/package.json +32 -17
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A3-site: SiteDeliveryContract — embedded | filesystem | remote selection + release fallback.
|
|
3
|
+
* Authoring via defineConfig({ delivery }) / defineSite(...); pure data only.
|
|
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 SITE_DELIVERY_CONTRACT_SCHEMA = 'vmz.site.delivery_contract.v0';
|
|
10
|
+
export const SITE_DELIVERY_RESOLUTION_SCHEMA = 'vmz.site.delivery_resolution.v0';
|
|
11
|
+
/**
|
|
12
|
+
* Pure-data helper for `defineConfig({ delivery: defineSite(...) })`.
|
|
13
|
+
* Not a second config entry — CLI never auto-discovers `vmz.site.ts`.
|
|
14
|
+
* @param {Record<string, unknown>} delivery
|
|
15
|
+
*/
|
|
16
|
+
export function defineSite(delivery) {
|
|
17
|
+
return delivery;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Normalize authoring delivery → frozen SiteDeliveryContract.
|
|
21
|
+
* @param {unknown} raw
|
|
22
|
+
* @param {{ siteId?: string, projectRoot?: string }} [opts]
|
|
23
|
+
* @returns {{ ok: true, contract: Record<string, any> } | { ok: false, diagnostics: Array<{ code: string, message: string }> }}
|
|
24
|
+
*/
|
|
25
|
+
export function normalizeSiteDelivery(raw, opts = {}) {
|
|
26
|
+
/** @type {Array<{ code: string, message: string }>} */
|
|
27
|
+
const diagnostics = [];
|
|
28
|
+
if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
diagnostics: [{ code: 'site.delivery.invalid', message: 'delivery must be a plain object' }],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const d = /** @type {Record<string, any>} */ (raw);
|
|
35
|
+
if (typeof d.artifact !== 'string' || !d.artifact.trim()) {
|
|
36
|
+
diagnostics.push({ code: 'site.delivery.artifact', message: 'delivery.artifact is required' });
|
|
37
|
+
}
|
|
38
|
+
if (!Array.isArray(d.sources) || d.sources.length < 1) {
|
|
39
|
+
diagnostics.push({ code: 'site.delivery.sources', message: 'delivery.sources must be a non-empty array' });
|
|
40
|
+
}
|
|
41
|
+
const sources = [];
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
for (const [i, s] of (d.sources || []).entries()) {
|
|
44
|
+
if (!s || typeof s !== 'object') {
|
|
45
|
+
diagnostics.push({ code: 'site.delivery.source', message: `sources[${i}] must be an object` });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const id = String(s.id || '').trim();
|
|
49
|
+
const kind = String(s.kind || '').trim();
|
|
50
|
+
if (!id) {
|
|
51
|
+
diagnostics.push({ code: 'site.delivery.sourceId', message: `sources[${i}].id is required` });
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (seen.has(id)) {
|
|
55
|
+
diagnostics.push({ code: 'site.delivery.sourceId.dup', message: `duplicate source id ${id}` });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
seen.add(id);
|
|
59
|
+
if (!['embedded', 'filesystem', 'remote'].includes(kind)) {
|
|
60
|
+
diagnostics.push({
|
|
61
|
+
code: 'site.delivery.kind',
|
|
62
|
+
message: `sources[${i}].kind must be embedded|filesystem|remote`,
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (typeof s.directory === 'function' || typeof s.baseUrl === 'function') {
|
|
67
|
+
diagnostics.push({
|
|
68
|
+
code: 'site.delivery.executable',
|
|
69
|
+
message: `sources[${i}] must be pure data (no functions)`,
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (kind === 'filesystem' && typeof s.directory !== 'string') {
|
|
74
|
+
diagnostics.push({
|
|
75
|
+
code: 'site.delivery.filesystem',
|
|
76
|
+
message: `sources[${i}] filesystem requires directory string`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (kind === 'remote' && typeof s.baseUrl !== 'string') {
|
|
80
|
+
diagnostics.push({
|
|
81
|
+
code: 'site.delivery.remote',
|
|
82
|
+
message: `sources[${i}] remote requires baseUrl string`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (kind === 'embedded' && s.artifact == null && d.artifact == null) {
|
|
86
|
+
diagnostics.push({
|
|
87
|
+
code: 'site.delivery.embedded',
|
|
88
|
+
message: `sources[${i}] embedded requires artifact id`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
sources.push({
|
|
92
|
+
sourceId: id,
|
|
93
|
+
kind,
|
|
94
|
+
priority: typeof s.priority === 'number' ? s.priority : i,
|
|
95
|
+
trust: s.trust || 'signed-release',
|
|
96
|
+
directory: kind === 'filesystem' ? String(s.directory) : null,
|
|
97
|
+
baseUrl: kind === 'remote' ? String(s.baseUrl).replace(/\/$/, '') : null,
|
|
98
|
+
timeoutMs: kind === 'remote' ? Number(s.timeoutMs || 1500) : null,
|
|
99
|
+
artifact: s.artifact != null ? String(s.artifact) : kind === 'embedded' ? String(d.artifact) : null,
|
|
100
|
+
integrity: s.integrity || null,
|
|
101
|
+
signaturePolicy: s.signaturePolicy || s.trust || 'signed-release',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const resolution = d.resolution && typeof d.resolution === 'object' ? d.resolution : {};
|
|
105
|
+
const mode = String(resolution.mode || 'release');
|
|
106
|
+
if (mode !== 'release') {
|
|
107
|
+
diagnostics.push({
|
|
108
|
+
code: 'site.delivery.resolution.mode',
|
|
109
|
+
message: `resolution.mode must be 'release' (got ${mode})`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
let fallback = Array.isArray(resolution.fallback) ? resolution.fallback.map(String) : sources.map((s) => s.sourceId);
|
|
113
|
+
for (const id of fallback) {
|
|
114
|
+
if (!seen.has(id)) {
|
|
115
|
+
diagnostics.push({
|
|
116
|
+
code: 'site.delivery.fallback.unknown',
|
|
117
|
+
message: `resolution.fallback references unknown source ${id}`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Preserve author order — do not reorder by discovery/speed.
|
|
122
|
+
const activation = String(d.activation || 'atomic');
|
|
123
|
+
if (activation !== 'atomic') {
|
|
124
|
+
diagnostics.push({
|
|
125
|
+
code: 'site.delivery.activation',
|
|
126
|
+
message: `activation must be 'atomic' in v0`,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (diagnostics.length)
|
|
130
|
+
return { ok: false, diagnostics };
|
|
131
|
+
const contractBody = {
|
|
132
|
+
schema: SITE_DELIVERY_CONTRACT_SCHEMA,
|
|
133
|
+
schemaVersion: '0',
|
|
134
|
+
siteId: opts.siteId || d.siteId || d.artifact,
|
|
135
|
+
artifact: String(d.artifact),
|
|
136
|
+
expectedCompatibility: d.expectedCompatibility || {
|
|
137
|
+
runtime: 'vmz',
|
|
138
|
+
deliveryProfiles: ['web-static', 'filesystem'],
|
|
139
|
+
},
|
|
140
|
+
sources,
|
|
141
|
+
resolutionPolicy: {
|
|
142
|
+
mode: 'release',
|
|
143
|
+
fallback,
|
|
144
|
+
fileLevelMix: false,
|
|
145
|
+
},
|
|
146
|
+
failurePolicy: d.failure || d.failurePolicy || { onAllSourcesFailed: 'embedded-or-fail' },
|
|
147
|
+
updatePolicy: d.update || d.updatePolicy || { backgroundRemote: true },
|
|
148
|
+
rollbackPolicy: d.rollback || d.rollbackPolicy || { retainPrevious: true },
|
|
149
|
+
securityPolicy: d.security || d.securityPolicy || { requireSignature: true, forbidSecretsInContract: true },
|
|
150
|
+
activation: 'atomic',
|
|
151
|
+
};
|
|
152
|
+
contractBody.contractDigest = sha256Hex(canonicalJson(contractBody));
|
|
153
|
+
return { ok: true, contract: contractBody };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Probe one physical source for release-level readiness (not per-URL).
|
|
157
|
+
* @param {{
|
|
158
|
+
* available?: boolean,
|
|
159
|
+
* artifactDigest?: string | null,
|
|
160
|
+
* integrityOk?: boolean,
|
|
161
|
+
* signatureOk?: boolean,
|
|
162
|
+
* objectClosureOk?: boolean,
|
|
163
|
+
* mixedDigestObjects?: boolean,
|
|
164
|
+
* error?: string | null,
|
|
165
|
+
* }} [probe]
|
|
166
|
+
*/
|
|
167
|
+
export function normalizeSourceProbe(probe = {}) {
|
|
168
|
+
return {
|
|
169
|
+
available: probe.available !== false,
|
|
170
|
+
artifactDigest: probe.artifactDigest ?? null,
|
|
171
|
+
integrityOk: probe.integrityOk !== false,
|
|
172
|
+
signatureOk: probe.signatureOk !== false,
|
|
173
|
+
objectClosureOk: probe.objectClosureOk !== false,
|
|
174
|
+
mixedDigestObjects: Boolean(probe.mixedDigestObjects),
|
|
175
|
+
error: probe.error || null,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Resolve one complete release per SiteDeliveryContract (no file-level mix).
|
|
180
|
+
* @param {Record<string, any>} contract
|
|
181
|
+
* @param {Record<string, ReturnType<typeof normalizeSourceProbe>>} probes by sourceId
|
|
182
|
+
*/
|
|
183
|
+
export function resolveSiteRelease(contract, probes = {}) {
|
|
184
|
+
const attempted = [];
|
|
185
|
+
const fallback = contract.resolutionPolicy?.fallback || contract.sources.map((s) => s.sourceId);
|
|
186
|
+
for (const sourceId of fallback) {
|
|
187
|
+
const source = (contract.sources || []).find((s) => s.sourceId === sourceId);
|
|
188
|
+
if (!source) {
|
|
189
|
+
attempted.push({ sourceId, result: 'skip', reason: 'unknown-source' });
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const probe = normalizeSourceProbe(probes[sourceId]);
|
|
193
|
+
if (!probe.available) {
|
|
194
|
+
attempted.push({ sourceId, result: 'reject', reason: probe.error || 'unavailable' });
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
if (probe.mixedDigestObjects) {
|
|
198
|
+
attempted.push({
|
|
199
|
+
sourceId,
|
|
200
|
+
result: 'reject',
|
|
201
|
+
reason: 'file-level-mix-forbidden',
|
|
202
|
+
});
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (!probe.objectClosureOk) {
|
|
206
|
+
attempted.push({ sourceId, result: 'reject', reason: 'object-closure-incomplete' });
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (contract.securityPolicy?.requireSignature !== false && !probe.signatureOk) {
|
|
210
|
+
attempted.push({ sourceId, result: 'reject', reason: 'signature-failed' });
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (!probe.integrityOk) {
|
|
214
|
+
attempted.push({ sourceId, result: 'reject', reason: 'integrity-failed' });
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (!probe.artifactDigest) {
|
|
218
|
+
attempted.push({ sourceId, result: 'reject', reason: 'missing-artifact-digest' });
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
attempted.push({ sourceId, result: 'accept', reason: null });
|
|
222
|
+
const resolution = {
|
|
223
|
+
schema: SITE_DELIVERY_RESOLUTION_SCHEMA,
|
|
224
|
+
status: 'activated',
|
|
225
|
+
selectedSourceId: sourceId,
|
|
226
|
+
selectedKind: source.kind,
|
|
227
|
+
selectedDigest: probe.artifactDigest,
|
|
228
|
+
fallbackReason: attempted.some((a) => a.result === 'reject')
|
|
229
|
+
? attempted
|
|
230
|
+
.filter((a) => a.result === 'reject')
|
|
231
|
+
.map((a) => `${a.sourceId}:${a.reason}`)
|
|
232
|
+
.join(';')
|
|
233
|
+
: null,
|
|
234
|
+
attempted,
|
|
235
|
+
fileLevelMix: false,
|
|
236
|
+
activation: 'atomic',
|
|
237
|
+
contractDigest: contract.contractDigest,
|
|
238
|
+
};
|
|
239
|
+
resolution.resolutionDigest = sha256Hex(canonicalJson(resolution));
|
|
240
|
+
return resolution;
|
|
241
|
+
}
|
|
242
|
+
return {
|
|
243
|
+
schema: SITE_DELIVERY_RESOLUTION_SCHEMA,
|
|
244
|
+
status: 'failed',
|
|
245
|
+
selectedSourceId: null,
|
|
246
|
+
selectedKind: null,
|
|
247
|
+
selectedDigest: null,
|
|
248
|
+
fallbackReason: 'all-sources-rejected',
|
|
249
|
+
attempted,
|
|
250
|
+
fileLevelMix: false,
|
|
251
|
+
activation: 'atomic',
|
|
252
|
+
contractDigest: contract.contractDigest,
|
|
253
|
+
resolutionDigest: null,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Read a packed release directory probe (expects _vmz/release-envelope.json + object closure).
|
|
258
|
+
* @param {string} releaseDir absolute path to a release snapshot (contains dist/ or is dist/)
|
|
259
|
+
*/
|
|
260
|
+
export function probeReleaseDirectory(releaseDir) {
|
|
261
|
+
const root = path.resolve(releaseDir);
|
|
262
|
+
const dist = fs.existsSync(path.join(root, 'dist')) ? path.join(root, 'dist') : root;
|
|
263
|
+
const envelopePath = path.join(dist, '_vmz', 'release-envelope.json');
|
|
264
|
+
if (!fs.existsSync(envelopePath)) {
|
|
265
|
+
return normalizeSourceProbe({
|
|
266
|
+
available: false,
|
|
267
|
+
error: 'missing-release-envelope',
|
|
268
|
+
objectClosureOk: false,
|
|
269
|
+
signatureOk: false,
|
|
270
|
+
integrityOk: false,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
let envelope;
|
|
274
|
+
try {
|
|
275
|
+
envelope = JSON.parse(fs.readFileSync(envelopePath, 'utf8'));
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
return normalizeSourceProbe({
|
|
279
|
+
available: false,
|
|
280
|
+
error: 'invalid-release-envelope',
|
|
281
|
+
objectClosureOk: false,
|
|
282
|
+
signatureOk: false,
|
|
283
|
+
integrityOk: false,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
const digest = envelope.artifactDigest || null;
|
|
287
|
+
const required = ['index.html', '_vmz/release-envelope.json'];
|
|
288
|
+
let closureOk = true;
|
|
289
|
+
for (const rel of required) {
|
|
290
|
+
if (!fs.existsSync(path.join(dist, rel))) {
|
|
291
|
+
closureOk = false;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Detect naive file-level mix: CURRENT HTML digest stamp mismatch with envelope (test hook).
|
|
296
|
+
const mixMarker = path.join(dist, '_vmz', 'MIXED_DIGEST');
|
|
297
|
+
const mixed = fs.existsSync(mixMarker);
|
|
298
|
+
return normalizeSourceProbe({
|
|
299
|
+
available: true,
|
|
300
|
+
artifactDigest: digest,
|
|
301
|
+
integrityOk: Boolean(digest) && !mixed,
|
|
302
|
+
signatureOk: envelope.signatureOk !== false,
|
|
303
|
+
objectClosureOk: closureOk && !mixed,
|
|
304
|
+
mixedDigestObjects: mixed,
|
|
305
|
+
error: mixed ? 'mixed-digest' : null,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Emit normalized contract (+ optional resolution) under dist/_vmz.
|
|
310
|
+
* @param {string} outDir
|
|
311
|
+
* @param {unknown} deliveryRaw
|
|
312
|
+
* @param {{ siteId?: string, probes?: Record<string, any> }} [opts]
|
|
313
|
+
*/
|
|
314
|
+
export function emitSiteDelivery(outDir, deliveryRaw, opts = {}) {
|
|
315
|
+
const norm = normalizeSiteDelivery(deliveryRaw, { siteId: opts.siteId });
|
|
316
|
+
if (!norm.ok) {
|
|
317
|
+
throw new Error(`emitSiteDelivery: ${norm.diagnostics.map((d) => d.message).join('; ')}`);
|
|
318
|
+
}
|
|
319
|
+
const vmzDir = path.join(outDir, '_vmz');
|
|
320
|
+
fs.mkdirSync(vmzDir, { recursive: true });
|
|
321
|
+
fs.writeFileSync(path.join(vmzDir, 'site-delivery-contract.json'), `${JSON.stringify(norm.contract, null, 2)}\n`, 'utf8');
|
|
322
|
+
let resolution = null;
|
|
323
|
+
if (opts.probes) {
|
|
324
|
+
resolution = resolveSiteRelease(norm.contract, opts.probes);
|
|
325
|
+
fs.writeFileSync(path.join(vmzDir, 'site-delivery-resolution.json'), `${JSON.stringify(resolution, null, 2)}\n`, 'utf8');
|
|
326
|
+
}
|
|
327
|
+
return { contract: norm.contract, resolution };
|
|
328
|
+
}
|
|
329
|
+
function sha256Hex(data) {
|
|
330
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
331
|
+
}
|
|
332
|
+
function canonicalJson(value) {
|
|
333
|
+
return JSON.stringify(sortKeys(value));
|
|
334
|
+
}
|
|
335
|
+
function sortKeys(value) {
|
|
336
|
+
if (Array.isArray(value))
|
|
337
|
+
return value.map(sortKeys);
|
|
338
|
+
if (value && typeof value === 'object') {
|
|
339
|
+
const out = {};
|
|
340
|
+
for (const k of Object.keys(value).sort())
|
|
341
|
+
out[k] = sortKeys(value[k]);
|
|
342
|
+
return out;
|
|
343
|
+
}
|
|
344
|
+
return value;
|
|
345
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A3-static: emit per-route HTML + 404 + SEO head + StaticDeliveryManifest.
|
|
3
|
+
* Reuses the same Direct SSR path as serve-host (no second SSG runtime).
|
|
4
|
+
*/
|
|
5
|
+
export declare const STATIC_DELIVERY_MANIFEST_SCHEMA = "vmz.static.delivery_manifest.v0";
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} distDir
|
|
8
|
+
* @param {{
|
|
9
|
+
* origin?: string,
|
|
10
|
+
* applicationId?: string,
|
|
11
|
+
* staticParams?: Record<string, Array<Record<string, string>>>,
|
|
12
|
+
* }} [opts]
|
|
13
|
+
*/
|
|
14
|
+
export declare function emitWebStatic(distDir: any, opts?: {}): Promise<{
|
|
15
|
+
manifest: {
|
|
16
|
+
schema: string;
|
|
17
|
+
applicationId: any;
|
|
18
|
+
deliveryProfile: string;
|
|
19
|
+
origin: string;
|
|
20
|
+
generatedAt: string;
|
|
21
|
+
spaFallback: boolean;
|
|
22
|
+
errorDocuments: {
|
|
23
|
+
status: number;
|
|
24
|
+
path: string;
|
|
25
|
+
}[];
|
|
26
|
+
routes: {
|
|
27
|
+
routeId: any;
|
|
28
|
+
path: any;
|
|
29
|
+
chunkId: any;
|
|
30
|
+
htmlPath: any;
|
|
31
|
+
classification: any;
|
|
32
|
+
seo: {
|
|
33
|
+
title: any;
|
|
34
|
+
description: any;
|
|
35
|
+
canonical: any;
|
|
36
|
+
robots: any;
|
|
37
|
+
};
|
|
38
|
+
}[];
|
|
39
|
+
skipped: any[];
|
|
40
|
+
seoArtifacts: {
|
|
41
|
+
sitemap: string;
|
|
42
|
+
robots: string;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
htmlFiles: any[];
|
|
46
|
+
skipped: any[];
|
|
47
|
+
digest: any;
|
|
48
|
+
assets: {
|
|
49
|
+
schema: string;
|
|
50
|
+
layout: string;
|
|
51
|
+
immutable: boolean;
|
|
52
|
+
objectCount: number;
|
|
53
|
+
objects: any[];
|
|
54
|
+
rewrittenHtml: number;
|
|
55
|
+
};
|
|
56
|
+
cdnPolicy: {
|
|
57
|
+
schema: string;
|
|
58
|
+
applicationId: any;
|
|
59
|
+
deliveryProfile: string;
|
|
60
|
+
origin: string;
|
|
61
|
+
spaFallback: boolean;
|
|
62
|
+
staticManifestDigest: any;
|
|
63
|
+
redirects: any[];
|
|
64
|
+
headers: ({
|
|
65
|
+
match: string;
|
|
66
|
+
headers: {
|
|
67
|
+
'cache-control': string;
|
|
68
|
+
'x-robots-tag'?: undefined;
|
|
69
|
+
};
|
|
70
|
+
} | {
|
|
71
|
+
match: string;
|
|
72
|
+
headers: {
|
|
73
|
+
'cache-control': string;
|
|
74
|
+
'x-robots-tag': string;
|
|
75
|
+
};
|
|
76
|
+
})[];
|
|
77
|
+
errorDocuments: any;
|
|
78
|
+
routes: any;
|
|
79
|
+
};
|
|
80
|
+
cdnAdapters: {
|
|
81
|
+
'local-static': {
|
|
82
|
+
schema: string;
|
|
83
|
+
adapterId: string;
|
|
84
|
+
policyDigest: any;
|
|
85
|
+
host: string;
|
|
86
|
+
spaFallback: boolean;
|
|
87
|
+
redirects: any;
|
|
88
|
+
headers: any;
|
|
89
|
+
errorDocuments: any;
|
|
90
|
+
files: {
|
|
91
|
+
_headers?: undefined;
|
|
92
|
+
_redirects?: undefined;
|
|
93
|
+
};
|
|
94
|
+
} | {
|
|
95
|
+
schema: string;
|
|
96
|
+
adapterId: string;
|
|
97
|
+
policyDigest: any;
|
|
98
|
+
host: string;
|
|
99
|
+
spaFallback: boolean;
|
|
100
|
+
redirects: any;
|
|
101
|
+
headers: any;
|
|
102
|
+
errorDocuments: any;
|
|
103
|
+
files: {
|
|
104
|
+
_headers: string;
|
|
105
|
+
_redirects: string;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
netlify: {
|
|
109
|
+
schema: string;
|
|
110
|
+
adapterId: string;
|
|
111
|
+
policyDigest: any;
|
|
112
|
+
host: string;
|
|
113
|
+
spaFallback: boolean;
|
|
114
|
+
redirects: any;
|
|
115
|
+
headers: any;
|
|
116
|
+
errorDocuments: any;
|
|
117
|
+
files: {
|
|
118
|
+
_headers?: undefined;
|
|
119
|
+
_redirects?: undefined;
|
|
120
|
+
};
|
|
121
|
+
} | {
|
|
122
|
+
schema: string;
|
|
123
|
+
adapterId: string;
|
|
124
|
+
policyDigest: any;
|
|
125
|
+
host: string;
|
|
126
|
+
spaFallback: boolean;
|
|
127
|
+
redirects: any;
|
|
128
|
+
headers: any;
|
|
129
|
+
errorDocuments: any;
|
|
130
|
+
files: {
|
|
131
|
+
_headers: string;
|
|
132
|
+
_redirects: string;
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
}>;
|