@vmz/vmz 0.0.1 → 0.0.2

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.
Files changed (75) hide show
  1. package/README.md +48 -2
  2. package/bin/vmz.js +4 -0
  3. package/dist/application-cmd.d.ts +22 -0
  4. package/dist/application-cmd.js +348 -0
  5. package/dist/bundler-adapter.d.ts +64 -0
  6. package/dist/bundler-adapter.js +111 -0
  7. package/dist/cli.d.ts +15 -0
  8. package/dist/cli.js +370 -0
  9. package/dist/dev-session.d.ts +35 -0
  10. package/dist/dev-session.js +290 -0
  11. package/dist/document-build.d.ts +99 -0
  12. package/dist/document-build.js +274 -0
  13. package/dist/document-check.d.ts +44 -0
  14. package/dist/document-check.js +246 -0
  15. package/dist/document-cmd.d.ts +9 -0
  16. package/dist/document-cmd.js +147 -0
  17. package/dist/document-designs.d.ts +9 -0
  18. package/dist/document-designs.js +126 -0
  19. package/dist/document-enrich.d.ts +23 -0
  20. package/dist/document-enrich.js +234 -0
  21. package/dist/document-evidence.d.ts +49 -0
  22. package/dist/document-evidence.js +501 -0
  23. package/dist/document-integrate.d.ts +35 -0
  24. package/dist/document-integrate.js +89 -0
  25. package/dist/document-interactive.d.ts +69 -0
  26. package/dist/document-interactive.js +255 -0
  27. package/dist/document-locale.d.ts +31 -0
  28. package/dist/document-locale.js +59 -0
  29. package/dist/document-markdown.d.ts +13 -0
  30. package/dist/document-markdown.js +39 -0
  31. package/dist/document-scan.d.ts +21 -0
  32. package/dist/document-scan.js +151 -0
  33. package/dist/document-schema.d.ts +87 -0
  34. package/dist/document-schema.js +88 -0
  35. package/dist/explain-cmd.d.ts +5 -0
  36. package/dist/explain-cmd.js +123 -0
  37. package/dist/index.d.ts +808 -0
  38. package/dist/index.js +569 -0
  39. package/dist/locale-check.d.ts +106 -0
  40. package/dist/locale-check.js +737 -0
  41. package/dist/locale-cmd.d.ts +5 -0
  42. package/dist/locale-cmd.js +443 -0
  43. package/dist/locale-delivery.d.ts +298 -0
  44. package/dist/locale-delivery.js +444 -0
  45. package/dist/locale-router.d.ts +207 -0
  46. package/dist/locale-router.js +508 -0
  47. package/dist/locale-runtime.d.ts +406 -0
  48. package/dist/locale-runtime.js +542 -0
  49. package/dist/locale-schema.d.ts +9 -0
  50. package/dist/locale-schema.js +10 -0
  51. package/dist/locale-tooling.d.ts +118 -0
  52. package/dist/locale-tooling.js +358 -0
  53. package/dist/log.d.ts +19 -0
  54. package/dist/log.js +42 -0
  55. package/dist/packages.d.ts +27 -0
  56. package/dist/packages.js +147 -0
  57. package/dist/plugin-host.d.ts +30 -0
  58. package/dist/plugin-host.js +370 -0
  59. package/dist/refactor-cmd.d.ts +8 -0
  60. package/dist/refactor-cmd.js +156 -0
  61. package/dist/resolve.d.ts +25 -0
  62. package/dist/resolve.js +56 -0
  63. package/dist/test-cmd.d.ts +9 -0
  64. package/dist/test-cmd.js +343 -0
  65. package/dist/test-compile.d.ts +2 -0
  66. package/dist/test-compile.js +3 -0
  67. package/dist/test-discover.d.ts +2 -0
  68. package/dist/test-discover.js +3 -0
  69. package/dist/test-logic.d.ts +2 -0
  70. package/dist/test-logic.js +3 -0
  71. package/dist/test-protocol.d.ts +2 -0
  72. package/dist/test-protocol.js +3 -0
  73. package/dist/watch-diff.d.ts +17 -0
  74. package/dist/watch-diff.js +56 -0
  75. package/package.json +81 -3
@@ -0,0 +1,444 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * Locale I4 multi-host delivery: Web chunks · Mini packages · Native packs ·
4
+ * Server error envelope / formatter resources.
5
+ * Design: 规划设计/vmz/28 §9–§10
6
+ *
7
+ * Same MessageNode projects to all Surfaces; LocaleId is not a WebSurface concern.
8
+ */
9
+ import { createHash } from 'node:crypto';
10
+ import { DIAG_LOCALE_CHUNK_HASH_MISMATCH, DIAG_LOCALE_DELIVERY_FULL_BUNDLE, DIAG_LOCALE_HOST_MESSAGE_DIVERGENCE, DIAG_LOCALE_MINI_CROSS_PACKAGE_UNPROVEN, DIAG_LOCALE_NATIVE_PACK_APP_MISMATCH, DIAG_LOCALE_NATIVE_PACK_HAS_JS, DIAG_LOCALE_NATIVE_PACK_UNSIGNED, DIAG_LOCALE_SERVER_FORMAT_WITHOUT_CONTEXT, DIAG_LOCALE_SERVER_TRANSLATED_ERROR, FORMATTER_DATA_VERSION, LOCALE_CHUNK_MANIFEST_SCHEMA, LOCALE_DELIVERY_CHECK_SCHEMA, LOCALE_DELIVERY_RESOLUTION_SCHEMA, LOCALE_MINI_PACKAGE_PROOF_SCHEMA, LOCALE_NATIVE_PACK_SCHEMA, LOCALE_SERVER_ERROR_ENVELOPE_SCHEMA, } from './locale-schema.js';
11
+ /**
12
+ * @param {unknown} value
13
+ */
14
+ function stableHash(value) {
15
+ return createHash('sha256').update(JSON.stringify(value)).digest('hex').slice(0, 32);
16
+ }
17
+ /**
18
+ * @param {Record<string, string[]>} [fallback]
19
+ */
20
+ export function fallbackDigest(fallback = {}) {
21
+ const keys = Object.keys(fallback).sort();
22
+ const normalized = {};
23
+ for (const k of keys)
24
+ normalized[k] = [...(fallback[k] || [])];
25
+ return stableHash(normalized);
26
+ }
27
+ /**
28
+ * Hash reachable message variants for one locale.
29
+ * @param {Array<{ messageId: string, variants: Record<string, { template: string }> }>} messages
30
+ * @param {string} localeId
31
+ * @param {string[]} [reachableIds]
32
+ */
33
+ export function messageCatalogHash(messages, localeId, reachableIds) {
34
+ const allow = reachableIds ? new Set(reachableIds) : null;
35
+ /** @type {Record<string, string>} */
36
+ const slice = {};
37
+ for (const m of messages || []) {
38
+ if (allow && !allow.has(m.messageId))
39
+ continue;
40
+ const t = m.variants?.[localeId]?.template;
41
+ if (t != null)
42
+ slice[m.messageId] = t;
43
+ }
44
+ const ordered = Object.keys(slice)
45
+ .sort()
46
+ .map((k) => [k, slice[k]]);
47
+ return stableHash(ordered);
48
+ }
49
+ /**
50
+ * Build LocaleDeliveryResolution for one Host surface.
51
+ * @param {{
52
+ * host: 'web'|'mini'|'native'|'server',
53
+ * applicationId: string,
54
+ * deliveryId: string,
55
+ * planVersion?: string,
56
+ * supportedLocales: string[],
57
+ * defaultLocale: string,
58
+ * fallback?: Record<string, string[]>,
59
+ * routingRealization?: unknown,
60
+ * messages: Array<{ messageId: string, variants: Record<string, { template: string }> }>,
61
+ * reachableMessageIds?: string[],
62
+ * bundledLocales?: string[],
63
+ * allowFullClientBundle?: boolean,
64
+ * }} input
65
+ */
66
+ export function buildLocaleDeliveryResolution(input) {
67
+ /** @type {any[]} */
68
+ const diagnostics = [];
69
+ const supported = [...(input.supportedLocales || [])];
70
+ const defaultLocale = input.defaultLocale;
71
+ const reachable = input.reachableMessageIds || (input.messages || []).map((m) => m.messageId);
72
+ const bundled = input.bundledLocales && input.bundledLocales.length ? [...input.bundledLocales] : [defaultLocale];
73
+ // Never default-ship every locale into a client bundle.
74
+ if ((input.host === 'web' || input.host === 'mini') &&
75
+ bundled.length >= supported.length &&
76
+ supported.length > 1 &&
77
+ !input.allowFullClientBundle) {
78
+ diagnostics.push({
79
+ code: DIAG_LOCALE_DELIVERY_FULL_BUNDLE,
80
+ severity: 'error',
81
+ message: `${input.host} delivery must not bundle all ${supported.length} locales by default`,
82
+ });
83
+ }
84
+ /** @type {Record<string, string>} */
85
+ const messageCatalogHashes = {};
86
+ for (const loc of supported) {
87
+ messageCatalogHashes[loc] = messageCatalogHash(input.messages, loc, reachable);
88
+ }
89
+ /** @type {any[]} */
90
+ const lazyLocaleChunks = [];
91
+ for (const loc of supported) {
92
+ if (bundled.includes(loc))
93
+ continue;
94
+ lazyLocaleChunks.push({
95
+ schema: LOCALE_CHUNK_MANIFEST_SCHEMA,
96
+ localeId: loc,
97
+ host: input.host,
98
+ messageIds: reachable,
99
+ hash: messageCatalogHashes[loc],
100
+ kind: input.host === 'mini' ? 'subpackage_module' : 'locale_chunk',
101
+ });
102
+ }
103
+ const bundledChunks = bundled.map((loc) => ({
104
+ schema: LOCALE_CHUNK_MANIFEST_SCHEMA,
105
+ localeId: loc,
106
+ host: input.host,
107
+ messageIds: reachable,
108
+ hash: messageCatalogHashes[loc],
109
+ kind: input.host === 'server' ? 'server_resources' : 'bundled',
110
+ }));
111
+ return {
112
+ schema: LOCALE_DELIVERY_RESOLUTION_SCHEMA,
113
+ status: diagnostics.length ? 'failed' : 'ready',
114
+ host: input.host,
115
+ applicationId: input.applicationId,
116
+ deliveryId: input.deliveryId,
117
+ planVersion: input.planVersion || 'plan.v0',
118
+ supportedLocales: supported,
119
+ defaultLocale,
120
+ fallbackDigest: fallbackDigest(input.fallback),
121
+ routingRealization: input.routingRealization || null,
122
+ bundledLocales: bundled,
123
+ lazyLocaleChunks,
124
+ bundledChunks,
125
+ formatterDataVersion: FORMATTER_DATA_VERSION,
126
+ messageCatalogHashes,
127
+ reachableMessageIds: reachable,
128
+ diagnostics,
129
+ };
130
+ }
131
+ /**
132
+ * Validate a Native optional locale pack (signed, no JS, bound to app/plan/schema).
133
+ * @param {{
134
+ * pack: {
135
+ * schema?: string,
136
+ * applicationId: string,
137
+ * planVersion: string,
138
+ * localeId: string,
139
+ * signature?: string,
140
+ * catalog?: Record<string, string>,
141
+ * formatterDataVersion?: string,
142
+ * entries?: Array<{ path: string, kind?: string }>,
143
+ * executable?: boolean,
144
+ * },
145
+ * expectedApplicationId: string,
146
+ * expectedPlanVersion: string,
147
+ * }} input
148
+ */
149
+ export function validateNativeLocalePack(input) {
150
+ /** @type {any[]} */
151
+ const diagnostics = [];
152
+ const pack = input.pack || {};
153
+ if (!pack.signature) {
154
+ diagnostics.push({
155
+ code: DIAG_LOCALE_NATIVE_PACK_UNSIGNED,
156
+ severity: 'error',
157
+ message: 'Native locale pack must be signed',
158
+ });
159
+ }
160
+ if (pack.applicationId !== input.expectedApplicationId) {
161
+ diagnostics.push({
162
+ code: DIAG_LOCALE_NATIVE_PACK_APP_MISMATCH,
163
+ severity: 'error',
164
+ message: `pack applicationId ${pack.applicationId} != ${input.expectedApplicationId}`,
165
+ });
166
+ }
167
+ if (pack.planVersion !== input.expectedPlanVersion) {
168
+ diagnostics.push({
169
+ code: DIAG_LOCALE_NATIVE_PACK_APP_MISMATCH,
170
+ severity: 'error',
171
+ message: `pack planVersion ${pack.planVersion} != ${input.expectedPlanVersion}`,
172
+ });
173
+ }
174
+ if (pack.executable === true) {
175
+ diagnostics.push({
176
+ code: DIAG_LOCALE_NATIVE_PACK_HAS_JS,
177
+ severity: 'error',
178
+ message: 'Native locale pack must not carry executable JavaScript',
179
+ });
180
+ }
181
+ for (const e of pack.entries || []) {
182
+ const path = String(e.path || '');
183
+ const kind = String(e.kind || '');
184
+ if (/\.(js|mjs|cjs|wasm)$/i.test(path) || kind === 'javascript' || kind === 'script') {
185
+ diagnostics.push({
186
+ code: DIAG_LOCALE_NATIVE_PACK_HAS_JS,
187
+ severity: 'error',
188
+ message: `Native pack entry forbids executable ${path || kind}`,
189
+ });
190
+ }
191
+ }
192
+ if (pack.formatterDataVersion && pack.formatterDataVersion !== FORMATTER_DATA_VERSION) {
193
+ diagnostics.push({
194
+ code: DIAG_LOCALE_CHUNK_HASH_MISMATCH,
195
+ severity: 'error',
196
+ message: `formatterDataVersion ${pack.formatterDataVersion} != ${FORMATTER_DATA_VERSION}`,
197
+ });
198
+ }
199
+ return {
200
+ schema: LOCALE_NATIVE_PACK_SCHEMA,
201
+ status: diagnostics.length ? 'failed' : 'ready',
202
+ localeId: pack.localeId,
203
+ diagnostics,
204
+ pack: {
205
+ schema: LOCALE_NATIVE_PACK_SCHEMA,
206
+ applicationId: pack.applicationId,
207
+ planVersion: pack.planVersion,
208
+ localeId: pack.localeId,
209
+ signature: pack.signature || null,
210
+ formatterDataVersion: pack.formatterDataVersion || FORMATTER_DATA_VERSION,
211
+ catalogKeys: Object.keys(pack.catalog || {}).sort(),
212
+ },
213
+ };
214
+ }
215
+ /**
216
+ * Mini cross-subpackage message dependencies must be proven.
217
+ * @param {{
218
+ * packages: Array<{ id: string, messageIds: string[] }>,
219
+ * edges: Array<{ fromPackage: string, toPackage: string, messageId: string }>,
220
+ * }} input
221
+ */
222
+ export function proveMiniPackageMessages(input) {
223
+ /** @type {any[]} */
224
+ const diagnostics = [];
225
+ /** @type {Map<string, Set<string>>} */
226
+ const owned = new Map();
227
+ for (const p of input.packages || []) {
228
+ owned.set(p.id, new Set(p.messageIds || []));
229
+ }
230
+ /** @type {any[]} */
231
+ const proven = [];
232
+ for (const edge of input.edges || []) {
233
+ const target = owned.get(edge.toPackage);
234
+ if (!target || !target.has(edge.messageId)) {
235
+ diagnostics.push({
236
+ code: DIAG_LOCALE_MINI_CROSS_PACKAGE_UNPROVEN,
237
+ severity: 'error',
238
+ message: `cross-package message ${edge.messageId}: ${edge.fromPackage} -> ${edge.toPackage} unproven`,
239
+ });
240
+ continue;
241
+ }
242
+ proven.push({
243
+ fromPackage: edge.fromPackage,
244
+ toPackage: edge.toPackage,
245
+ messageId: edge.messageId,
246
+ });
247
+ }
248
+ return {
249
+ schema: LOCALE_MINI_PACKAGE_PROOF_SCHEMA,
250
+ status: diagnostics.length ? 'failed' : 'ready',
251
+ proven,
252
+ diagnostics,
253
+ };
254
+ }
255
+ /**
256
+ * Server/client boundary: ErrorCode + params only (no translated strings).
257
+ * @param {any} payload
258
+ */
259
+ export function assertServerErrorEnvelope(payload) {
260
+ /** @type {any[]} */
261
+ const diagnostics = [];
262
+ if (payload == null || typeof payload !== 'object') {
263
+ diagnostics.push({
264
+ code: DIAG_LOCALE_SERVER_TRANSLATED_ERROR,
265
+ severity: 'error',
266
+ message: 'server error envelope must be an object',
267
+ });
268
+ return { schema: LOCALE_SERVER_ERROR_ENVELOPE_SCHEMA, status: 'failed', diagnostics };
269
+ }
270
+ if (typeof payload.message === 'string' || typeof payload.text === 'string' || typeof payload.localized === 'string') {
271
+ diagnostics.push({
272
+ code: DIAG_LOCALE_SERVER_TRANSLATED_ERROR,
273
+ severity: 'error',
274
+ message: 'server must not cross boundary with translated error strings',
275
+ });
276
+ }
277
+ if (typeof payload.code !== 'string' || !payload.code) {
278
+ diagnostics.push({
279
+ code: DIAG_LOCALE_SERVER_TRANSLATED_ERROR,
280
+ severity: 'error',
281
+ message: 'server error envelope requires stable ErrorCode `code`',
282
+ });
283
+ }
284
+ return {
285
+ schema: LOCALE_SERVER_ERROR_ENVELOPE_SCHEMA,
286
+ status: diagnostics.length ? 'failed' : 'ready',
287
+ envelope: {
288
+ schema: LOCALE_SERVER_ERROR_ENVELOPE_SCHEMA,
289
+ code: payload.code,
290
+ params: payload.params || {},
291
+ },
292
+ diagnostics,
293
+ };
294
+ }
295
+ /**
296
+ * Final-user server formatting (mail/export/push) requires explicit LocaleContext.
297
+ * @param {{ localeContext?: { localeId?: string, timeZone?: string }|null, purpose: string }} input
298
+ */
299
+ export function assertServerFormatContext(input) {
300
+ /** @type {any[]} */
301
+ const diagnostics = [];
302
+ const ctx = input.localeContext;
303
+ if (!ctx?.localeId || !ctx?.timeZone) {
304
+ diagnostics.push({
305
+ code: DIAG_LOCALE_SERVER_FORMAT_WITHOUT_CONTEXT,
306
+ severity: 'error',
307
+ message: `server ${input.purpose} formatting requires explicit LocaleContext`,
308
+ });
309
+ }
310
+ return { ok: diagnostics.length === 0, diagnostics };
311
+ }
312
+ /**
313
+ * Same MessageId / catalog hashes must agree across Host projections.
314
+ * @param {Array<ReturnType<typeof buildLocaleDeliveryResolution>>} resolutions
315
+ */
316
+ export function assertHostMessageInvariant(resolutions) {
317
+ /** @type {any[]} */
318
+ const diagnostics = [];
319
+ if (!resolutions?.length)
320
+ return { ok: true, diagnostics };
321
+ const base = resolutions[0];
322
+ for (const r of resolutions.slice(1)) {
323
+ for (const loc of base.supportedLocales || []) {
324
+ if (base.messageCatalogHashes[loc] !== r.messageCatalogHashes?.[loc]) {
325
+ diagnostics.push({
326
+ code: DIAG_LOCALE_HOST_MESSAGE_DIVERGENCE,
327
+ severity: 'error',
328
+ message: `messageCatalogHashes[${loc}] diverge between ${base.host} and ${r.host}`,
329
+ });
330
+ }
331
+ }
332
+ if (base.formatterDataVersion !== r.formatterDataVersion) {
333
+ diagnostics.push({
334
+ code: DIAG_LOCALE_HOST_MESSAGE_DIVERGENCE,
335
+ severity: 'error',
336
+ message: `formatterDataVersion diverge between ${base.host} and ${r.host}`,
337
+ });
338
+ }
339
+ if (base.fallbackDigest !== r.fallbackDigest) {
340
+ diagnostics.push({
341
+ code: DIAG_LOCALE_HOST_MESSAGE_DIVERGENCE,
342
+ severity: 'error',
343
+ message: `fallbackDigest diverge between ${base.host} and ${r.host}`,
344
+ });
345
+ }
346
+ }
347
+ return { ok: diagnostics.length === 0, diagnostics };
348
+ }
349
+ /**
350
+ * Aggregate I4 delivery proof for fixture / CLI.
351
+ * @param {{
352
+ * manifest: {
353
+ * defaultLocale: string,
354
+ * locales: Array<{ id: string }>,
355
+ * fallback?: Record<string, string[]>,
356
+ * routing?: unknown,
357
+ * },
358
+ * messages: Array<{ messageId: string, variants: Record<string, { template: string }> }>,
359
+ * applicationId?: string,
360
+ * planVersion?: string,
361
+ * reachableMessageIds?: string[],
362
+ * }} input
363
+ */
364
+ export function checkLocaleDelivery(input) {
365
+ /** @type {any[]} */
366
+ const diagnostics = [];
367
+ const supported = (input.manifest?.locales || []).map((l) => l.id);
368
+ const defaultLocale = input.manifest?.defaultLocale;
369
+ const messages = input.messages || [];
370
+ const reachable = input.reachableMessageIds || messages.map((m) => m.messageId);
371
+ const common = {
372
+ applicationId: input.applicationId || 'app.locales-fixture',
373
+ deliveryId: 'delivery.multi',
374
+ planVersion: input.planVersion || 'plan.v0',
375
+ supportedLocales: supported,
376
+ defaultLocale,
377
+ fallback: input.manifest?.fallback || {},
378
+ routingRealization: input.manifest?.routing || null,
379
+ messages,
380
+ reachableMessageIds: reachable,
381
+ bundledLocales: [defaultLocale],
382
+ };
383
+ const web = buildLocaleDeliveryResolution({ ...common, host: 'web', deliveryId: 'delivery.web' });
384
+ const mini = buildLocaleDeliveryResolution({ ...common, host: 'mini', deliveryId: 'delivery.mini' });
385
+ const native = buildLocaleDeliveryResolution({
386
+ ...common,
387
+ host: 'native',
388
+ deliveryId: 'delivery.native',
389
+ });
390
+ const server = buildLocaleDeliveryResolution({
391
+ ...common,
392
+ host: 'server',
393
+ deliveryId: 'delivery.server',
394
+ // server may include all reachable locales as resources (not a client bundle)
395
+ bundledLocales: supported,
396
+ allowFullClientBundle: true,
397
+ });
398
+ for (const r of [web, mini, native, server])
399
+ diagnostics.push(...r.diagnostics);
400
+ const invariant = assertHostMessageInvariant([web, mini, native, server]);
401
+ diagnostics.push(...invariant.diagnostics);
402
+ const packOk = validateNativeLocalePack({
403
+ pack: {
404
+ applicationId: common.applicationId,
405
+ planVersion: common.planVersion,
406
+ localeId: 'en-us',
407
+ signature: 'sig.test',
408
+ catalog: { 'account.actions.save': 'Save' },
409
+ formatterDataVersion: FORMATTER_DATA_VERSION,
410
+ entries: [{ path: 'catalog.json5', kind: 'catalog' }],
411
+ },
412
+ expectedApplicationId: common.applicationId,
413
+ expectedPlanVersion: common.planVersion,
414
+ });
415
+ // Probe only — do not fail delivery check if packOk ready.
416
+ if (packOk.status !== 'ready')
417
+ diagnostics.push(...packOk.diagnostics);
418
+ const miniProof = proveMiniPackageMessages({
419
+ packages: [
420
+ { id: 'main', messageIds: ['account.actions.save'] },
421
+ { id: 'pkg-account', messageIds: ['account.greeting', 'account.itemCount'] },
422
+ ],
423
+ edges: [{ fromPackage: 'main', toPackage: 'pkg-account', messageId: 'account.greeting' }],
424
+ });
425
+ if (miniProof.status !== 'ready')
426
+ diagnostics.push(...miniProof.diagnostics);
427
+ const errOk = assertServerErrorEnvelope({
428
+ code: 'account.email_taken',
429
+ params: { email: 'a@b.c' },
430
+ });
431
+ if (errOk.status !== 'ready')
432
+ diagnostics.push(...errOk.diagnostics);
433
+ const hasErrors = diagnostics.some((d) => d.severity === 'error');
434
+ return {
435
+ schema: LOCALE_DELIVERY_CHECK_SCHEMA,
436
+ status: hasErrors ? 'failed' : 'ready',
437
+ resolutions: { web, mini, native, server },
438
+ nativePackProbe: packOk,
439
+ miniPackageProof: miniProof,
440
+ serverErrorEnvelope: errOk,
441
+ formatterDataVersion: FORMATTER_DATA_VERSION,
442
+ diagnostics,
443
+ };
444
+ }
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Locale I3 router / PageMeta: route realization · canonical · hreflang ·
3
+ * Link locale retain · locale-aware cache key.
4
+ * Design: 规划设计/vmz/28 §6 · §10 · 20
5
+ *
6
+ * LocaleId is a RouteNode realization dimension — not part of stable RouteId.
7
+ */
8
+ /**
9
+ * Join locale prefix with a stable route path pattern.
10
+ * @param {string} localeId
11
+ * @param {string} pathPattern stable path without locale (e.g. /account/profile)
12
+ * @param {{ strategy?: string, defaultPrefix?: string, defaultLocale?: string }} routing
13
+ */
14
+ export declare function realizeRoutePath(localeId: any, pathPattern: any, routing?: {}): {
15
+ schema: string;
16
+ localeId: any;
17
+ path: string;
18
+ prefixed: boolean;
19
+ strategy: any;
20
+ defaultPrefix?: undefined;
21
+ } | {
22
+ schema: string;
23
+ localeId: any;
24
+ path: string;
25
+ prefixed: boolean;
26
+ strategy: string;
27
+ defaultPrefix: any;
28
+ };
29
+ /**
30
+ * Build RouteId × LocaleId realization table.
31
+ * @param {{
32
+ * routes: Array<{ routeId: string, path: string }>,
33
+ * locales: string[],
34
+ * defaultLocale: string,
35
+ * routing?: { strategy?: string, defaultPrefix?: string },
36
+ * }} input
37
+ */
38
+ export declare function buildLocaleRouteRealizationTable(input: any): {
39
+ schema: string;
40
+ status: string;
41
+ routing: {
42
+ strategy: any;
43
+ defaultPrefix: any;
44
+ defaultLocale: any;
45
+ };
46
+ realizations: any[];
47
+ diagnostics: any[];
48
+ };
49
+ /**
50
+ * Absolute URL helper.
51
+ * @param {string} origin
52
+ * @param {string} path
53
+ */
54
+ export declare function absoluteUrl(origin: any, path: any): string;
55
+ /**
56
+ * Locale-aware PageMeta for one RouteId × LocaleId.
57
+ * @param {{
58
+ * routeId: string,
59
+ * localeId: string,
60
+ * direction?: string,
61
+ * title: string,
62
+ * description?: string,
63
+ * origin: string,
64
+ * realizations: Array<{ routeId: string, localeId: string, path: string }>,
65
+ * locales: string[],
66
+ * defaultLocale: string,
67
+ * }} input
68
+ */
69
+ export declare function buildLocalePageMeta(input: any): {
70
+ schema: string;
71
+ routeId: any;
72
+ locale: any;
73
+ htmlLang: any;
74
+ dir: any;
75
+ title: any;
76
+ description: any;
77
+ canonical: string;
78
+ alternates: any[];
79
+ diagnostics: any[];
80
+ status: string;
81
+ };
82
+ /**
83
+ * `<Link to="routeId">` retains current locale — never hand-written localized paths.
84
+ * @param {{
85
+ * to: string,
86
+ * currentLocale: string,
87
+ * realizations: Array<{ routeId: string, localeId: string, path: string }>,
88
+ * }} input
89
+ */
90
+ export declare function resolveLinkHref(input: any): {
91
+ schema: string;
92
+ status: string;
93
+ to: any;
94
+ href: any;
95
+ localeId: any;
96
+ diagnostics: {
97
+ code: string;
98
+ severity: string;
99
+ message: string;
100
+ }[];
101
+ routeId?: undefined;
102
+ } | {
103
+ schema: string;
104
+ status: string;
105
+ to: any;
106
+ routeId: any;
107
+ localeId: any;
108
+ href: any;
109
+ diagnostics: any[];
110
+ };
111
+ /**
112
+ * Parse locale prefix from a pathname under prefix strategy.
113
+ * @param {string} pathname
114
+ * @param {string[]} supportedLocales
115
+ */
116
+ export declare function parseLocaleFromPath(pathname: any, supportedLocales: any): {
117
+ localeId: string;
118
+ restPath: string;
119
+ };
120
+ /**
121
+ * Plan redirect / negotiation for an incoming URL (omit-prefix aware).
122
+ * @param {{
123
+ * pathname: string,
124
+ * supportedLocales: string[],
125
+ * defaultLocale: string,
126
+ * routing?: { strategy?: string, defaultPrefix?: string },
127
+ * hostCandidates?: string[],
128
+ * preference?: string|null,
129
+ * userChoice?: string|null,
130
+ * }} input
131
+ */
132
+ export declare function planLocalePathNavigation(input: any): {
133
+ schema: string;
134
+ kind: string;
135
+ pathname: string;
136
+ routeLocale: string;
137
+ negotiatedLocale: any;
138
+ restPath: string;
139
+ redirectTo: any;
140
+ realizedPath: string;
141
+ diagnostics: any[];
142
+ contentLocale: any;
143
+ };
144
+ /**
145
+ * Locale-aware cache key — must include LocaleId so Accept-Language cannot steal content.
146
+ * @param {{ routeId: string, localeId: string, path: string }} input
147
+ */
148
+ export declare function localeAwareCacheKey(input: any): string;
149
+ /**
150
+ * Reject Vary: Accept-Language on a cache key that does not encode LocaleId.
151
+ * @param {{ cacheKey: string, varyAcceptLanguage?: boolean, localeId?: string }} input
152
+ */
153
+ export declare function assertLocaleCacheKey(input: any): {
154
+ ok: boolean;
155
+ diagnostics: any[];
156
+ };
157
+ /**
158
+ * LocaleTransition must commit Route realization + PageMeta together.
159
+ * @param {{
160
+ * fromLocale: string,
161
+ * toLocale: string,
162
+ * routeId: string,
163
+ * realizations: Array<{ routeId: string, localeId: string, path: string }>,
164
+ * pageMetaByLocale: Record<string, { locale: string, canonical: string }>,
165
+ * }} input
166
+ */
167
+ export declare function commitLocaleRouteMetaTransition(input: any): {
168
+ schema: string;
169
+ kind: string;
170
+ status: string;
171
+ fromLocale: any;
172
+ toLocale: any;
173
+ fromPath: any;
174
+ toPath: any;
175
+ pageMeta: any;
176
+ diagnostics: any[];
177
+ };
178
+ /**
179
+ * Aggregate I3 router/meta proof.
180
+ * @param {{
181
+ * manifest: {
182
+ * defaultLocale: string,
183
+ * locales: Array<{ id: string, direction?: string }>,
184
+ * routing?: { strategy?: string, defaultPrefix?: string },
185
+ * },
186
+ * routes: Array<{ routeId: string, path: string }>,
187
+ * titles?: Record<string, Record<string, string>>,
188
+ * origin?: string,
189
+ * }} input
190
+ */
191
+ export declare function checkLocaleRouter(input: any): {
192
+ schema: string;
193
+ status: string;
194
+ realizationTable: {
195
+ schema: string;
196
+ status: string;
197
+ routing: {
198
+ strategy: any;
199
+ defaultPrefix: any;
200
+ defaultLocale: any;
201
+ };
202
+ realizations: any[];
203
+ diagnostics: any[];
204
+ };
205
+ pageMetas: any[];
206
+ diagnostics: any[];
207
+ };