@bleedingdev/modern-js-create 3.4.0-ultramodern.2 → 3.4.0-ultramodern.20

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 (128) hide show
  1. package/README.md +13 -11
  2. package/dist/cjs/index.cjs +37 -4
  3. package/dist/cjs/locale/en.cjs +12 -2
  4. package/dist/cjs/locale/zh.cjs +12 -2
  5. package/dist/cjs/ultramodern-tooling/commands.cjs +185 -0
  6. package/dist/cjs/ultramodern-tooling/config.cjs +172 -0
  7. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +79 -61
  8. package/dist/cjs/ultramodern-workspace/bridge-config.cjs +327 -0
  9. package/dist/cjs/ultramodern-workspace/codesmith.cjs +1 -0
  10. package/dist/cjs/ultramodern-workspace/contracts.cjs +121 -648
  11. package/dist/cjs/ultramodern-workspace/demo-components.cjs +26 -33
  12. package/dist/cjs/ultramodern-workspace/descriptors.cjs +4 -4
  13. package/dist/cjs/ultramodern-workspace/effect-api.cjs +230 -100
  14. package/dist/cjs/ultramodern-workspace/fs-io.cjs +117 -0
  15. package/dist/cjs/ultramodern-workspace/generation-result.cjs +1 -1
  16. package/dist/cjs/ultramodern-workspace/index.cjs +4 -0
  17. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +571 -0
  18. package/dist/cjs/ultramodern-workspace/module-federation.cjs +51 -20
  19. package/dist/cjs/ultramodern-workspace/package-json.cjs +62 -19
  20. package/dist/cjs/ultramodern-workspace/policy.cjs +2 -2
  21. package/dist/cjs/ultramodern-workspace/public-api.cjs +4 -0
  22. package/dist/cjs/ultramodern-workspace/versions.cjs +5 -0
  23. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +80 -43
  24. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +63 -20
  25. package/dist/esm/index.js +37 -4
  26. package/dist/esm/locale/en.js +12 -2
  27. package/dist/esm/locale/zh.js +12 -2
  28. package/dist/esm/ultramodern-tooling/commands.js +132 -0
  29. package/dist/esm/ultramodern-tooling/config.js +120 -0
  30. package/dist/esm/ultramodern-workspace/add-vertical.js +81 -66
  31. package/dist/esm/ultramodern-workspace/bridge-config.js +270 -0
  32. package/dist/esm/ultramodern-workspace/codesmith.js +1 -0
  33. package/dist/esm/ultramodern-workspace/contracts.js +124 -603
  34. package/dist/esm/ultramodern-workspace/demo-components.js +26 -33
  35. package/dist/esm/ultramodern-workspace/descriptors.js +2 -2
  36. package/dist/esm/ultramodern-workspace/effect-api.js +230 -100
  37. package/dist/esm/ultramodern-workspace/fs-io.js +116 -2
  38. package/dist/esm/ultramodern-workspace/generation-result.js +2 -2
  39. package/dist/esm/ultramodern-workspace/index.js +1 -0
  40. package/dist/esm/ultramodern-workspace/mf-validation.js +516 -0
  41. package/dist/esm/ultramodern-workspace/module-federation.js +49 -21
  42. package/dist/esm/ultramodern-workspace/package-json.js +60 -20
  43. package/dist/esm/ultramodern-workspace/policy.js +2 -2
  44. package/dist/esm/ultramodern-workspace/public-api.js +1 -0
  45. package/dist/esm/ultramodern-workspace/versions.js +3 -1
  46. package/dist/esm/ultramodern-workspace/workspace-scripts.js +78 -26
  47. package/dist/esm/ultramodern-workspace/write-workspace.js +67 -27
  48. package/dist/esm-node/index.js +37 -4
  49. package/dist/esm-node/locale/en.js +12 -2
  50. package/dist/esm-node/locale/zh.js +12 -2
  51. package/dist/esm-node/ultramodern-tooling/commands.js +133 -0
  52. package/dist/esm-node/ultramodern-tooling/config.js +121 -0
  53. package/dist/esm-node/ultramodern-workspace/add-vertical.js +81 -66
  54. package/dist/esm-node/ultramodern-workspace/bridge-config.js +271 -0
  55. package/dist/esm-node/ultramodern-workspace/codesmith.js +1 -0
  56. package/dist/esm-node/ultramodern-workspace/contracts.js +124 -603
  57. package/dist/esm-node/ultramodern-workspace/demo-components.js +26 -33
  58. package/dist/esm-node/ultramodern-workspace/descriptors.js +2 -2
  59. package/dist/esm-node/ultramodern-workspace/effect-api.js +230 -100
  60. package/dist/esm-node/ultramodern-workspace/fs-io.js +116 -2
  61. package/dist/esm-node/ultramodern-workspace/generation-result.js +2 -2
  62. package/dist/esm-node/ultramodern-workspace/index.js +1 -0
  63. package/dist/esm-node/ultramodern-workspace/mf-validation.js +517 -0
  64. package/dist/esm-node/ultramodern-workspace/module-federation.js +49 -21
  65. package/dist/esm-node/ultramodern-workspace/package-json.js +60 -20
  66. package/dist/esm-node/ultramodern-workspace/policy.js +2 -2
  67. package/dist/esm-node/ultramodern-workspace/public-api.js +1 -0
  68. package/dist/esm-node/ultramodern-workspace/versions.js +3 -1
  69. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +78 -26
  70. package/dist/esm-node/ultramodern-workspace/write-workspace.js +67 -27
  71. package/dist/types/locale/en.d.ts +10 -0
  72. package/dist/types/locale/index.d.ts +20 -0
  73. package/dist/types/locale/zh.d.ts +10 -0
  74. package/dist/types/ultramodern-tooling/commands.d.ts +1 -0
  75. package/dist/types/ultramodern-tooling/config.d.ts +43 -0
  76. package/dist/types/ultramodern-workspace/add-vertical.d.ts +5 -2
  77. package/dist/types/ultramodern-workspace/bridge-config.d.ts +64 -0
  78. package/dist/types/ultramodern-workspace/codesmith.d.ts +1 -0
  79. package/dist/types/ultramodern-workspace/contracts.d.ts +2 -17
  80. package/dist/types/ultramodern-workspace/descriptors.d.ts +1 -1
  81. package/dist/types/ultramodern-workspace/fs-io.d.ts +1 -0
  82. package/dist/types/ultramodern-workspace/index.d.ts +2 -0
  83. package/dist/types/ultramodern-workspace/mf-validation.d.ts +27 -0
  84. package/dist/types/ultramodern-workspace/module-federation.d.ts +1 -0
  85. package/dist/types/ultramodern-workspace/package-json.d.ts +5 -3
  86. package/dist/types/ultramodern-workspace/public-api.d.ts +2 -0
  87. package/dist/types/ultramodern-workspace/types.d.ts +2 -0
  88. package/dist/types/ultramodern-workspace/versions.d.ts +2 -0
  89. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +2 -7
  90. package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -2
  91. package/package.json +5 -3
  92. package/template-workspace/{.agents → .codex}/skills-lock.json +12 -12
  93. package/template-workspace/.gitignore.handlebars +3 -0
  94. package/template-workspace/AGENTS.md.handlebars +11 -5
  95. package/template-workspace/README.md.handlebars +15 -12
  96. package/template-workspace/oxfmt.config.ts +1 -0
  97. package/template-workspace/oxlint.config.ts +1 -0
  98. package/template-workspace/patches/@tanstack__router-core@1.171.13.patch +51 -0
  99. package/template-workspace/pnpm-workspace.yaml.handlebars +12 -0
  100. package/template-workspace/scripts/bootstrap-agent-skills.mjs +96 -69
  101. package/templates/app/shell-frame.tsx +1 -2
  102. package/templates/app/ultramodern-route-head.tsx.handlebars +5 -6
  103. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +59 -7
  104. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mjs +339 -0
  105. package/templates/workspace-scripts/generate-public-surface-assets.mjs +245 -8
  106. package/templates/workspace-scripts/proof-cloudflare-version.mjs +276 -8
  107. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +35 -10
  108. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +164 -1
  109. package/templates/workspace-scripts/ultramodern-typecheck.mjs +4 -2
  110. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +949 -63
  111. /package/template-workspace/{.agents → .codex}/rstackjs-agent-skills-LICENSE +0 -0
  112. /package/template-workspace/{.agents → .codex}/skills/rsbuild-best-practices/SKILL.md +0 -0
  113. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/SKILL.md +0 -0
  114. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/command-map.md +0 -0
  115. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/common-analysis-patterns.md +0 -0
  116. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +0 -0
  117. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +0 -0
  118. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +0 -0
  119. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor.md +0 -0
  120. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +0 -0
  121. /package/template-workspace/{.agents → .codex}/skills/rslib-best-practices/SKILL.md +0 -0
  122. /package/template-workspace/{.agents → .codex}/skills/rslib-modern-package/SKILL.md +0 -0
  123. /package/template-workspace/{.agents → .codex}/skills/rspack-best-practices/SKILL.md +0 -0
  124. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/SKILL.md +0 -0
  125. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/bottlenecks.md +0 -0
  126. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/tracing-guide.md +0 -0
  127. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/scripts/analyze_trace.js +0 -0
  128. /package/template-workspace/{.agents → .codex}/skills/rstest-best-practices/SKILL.md +0 -0
@@ -1,17 +1,15 @@
1
1
  #!/usr/bin/env node
2
+ import crypto from 'node:crypto';
2
3
  import fs from 'node:fs';
3
4
  import path from 'node:path';
4
5
  import { fileURLToPath } from 'node:url';
5
6
  import { validateApp } from './ultramodern-cloudflare-proof.mjs';
6
7
 
7
8
  const workspaceRoot = path.resolve(
8
- path.dirname(fileURLToPath(import.meta.url)),
9
- '..',
10
- );
11
- const contractPath = path.join(
12
- workspaceRoot,
13
- '.modernjs/ultramodern-generated-contract.json',
9
+ process.env.ULTRAMODERN_WORKSPACE_ROOT ??
10
+ path.join(path.dirname(fileURLToPath(import.meta.url)), '..'),
14
11
  );
12
+ const compactConfigPath = path.join(workspaceRoot, '.modernjs/ultramodern.json');
15
13
  const defaultOut = path.join(
16
14
  workspaceRoot,
17
15
  '.codex/reports/cloudflare-version-proof/public-url-proof.json',
@@ -21,6 +19,276 @@ function readJson(filePath) {
21
19
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
22
20
  }
23
21
 
22
+ function toKebabCase(value) {
23
+ return String(value)
24
+ .trim()
25
+ .replace(/([a-z0-9])([A-Z])/gu, '$1-$2')
26
+ .replace(/[^a-zA-Z0-9._-]+/gu, '-')
27
+ .replace(/[._]+/gu, '-')
28
+ .toLowerCase()
29
+ .replace(/-+/gu, '-')
30
+ .replace(/^-+|-+$/gu, '');
31
+ }
32
+
33
+ function toPascalCase(value) {
34
+ return toKebabCase(value)
35
+ .split('-')
36
+ .filter(Boolean)
37
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
38
+ .join('');
39
+ }
40
+
41
+ function toEnvSegment(value) {
42
+ return toKebabCase(value).replace(/-/gu, '_').toUpperCase();
43
+ }
44
+
45
+ function normalizeRelativePath(value) {
46
+ return String(value ?? '').replace(/\\/gu, '/').replace(/^\.\/+/u, '');
47
+ }
48
+
49
+ function appNamespace(app) {
50
+ return app.kind === 'shell' ? 'shell' : (app.domain ?? app.id);
51
+ }
52
+
53
+ function normalizeCompactApp(rawApp) {
54
+ const id = String(rawApp.id);
55
+ const kind = rawApp.kind === 'vertical' ? 'vertical' : 'shell';
56
+ const appPath =
57
+ typeof rawApp.path === 'string'
58
+ ? normalizeRelativePath(rawApp.path)
59
+ : kind === 'shell'
60
+ ? 'apps/shell-super-app'
61
+ : `verticals/${toKebabCase(id)}`;
62
+ const packageSuffix =
63
+ typeof rawApp.packageSuffix === 'string'
64
+ ? rawApp.packageSuffix
65
+ : appPath.split('/').at(-1) ?? id;
66
+ const domain =
67
+ typeof rawApp.domain === 'string'
68
+ ? rawApp.domain
69
+ : kind === 'vertical'
70
+ ? packageSuffix
71
+ : undefined;
72
+ const moduleFederation =
73
+ rawApp.moduleFederation && typeof rawApp.moduleFederation === 'object'
74
+ ? rawApp.moduleFederation
75
+ : {};
76
+ const effectApi =
77
+ rawApp.effectApi && typeof rawApp.effectApi === 'object'
78
+ ? {
79
+ stem:
80
+ typeof rawApp.effectApi.stem === 'string'
81
+ ? rawApp.effectApi.stem
82
+ : domain ?? id,
83
+ prefix:
84
+ typeof rawApp.effectApi.prefix === 'string'
85
+ ? rawApp.effectApi.prefix
86
+ : `/${domain ?? id}-api`,
87
+ }
88
+ : undefined;
89
+
90
+ return {
91
+ id,
92
+ kind,
93
+ path: appPath,
94
+ packageSuffix,
95
+ domain,
96
+ mfName:
97
+ typeof moduleFederation.name === 'string'
98
+ ? moduleFederation.name
99
+ : kind === 'shell'
100
+ ? 'shellSuperApp'
101
+ : `vertical${toPascalCase(domain ?? id)}`,
102
+ effectApi,
103
+ };
104
+ }
105
+
106
+ function createBuildMarker(scope, app) {
107
+ return crypto
108
+ .createHash('sha256')
109
+ .update(`${scope}:${app.packageSuffix}:${app.id}:0.1.0`)
110
+ .digest('hex')
111
+ .slice(0, 16);
112
+ }
113
+
114
+ function createCloudflareSecurity() {
115
+ return {
116
+ enabled: true,
117
+ headers: {
118
+ referrerPolicy: 'strict-origin-when-cross-origin',
119
+ contentTypeOptions: 'nosniff',
120
+ permissionsPolicy:
121
+ 'camera=(), geolocation=(), microphone=(), payment=(), usb=()',
122
+ },
123
+ contentSecurityPolicy: {
124
+ mode: 'report-only',
125
+ directives: {
126
+ 'base-uri': [`'self'`],
127
+ 'connect-src': [`'self'`, 'https:', 'http:', 'wss:', 'ws:'],
128
+ 'default-src': [`'self'`],
129
+ 'font-src': [`'self'`, 'data:', 'https:', 'http:'],
130
+ 'form-action': [`'self'`],
131
+ 'frame-ancestors': [`'self'`],
132
+ 'img-src': [`'self'`, 'data:', 'blob:', 'https:', 'http:'],
133
+ 'manifest-src': [`'self'`, 'https:', 'http:'],
134
+ 'object-src': [`'none'`],
135
+ 'script-src': [
136
+ `'self'`,
137
+ `'unsafe-inline'`,
138
+ `'unsafe-eval'`,
139
+ 'https:',
140
+ 'http:',
141
+ 'blob:',
142
+ ],
143
+ 'style-src': [`'self'`, `'unsafe-inline'`, 'https:', 'http:'],
144
+ 'worker-src': [`'self'`, 'blob:'],
145
+ },
146
+ reason:
147
+ 'Report-only by default so Cloudflare Module Federation SSR can prove remote script, style, and connect compatibility before enforcement.',
148
+ },
149
+ noindex: {
150
+ workersDev: true,
151
+ localhost: true,
152
+ previewHostnames: [],
153
+ },
154
+ };
155
+ }
156
+
157
+ function createQualityGates() {
158
+ return {
159
+ publicRoutes: {
160
+ requireSitemapWhenPresent: true,
161
+ requireRobotsSitemapConsistency: true,
162
+ requireWebManifestWhenPresent: true,
163
+ },
164
+ statusCodes: {
165
+ notFoundRoute: '/__ultramodern-smoke-missing/nope',
166
+ unknownRouteStatus: 404,
167
+ },
168
+ indexing: {
169
+ previewNoindex: true,
170
+ productionPublicRoutesIndexable: true,
171
+ },
172
+ assets: {
173
+ cssPreloadRequired: true,
174
+ cssResponseRequired: true,
175
+ cacheControlRequiredForCss: true,
176
+ sourcemapsPubliclyReferenced: false,
177
+ },
178
+ budgets: {
179
+ ssrHtmlMaxBytes: 250_000,
180
+ mfManifestMaxBytes: 500_000,
181
+ localeJsonMaxBytes: 100_000,
182
+ sitemapXmlMaxBytes: 500_000,
183
+ cssAssetMaxBytes: 750_000,
184
+ },
185
+ csp: {
186
+ finalMode: 'report-only-dogfood',
187
+ decision:
188
+ 'Report-only remains the generated final mode until public smoke proof records MF SSR script/style/connect compatibility for the deployed surface.',
189
+ },
190
+ };
191
+ }
192
+
193
+ function createPublicHead() {
194
+ return {
195
+ alternates: {
196
+ hreflang: ['en', 'cs'],
197
+ xDefault: 'en',
198
+ },
199
+ };
200
+ }
201
+
202
+ function createPublicSurface() {
203
+ return {
204
+ publicRoutes: [],
205
+ routeEntries: [],
206
+ contentSources: [],
207
+ concreteUrlPaths: [],
208
+ };
209
+ }
210
+
211
+ function createCloudflareRoutes(app) {
212
+ return {
213
+ ssr: '/en',
214
+ mfManifest: '/mf-manifest.json',
215
+ locale: `/locales/en/${appNamespace(app)}.json`,
216
+ ...(app.effectApi
217
+ ? {
218
+ apiReadiness: `${app.effectApi.prefix}/${app.effectApi.stem}/readiness`,
219
+ }
220
+ : {}),
221
+ };
222
+ }
223
+
224
+ function createContractApp(config, app) {
225
+ const packageScope =
226
+ typeof config.workspace?.packageScope === 'string'
227
+ ? config.workspace.packageScope
228
+ : path.basename(workspaceRoot);
229
+ const compatibilityDate =
230
+ typeof config.deploy?.worker?.compatibilityDate === 'string'
231
+ ? config.deploy.worker.compatibilityDate
232
+ : '2026-06-02';
233
+
234
+ return {
235
+ id: app.id,
236
+ deploy: {
237
+ cloudflare: {
238
+ workerName: `${toKebabCase(packageScope)}-${app.packageSuffix}`.slice(
239
+ 0,
240
+ 63,
241
+ ),
242
+ publicUrlEnv: `ULTRAMODERN_PUBLIC_URL_${toEnvSegment(app.id)}`,
243
+ compatibilityDate,
244
+ compatibilityFlags: ['nodejs_compat', 'global_fetch_strictly_public'],
245
+ routes: createCloudflareRoutes(app),
246
+ security: createCloudflareSecurity(),
247
+ qualityGates: createQualityGates(),
248
+ },
249
+ },
250
+ i18n: {
251
+ namespace: appNamespace(app),
252
+ },
253
+ marker: {
254
+ appId: app.id,
255
+ build: createBuildMarker(packageScope, app),
256
+ },
257
+ routes: {
258
+ publicHead: createPublicHead(),
259
+ publicSurface: createPublicSurface(),
260
+ },
261
+ styling: {
262
+ federation: {
263
+ rootSelector: `[data-app-id="${app.id}"]`,
264
+ },
265
+ },
266
+ };
267
+ }
268
+
269
+ function synthesizeContractFromCompactConfig(config) {
270
+ const apps = Array.isArray(config.topology?.apps)
271
+ ? config.topology.apps.map(normalizeCompactApp)
272
+ : [];
273
+
274
+ return {
275
+ sourcePath: compactConfigPath,
276
+ apps: apps.map(app => createContractApp(config, app)),
277
+ };
278
+ }
279
+
280
+ function readGeneratedContractView() {
281
+ if (fs.existsSync(compactConfigPath)) {
282
+ return synthesizeContractFromCompactConfig(readJson(compactConfigPath));
283
+ }
284
+ throw new Error(
285
+ `Missing UltraModern config. Expected ${path.relative(
286
+ workspaceRoot,
287
+ compactConfigPath,
288
+ )}.`,
289
+ );
290
+ }
291
+
24
292
  function parseArgs(argv) {
25
293
  const parsed = {
26
294
  appId: undefined,
@@ -70,7 +338,7 @@ async function main(argv = process.argv.slice(2)) {
70
338
  return 0;
71
339
  }
72
340
 
73
- const contract = readJson(contractPath);
341
+ const contract = readGeneratedContractView();
74
342
  const apps = args.appId
75
343
  ? contract.apps.filter(app => app.id === args.appId)
76
344
  : contract.apps;
@@ -101,7 +369,7 @@ async function main(argv = process.argv.slice(2)) {
101
369
  schemaVersion: 1,
102
370
  generatedAt: new Date().toISOString(),
103
371
  status: results.length > 0 ? 'pass' : 'skipped',
104
- contractPath,
372
+ contractPath: contract.sourcePath ?? compactConfigPath,
105
373
  results,
106
374
  skipped,
107
375
  };
@@ -6,6 +6,20 @@ function normalizeUrlWithTrailingSlash(url) {
6
6
  return url.endsWith('/') ? url : `${url}/`;
7
7
  }
8
8
 
9
+ function resolveModuleFederationPublicPath(publicPath, manifestUrl) {
10
+ if (typeof publicPath !== 'string' || publicPath.trim().length === 0) {
11
+ return undefined;
12
+ }
13
+
14
+ try {
15
+ return normalizeUrlWithTrailingSlash(
16
+ new URL(publicPath.trim(), manifestUrl).toString(),
17
+ );
18
+ } catch {
19
+ return undefined;
20
+ }
21
+ }
22
+
9
23
  async function fetchText(url) {
10
24
  const response = await fetch(url);
11
25
  return {
@@ -464,7 +478,8 @@ async function validateSsrHead(evidence, app, publicUrl, ssrRoute, ssr) {
464
478
  async function validateNotFound(evidence, app, publicUrl) {
465
479
  const qualityGates = app.deploy?.cloudflare?.qualityGates ?? {};
466
480
  const notFoundRoute =
467
- qualityGates.statusCodes?.notFoundRoute ?? '/__ultramodern-smoke-missing';
481
+ qualityGates.statusCodes?.notFoundRoute ??
482
+ '/__ultramodern-smoke-missing/nope';
468
483
  const expectedStatus = qualityGates.statusCodes?.unknownRouteStatus ?? 404;
469
484
  const response = await fetchText(joinUrl(publicUrl, notFoundRoute));
470
485
  evidence.assertions.push({
@@ -721,7 +736,8 @@ async function validateModuleFederationManifestEvidence(evidence, app, publicUrl
721
736
  const budgets = qualityGates.budgets ?? {};
722
737
 
723
738
  const manifestRoute = routes.mfManifest ?? '/mf-manifest.json';
724
- const manifest = await fetchText(joinUrl(publicUrl, manifestRoute));
739
+ const manifestUrl = joinUrl(publicUrl, manifestRoute);
740
+ const manifest = await fetchText(manifestUrl);
725
741
  const manifestJson = parseMaybeJson(manifest.body);
726
742
  evidence.assertions.push({
727
743
  type: 'mf-manifest',
@@ -754,17 +770,26 @@ async function validateModuleFederationManifestEvidence(evidence, app, publicUrl
754
770
  manifest.accessControlAllowOrigin === '*',
755
771
  `${app.id} MF manifest is missing Cloudflare CORS headers`,
756
772
  );
757
- const expectedPublicPath = normalizeUrlWithTrailingSlash(publicUrl);
773
+ const expectedPublicPath = normalizeUrlWithTrailingSlash(
774
+ new URL('.', manifestUrl).toString(),
775
+ );
758
776
  const manifestPublicPath = manifestJson?.metaData?.publicPath;
777
+ const resolvedPublicPath = resolveModuleFederationPublicPath(
778
+ manifestPublicPath,
779
+ manifestUrl,
780
+ );
759
781
  evidence.assertions.push({
760
782
  type: 'mf-manifest-public-path',
761
783
  expected: expectedPublicPath,
762
784
  actual: manifestPublicPath,
763
- status: manifestPublicPath === expectedPublicPath ? 'pass' : 'fail',
785
+ resolved: resolvedPublicPath,
786
+ status: resolvedPublicPath === expectedPublicPath ? 'pass' : 'fail',
764
787
  });
765
788
  assert(
766
- manifestPublicPath === expectedPublicPath,
767
- `${app.id} MF manifest publicPath must resolve remote assets from ${expectedPublicPath}`,
789
+ resolvedPublicPath === expectedPublicPath,
790
+ `${app.id} MF manifest publicPath must resolve remote assets from ${expectedPublicPath}; got ${String(
791
+ manifestPublicPath,
792
+ )}`,
768
793
  );
769
794
  }
770
795
 
@@ -815,13 +840,13 @@ async function validateI18nEvidence(evidence, app, publicUrl, routes) {
815
840
  }
816
841
 
817
842
  async function validateReadinessEvidence(evidence, app, publicUrl, routes) {
818
- if (routes.effectReadiness) {
819
- const readiness = await fetchText(joinUrl(publicUrl, routes.effectReadiness));
843
+ if (routes.apiReadiness) {
844
+ const readiness = await fetchText(joinUrl(publicUrl, routes.apiReadiness));
820
845
  const readinessJson = parseMaybeJson(readiness.body);
821
846
  const apiMarker = markerFromJson(readinessJson);
822
847
  evidence.assertions.push({
823
848
  type: 'api-marker',
824
- route: routes.effectReadiness,
849
+ route: routes.apiReadiness,
825
850
  expected: app.marker?.build,
826
851
  actual: apiMarker,
827
852
  status: readiness.ok && apiMarker === app.marker?.build ? 'pass' : 'fail',
@@ -848,4 +873,4 @@ async function validateApp(app, publicUrl) {
848
873
  return evidence;
849
874
  }
850
875
 
851
- export { validateApp };
876
+ export { resolveModuleFederationPublicPath, validateApp };
@@ -6,6 +6,7 @@ const root = process.cwd();
6
6
  const defaultReportPath =
7
7
  '.codex/reports/performance-readiness/ultramodern-performance-readiness.json';
8
8
  const configPath = 'scripts/ultramodern-performance-readiness.config.mjs';
9
+ const compactConfigPath = '.modernjs/ultramodern.json';
9
10
  const optOutEnv = 'ULTRAMODERN_PERFORMANCE_READINESS_DIAGNOSTICS';
10
11
  const signalIds = [
11
12
  'bfcache',
@@ -60,6 +61,168 @@ const createSignal = (id, status, evidence) => ({
60
61
 
61
62
  const unique = values => new Set(values).size === values.length;
62
63
 
64
+ const toKebabCase = value =>
65
+ String(value)
66
+ .trim()
67
+ .replace(/([a-z0-9])([A-Z])/gu, '$1-$2')
68
+ .replace(/[^a-zA-Z0-9._-]+/gu, '-')
69
+ .replace(/[._]+/gu, '-')
70
+ .toLowerCase()
71
+ .replace(/-+/gu, '-')
72
+ .replace(/^-+|-+$/gu, '');
73
+
74
+ const toPascalCase = value =>
75
+ toKebabCase(value)
76
+ .split('-')
77
+ .filter(Boolean)
78
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
79
+ .join('');
80
+
81
+ const normalizeRelativePath = value =>
82
+ String(value ?? '').replace(/\\/gu, '/').replace(/^\.\/+/u, '');
83
+
84
+ const appNamespace = app => (app.kind === 'shell' ? 'shell' : (app.domain ?? app.id));
85
+
86
+ const normalizeCompactApp = rawApp => {
87
+ const id = String(rawApp.id);
88
+ const kind = rawApp.kind === 'vertical' ? 'vertical' : 'shell';
89
+ const appPath =
90
+ typeof rawApp.path === 'string'
91
+ ? normalizeRelativePath(rawApp.path)
92
+ : kind === 'shell'
93
+ ? 'apps/shell-super-app'
94
+ : `verticals/${toKebabCase(id)}`;
95
+ const packageSuffix =
96
+ typeof rawApp.packageSuffix === 'string'
97
+ ? rawApp.packageSuffix
98
+ : appPath.split('/').at(-1) ?? id;
99
+ const domain =
100
+ typeof rawApp.domain === 'string'
101
+ ? rawApp.domain
102
+ : kind === 'vertical'
103
+ ? packageSuffix
104
+ : undefined;
105
+ const moduleFederation =
106
+ rawApp.moduleFederation && typeof rawApp.moduleFederation === 'object'
107
+ ? rawApp.moduleFederation
108
+ : {};
109
+
110
+ return {
111
+ id,
112
+ kind,
113
+ path: appPath,
114
+ packageSuffix,
115
+ domain,
116
+ port:
117
+ typeof rawApp.port === 'number'
118
+ ? rawApp.port
119
+ : kind === 'shell'
120
+ ? 3020
121
+ : 3030,
122
+ mfName:
123
+ typeof moduleFederation.name === 'string'
124
+ ? moduleFederation.name
125
+ : kind === 'shell'
126
+ ? 'shellSuperApp'
127
+ : `vertical${toPascalCase(domain ?? id)}`,
128
+ moduleFederation: {
129
+ remotes: [],
130
+ verticalRefs: Array.isArray(moduleFederation.verticalRefs)
131
+ ? moduleFederation.verticalRefs.filter(ref => typeof ref === 'string')
132
+ : [],
133
+ },
134
+ };
135
+ };
136
+
137
+ const createRemoteContracts = (app, apps) =>
138
+ (app.moduleFederation?.verticalRefs ?? [])
139
+ .map(ref => apps.find(candidate => candidate.id === ref))
140
+ .filter(Boolean)
141
+ .map(remote => ({
142
+ id: remote.id,
143
+ name: remote.mfName,
144
+ manifestUrl: `http://localhost:${remote.port ?? 3030}/mf-manifest.json`,
145
+ }));
146
+
147
+ const createPerformanceReadinessContract = () => ({
148
+ schemaVersion: 1,
149
+ default: 'enabled',
150
+ mode: 'diagnostic',
151
+ scope: 'ultramodern-generated-and-framework-owned',
152
+ report: {
153
+ script: 'scripts/ultramodern-performance-readiness.mjs',
154
+ config: 'scripts/ultramodern-performance-readiness.config.mjs',
155
+ defaultPath: defaultReportPath,
156
+ deterministic: true,
157
+ },
158
+ signals: signalIds.map(id => ({ id })),
159
+ });
160
+
161
+ const createContractApp = (config, app, apps) => {
162
+ const compatibilityDate =
163
+ typeof config.deploy?.worker?.compatibilityDate === 'string'
164
+ ? config.deploy.worker.compatibilityDate
165
+ : '2026-06-02';
166
+
167
+ return {
168
+ id: app.id,
169
+ path: app.path,
170
+ config: {
171
+ plugins: [
172
+ 'appTools',
173
+ 'tanstackRouterPlugin',
174
+ 'i18nPlugin',
175
+ ...(app.kind === 'vertical' ? ['bffPlugin'] : []),
176
+ 'moduleFederationPlugin',
177
+ 'zephyrRspackPlugin',
178
+ ],
179
+ },
180
+ deploy: {
181
+ cloudflare: {
182
+ compatibilityDate,
183
+ compatibilityFlags: ['nodejs_compat', 'global_fetch_strictly_public'],
184
+ routes: {
185
+ ssr: '/en',
186
+ mfManifest: '/mf-manifest.json',
187
+ locale: `/locales/en/${appNamespace(app)}.json`,
188
+ },
189
+ qualityGates: {
190
+ assets: {
191
+ cacheControlRequiredForCss: true,
192
+ },
193
+ },
194
+ },
195
+ },
196
+ moduleFederation: {
197
+ remotes: createRemoteContracts(app, apps),
198
+ },
199
+ routes: {
200
+ localisedUrls: {},
201
+ publicSurface: {
202
+ artifactLifecycle: 'build-and-deploy-output',
203
+ },
204
+ },
205
+ };
206
+ };
207
+
208
+ const readGeneratedContractView = () => {
209
+ if (exists(compactConfigPath)) {
210
+ const compactConfig = readJson(compactConfigPath);
211
+ const apps = Array.isArray(compactConfig.topology?.apps)
212
+ ? compactConfig.topology.apps.map(normalizeCompactApp)
213
+ : [];
214
+ return {
215
+ sourcePath: compactConfigPath,
216
+ performanceReadiness: createPerformanceReadinessContract(),
217
+ apps: apps.map(app => createContractApp(compactConfig, app, apps)),
218
+ };
219
+ }
220
+
221
+ throw new Error(
222
+ `Missing UltraModern config. Expected ${compactConfigPath}.`,
223
+ );
224
+ };
225
+
63
226
  const appGeneratedFiles = app => [
64
227
  `${app.path}/modern.config.ts`,
65
228
  `${app.path}/module-federation.config.ts`,
@@ -181,7 +344,7 @@ const main = async () => {
181
344
  return;
182
345
  }
183
346
 
184
- const contract = readJson('.modernjs/ultramodern-generated-contract.json');
347
+ const contract = readGeneratedContractView();
185
348
  assert(
186
349
  contract.performanceReadiness?.default === 'enabled',
187
350
  'Generated contract must keep performance readiness diagnostics default-on',
@@ -9,11 +9,13 @@ import {
9
9
  mkdirSync,
10
10
  } from 'node:fs';
11
11
  import os from 'node:os';
12
- import { dirname, join } from 'node:path';
12
+ import { dirname, join, resolve } from 'node:path';
13
13
  import { fileURLToPath } from 'node:url';
14
14
 
15
15
  const args = process.argv.slice(2);
16
- const workspaceRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
16
+ const workspaceRoot = process.env.ULTRAMODERN_WORKSPACE_ROOT
17
+ ? resolve(process.env.ULTRAMODERN_WORKSPACE_ROOT)
18
+ : join(dirname(fileURLToPath(import.meta.url)), '..');
17
19
  const cpuCount = Math.max(
18
20
  1,
19
21
  typeof os.availableParallelism === 'function'