@bleedingdev/modern-js-create 3.2.0-ultramodern.31 → 3.2.0-ultramodern.33

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/index.js CHANGED
@@ -607,6 +607,9 @@ const modernPackageNames = [
607
607
  '@modern-js/runtime'
608
608
  ];
609
609
  const ULTRAMODERN_WORKSPACE_FLAG = '--ultramodern-workspace';
610
+ function isRecord(value) {
611
+ return null !== value && 'object' == typeof value && !Array.isArray(value);
612
+ }
610
613
  const shellApp = {
611
614
  id: 'shell-super-app',
612
615
  directory: 'apps/shell-super-app',
@@ -617,9 +620,9 @@ const shellApp = {
617
620
  port: 3020,
618
621
  mfName: 'shellSuperApp',
619
622
  remoteRefs: [
620
- 'remote-commerce',
621
- 'remote-identity',
622
- 'remote-design-system'
623
+ 'remote-explore',
624
+ 'remote-decide',
625
+ 'remote-checkout'
623
626
  ],
624
627
  ownership: {
625
628
  team: 'super-app-platform',
@@ -638,104 +641,123 @@ const shellApp = {
638
641
  };
639
642
  const remoteApps = [
640
643
  {
641
- id: 'remote-commerce',
642
- directory: 'apps/remotes/remote-commerce',
643
- packageSuffix: 'remote-commerce',
644
- displayName: 'Commerce Remote',
644
+ id: 'remote-explore',
645
+ directory: 'apps/remotes/remote-explore',
646
+ packageSuffix: 'remote-explore',
647
+ displayName: 'Explore Remote',
645
648
  kind: 'vertical',
646
- domain: 'commerce',
647
- portEnv: 'REMOTE_COMMERCE_PORT',
649
+ domain: 'explore',
650
+ portEnv: 'REMOTE_EXPLORE_PORT',
648
651
  port: 3021,
649
- mfName: 'remoteCommerce',
652
+ mfName: 'remoteExplore',
650
653
  exposes: {
654
+ './Footer': './src/components/footer.tsx',
655
+ './Header': './src/components/header.tsx',
656
+ './Recommendations': './src/components/recommendations.tsx',
651
657
  './Route': './src/remote-entry.tsx',
652
- './Widget': './src/components/commerce-widget.tsx'
658
+ './StorePicker': './src/components/store-picker.tsx'
653
659
  },
654
660
  effectApi: {
655
- stem: 'recommendations',
656
- prefix: '/commerce-api',
661
+ stem: 'explore',
662
+ prefix: '/explore-api',
657
663
  consumedBy: [
658
664
  shellApp.id,
659
- 'remote-commerce'
665
+ 'remote-explore'
660
666
  ]
661
667
  },
662
668
  ownership: {
663
- team: 'commerce-experience',
664
- slack: '#commerce-experience',
665
- pagerDuty: 'pd-commerce-experience',
666
- runbookRef: 'runbooks/wave2/remote-commerce.md',
667
- adrRef: 'docs/super-app-rfc-adr/wave2/reference-topology.md#remote-commerce',
669
+ team: 'tractor-explore',
670
+ slack: '#tractor-explore',
671
+ pagerDuty: 'pd-tractor-explore',
672
+ runbookRef: 'runbooks/wave2/remote-explore.md',
673
+ adrRef: 'docs/super-app-rfc-adr/wave2/reference-topology.md#remote-explore',
668
674
  blastRadius: {
669
- tier: 'tier-1-revenue-path',
675
+ tier: 'tier-1-tractor-discovery',
670
676
  references: [
671
- 'docs/super-app-rfc-adr/wave2/blast-radius.md#commerce',
672
- 'docs/super-app-rfc-adr/wave2/rollback.md#commerce-lkg'
677
+ 'docs/super-app-rfc-adr/wave2/blast-radius.md#explore',
678
+ 'docs/super-app-rfc-adr/wave2/rollback.md#explore-lkg'
673
679
  ]
674
680
  }
675
681
  }
676
682
  },
677
683
  {
678
- id: 'remote-identity',
679
- directory: 'apps/remotes/remote-identity',
680
- packageSuffix: 'remote-identity',
681
- displayName: 'Identity Remote',
684
+ id: 'remote-decide',
685
+ directory: 'apps/remotes/remote-decide',
686
+ packageSuffix: 'remote-decide',
687
+ displayName: 'Decide Remote',
682
688
  kind: 'vertical',
683
- domain: 'identity',
684
- portEnv: 'REMOTE_IDENTITY_PORT',
689
+ domain: 'decide',
690
+ portEnv: 'REMOTE_DECIDE_PORT',
685
691
  port: 3022,
686
- mfName: 'remoteIdentity',
692
+ mfName: 'remoteDecide',
693
+ remoteRefs: [
694
+ 'remote-explore',
695
+ 'remote-checkout'
696
+ ],
687
697
  exposes: {
688
- './Route': './src/remote-entry.tsx',
689
- './Widget': './src/components/identity-widget.tsx'
698
+ './ProductPage': './src/components/product-page.tsx',
699
+ './Route': './src/remote-entry.tsx'
690
700
  },
691
701
  effectApi: {
692
- stem: 'identity',
693
- prefix: '/identity-api',
702
+ stem: 'decide',
703
+ prefix: '/decide-api',
694
704
  consumedBy: [
695
705
  shellApp.id,
696
- 'remote-identity'
706
+ 'remote-decide'
697
707
  ]
698
708
  },
699
709
  ownership: {
700
- team: 'identity-platform',
701
- slack: '#identity-platform',
702
- pagerDuty: 'pd-identity-platform',
703
- runbookRef: 'runbooks/wave2/remote-identity.md',
704
- adrRef: 'docs/super-app-rfc-adr/wave2/reference-topology.md#remote-identity',
710
+ team: 'tractor-decide',
711
+ slack: '#tractor-decide',
712
+ pagerDuty: 'pd-tractor-decide',
713
+ runbookRef: 'runbooks/wave2/remote-decide.md',
714
+ adrRef: 'docs/super-app-rfc-adr/wave2/reference-topology.md#remote-decide',
705
715
  blastRadius: {
706
- tier: 'tier-0-authentication',
716
+ tier: 'tier-1-tractor-configuration',
707
717
  references: [
708
- 'docs/super-app-rfc-adr/wave2/blast-radius.md#identity',
709
- 'docs/super-app-rfc-adr/wave2/rollback.md#identity-lkg'
718
+ 'docs/super-app-rfc-adr/wave2/blast-radius.md#decide',
719
+ 'docs/super-app-rfc-adr/wave2/rollback.md#decide-lkg'
710
720
  ]
711
721
  }
712
722
  }
713
723
  },
714
724
  {
715
- id: 'remote-design-system',
716
- directory: 'apps/remotes/remote-design-system',
717
- packageSuffix: 'remote-design-system',
718
- displayName: 'Design System Remote',
719
- kind: 'horizontal-design-system',
720
- domain: 'design-system',
721
- portEnv: 'REMOTE_DESIGN_SYSTEM_PORT',
725
+ id: 'remote-checkout',
726
+ directory: 'apps/remotes/remote-checkout',
727
+ packageSuffix: 'remote-checkout',
728
+ displayName: 'Checkout Remote',
729
+ kind: 'vertical',
730
+ domain: 'checkout',
731
+ portEnv: 'REMOTE_CHECKOUT_PORT',
722
732
  port: 3023,
723
- mfName: 'remoteDesignSystem',
733
+ mfName: 'remoteCheckout',
724
734
  exposes: {
725
- './Button': './src/components/button.tsx',
726
- './tokens': './src/tokens.ts'
735
+ './AddToCart': './src/components/add-to-cart.tsx',
736
+ './CartPage': './src/components/cart-page.tsx',
737
+ './CheckoutPage': './src/components/checkout-page.tsx',
738
+ './MiniCart': './src/components/mini-cart.tsx',
739
+ './Route': './src/remote-entry.tsx',
740
+ './ThanksPage': './src/components/thanks-page.tsx'
741
+ },
742
+ effectApi: {
743
+ stem: 'checkout',
744
+ prefix: '/checkout-api',
745
+ consumedBy: [
746
+ shellApp.id,
747
+ 'remote-checkout'
748
+ ]
727
749
  },
728
750
  ownership: {
729
- team: 'design-platform',
730
- slack: '#design-platform',
731
- pagerDuty: 'pd-design-platform',
732
- runbookRef: 'runbooks/wave2/remote-design-system.md',
733
- adrRef: 'docs/super-app-rfc-adr/wave2/reference-topology.md#remote-design-system',
751
+ team: 'tractor-checkout',
752
+ slack: '#tractor-checkout',
753
+ pagerDuty: 'pd-tractor-checkout',
754
+ runbookRef: 'runbooks/wave2/remote-checkout.md',
755
+ adrRef: 'docs/super-app-rfc-adr/wave2/reference-topology.md#remote-checkout',
734
756
  blastRadius: {
735
- tier: 'tier-0-shared-ui',
757
+ tier: 'tier-1-tractor-purchase',
736
758
  references: [
737
- 'docs/super-app-rfc-adr/wave2/blast-radius.md#design-system',
738
- 'docs/super-app-rfc-adr/wave2/rollback.md#design-system-pins'
759
+ 'docs/super-app-rfc-adr/wave2/blast-radius.md#checkout',
760
+ 'docs/super-app-rfc-adr/wave2/rollback.md#checkout-lkg'
739
761
  ]
740
762
  }
741
763
  }
@@ -1100,11 +1122,11 @@ function createRootPackageJson(scope, packageSource) {
1100
1122
  type: 'module',
1101
1123
  packageManager: `pnpm@${PNPM_VERSION}`,
1102
1124
  scripts: {
1103
- dev: `pnpm --parallel --filter ${ultramodern_workspace_packageName(scope, shellApp.packageSuffix)} --filter ${ultramodern_workspace_packageName(scope, 'remote-commerce')} --filter ${ultramodern_workspace_packageName(scope, 'remote-identity')} --filter ${ultramodern_workspace_packageName(scope, 'remote-design-system')} dev`,
1125
+ dev: `pnpm --parallel --filter ${ultramodern_workspace_packageName(scope, shellApp.packageSuffix)} --filter ${ultramodern_workspace_packageName(scope, 'remote-explore')} --filter ${ultramodern_workspace_packageName(scope, 'remote-decide')} --filter ${ultramodern_workspace_packageName(scope, 'remote-checkout')} dev`,
1104
1126
  'dev:shell': `pnpm --filter ${ultramodern_workspace_packageName(scope, shellApp.packageSuffix)} dev`,
1105
- 'dev:commerce': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-commerce')} dev`,
1106
- 'dev:identity': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-identity')} dev`,
1107
- 'dev:design-system': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-design-system')} dev`,
1127
+ 'dev:explore': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-explore')} dev`,
1128
+ 'dev:decide': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-decide')} dev`,
1129
+ 'dev:checkout': `pnpm --filter ${ultramodern_workspace_packageName(scope, 'remote-checkout')} dev`,
1108
1130
  build: 'pnpm -r --filter "./apps/remotes/**" run build && pnpm --filter "./apps/shell-super-app" run build && pnpm ultramodern:assert-mf-types',
1109
1131
  format: 'oxfmt .',
1110
1132
  'format:check': 'oxfmt --check .',
@@ -1112,6 +1134,8 @@ function createRootPackageJson(scope, packageSource) {
1112
1134
  'lint:fix': 'oxlint . --fix',
1113
1135
  typecheck: `pnpm -r --filter "@${scope}/*" typecheck`,
1114
1136
  'cloudflare:build': 'pnpm -r --filter "./apps/remotes/**" run cloudflare:build && pnpm --filter "./apps/shell-super-app" run cloudflare:build && pnpm ultramodern:assert-mf-types',
1137
+ 'cloudflare:deploy': 'pnpm -r --filter "./apps/remotes/**" run cloudflare:deploy && pnpm --filter "./apps/shell-super-app" run cloudflare:deploy',
1138
+ 'cloudflare:proof': "node ./scripts/proof-cloudflare-version.mjs --out .codex/reports/cloudflare-version-proof/public-url-proof.json",
1115
1139
  'skills:install': "node ./scripts/bootstrap-agent-skills.mjs",
1116
1140
  'skills:check': "node ./scripts/bootstrap-agent-skills.mjs --check",
1117
1141
  'agents:refs:install': "node ./scripts/setup-agent-reference-repos.mjs",
@@ -1158,13 +1182,61 @@ function remoteDependencyAlias(remote) {
1158
1182
  function zephyrRemoteDependency(scope, remote) {
1159
1183
  return `${ultramodern_workspace_packageName(scope, remote.packageSuffix)}@workspace:*`;
1160
1184
  }
1185
+ function resolveRemoteRefs(app, remotes = remoteApps) {
1186
+ const remoteRefs = app.remoteRefs ?? [];
1187
+ return remoteRefs.map((remoteRef)=>remotes.find((remote)=>remote.id === remoteRef)).filter((remote)=>void 0 !== remote);
1188
+ }
1189
+ function createModuleFederationRemoteContracts(app, remotes = remoteApps) {
1190
+ return resolveRemoteRefs(app, remotes).map((remote)=>({
1191
+ id: remote.id,
1192
+ alias: remoteDependencyAlias(remote),
1193
+ name: remote.mfName,
1194
+ manifestEnv: createRemoteManifestEnv(remote),
1195
+ manifestUrl: `http://localhost:${remote.port}/mf-manifest.json`
1196
+ }));
1197
+ }
1161
1198
  function createZephyrDependencies(scope, app, remotes = remoteApps) {
1162
- if ('shell' !== app.kind) return {};
1163
- return Object.fromEntries(remotes.map((remote)=>[
1199
+ if (!app.remoteRefs?.length) return {};
1200
+ return Object.fromEntries(resolveRemoteRefs(app, remotes).map((remote)=>[
1164
1201
  remoteDependencyAlias(remote),
1165
1202
  zephyrRemoteDependency(scope, remote)
1166
1203
  ]));
1167
1204
  }
1205
+ function createCloudflareWorkerName(scope, app) {
1206
+ return toKebabCase(`${scope}-${app.packageSuffix}`).slice(0, 63);
1207
+ }
1208
+ function createCloudflarePublicUrlEnv(app) {
1209
+ return `ULTRAMODERN_PUBLIC_URL_${toEnvSegment(app.id)}`;
1210
+ }
1211
+ function createCloudflareProofRoute(app) {
1212
+ const languageRoutes = createLocalisedUrlsMap(app);
1213
+ const firstCanonicalPath = Object.keys(languageRoutes)[0];
1214
+ const localizedPath = firstCanonicalPath && isRecord(languageRoutes[firstCanonicalPath]) ? languageRoutes[firstCanonicalPath].en : void 0;
1215
+ return {
1216
+ ssr: localizedPath ?? '/en',
1217
+ mfManifest: '/mf-manifest.json',
1218
+ locale: `/locales/en/${appI18nNamespace(app)}.json`,
1219
+ ...appHasEffectApi(app) ? {
1220
+ effectReadiness: `${effectApiPrefix(app)}/effect/${effectApiStem(app)}/readiness`
1221
+ } : {}
1222
+ };
1223
+ }
1224
+ function createCloudflareDeployContract(scope, app) {
1225
+ return {
1226
+ target: 'cloudflare',
1227
+ workerName: createCloudflareWorkerName(scope, app),
1228
+ publicUrlEnv: createCloudflarePublicUrlEnv(app),
1229
+ compatibilityFlags: [
1230
+ 'nodejs_compat'
1231
+ ],
1232
+ assetsBinding: 'ASSETS',
1233
+ routes: createCloudflareProofRoute(app),
1234
+ evidence: {
1235
+ proofScript: "scripts/proof-cloudflare-version.mjs",
1236
+ reportDefault: '.codex/reports/cloudflare-version-proof/public-url-proof.json'
1237
+ }
1238
+ };
1239
+ }
1168
1240
  function createTsConfigBase() {
1169
1241
  return {
1170
1242
  compilerOptions: {
@@ -1234,7 +1306,9 @@ function createAppPackage(scope, app, packageSource, enableTailwind) {
1234
1306
  dev: 'modern dev',
1235
1307
  build: app.exposes ? `modern build && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mjs` : 'modern build',
1236
1308
  'cloudflare:build': 'MODERNJS_DEPLOY=cloudflare modern build && MODERNJS_DEPLOY=cloudflare modern deploy',
1309
+ 'cloudflare:deploy': 'MODERNJS_DEPLOY=cloudflare modern deploy',
1237
1310
  'cloudflare:preview': 'MODERNJS_DEPLOY=cloudflare modern build && MODERNJS_DEPLOY=cloudflare modern deploy && wrangler dev --config .output/wrangler.json',
1311
+ 'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mjs --app ${app.id}`,
1238
1312
  serve: 'modern serve',
1239
1313
  typecheck: effectTsgoTypecheckCommand
1240
1314
  },
@@ -1255,6 +1329,9 @@ function createAppPackage(scope, app, packageSource, enableTailwind) {
1255
1329
  './effect/client': `./src/effect/${app.effectApi.stem}-client.ts`,
1256
1330
  './shared/effect/api': './shared/effect/api.ts'
1257
1331
  };
1332
+ else if ('shell' === app.kind) packageJson.exports = {
1333
+ './effect/clients': './src/effect/recommendations-client.ts'
1334
+ };
1258
1335
  return packageJson;
1259
1336
  }
1260
1337
  function createServicePackage(scope, packageSource, enableTailwind, service = effectService) {
@@ -1315,12 +1392,16 @@ function createSharedPackage(scope, id, description, packageSource) {
1315
1392
  "@typescript/native-preview": TYPESCRIPT_NATIVE_PREVIEW_VERSION
1316
1393
  }
1317
1394
  };
1395
+ if ('shared-design-tokens' === id) packageJson.exports = {
1396
+ ...packageJson.exports,
1397
+ './tokens.css': './src/tokens.css'
1398
+ };
1318
1399
  if ('shared-effect-api' === id) packageJson.dependencies = {
1319
1400
  '@modern-js/plugin-bff': modernPackageSpecifier('@modern-js/plugin-bff', packageSource)
1320
1401
  };
1321
1402
  return packageJson;
1322
1403
  }
1323
- function createAppModernConfig(app) {
1404
+ function createAppModernConfig(scope, app) {
1324
1405
  const bffImport = appHasEffectApi(app) ? "import { bffPlugin } from '@modern-js/plugin-bff';\n" : '';
1325
1406
  const bffConfig = appHasEffectApi(app) ? ` bff: {
1326
1407
  effect: {
@@ -1343,6 +1424,7 @@ ${bffImport}import { i18nPlugin } from '@modern-js/plugin-i18n';
1343
1424
  import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
1344
1425
  import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
1345
1426
  import { withZephyr as withZephyrRspack } from 'zephyr-rspack-plugin';
1427
+ import { ultramodernLocalisedUrls } from './src/routes/ultramodern-route-metadata';
1346
1428
 
1347
1429
  type ZephyrRspackConfig = Parameters<ReturnType<typeof withZephyrRspack>>[0];
1348
1430
 
@@ -1361,22 +1443,12 @@ const zephyrRspackPlugin = () => ({
1361
1443
  });
1362
1444
 
1363
1445
  const appId = '${app.id}';
1446
+ const cloudflareWorkerName = '${createCloudflareWorkerName(scope, app)}';
1364
1447
  const port = Number(process.env['${app.portEnv}'] ?? ${app.port});
1365
- const configuredSiteUrl = process.env['MODERN_PUBLIC_SITE_URL'];
1366
- const hasConfiguredSiteUrl =
1367
- typeof configuredSiteUrl === 'string' && configuredSiteUrl.length > 0;
1368
- const isProductionBuild =
1369
- process.env['NODE_ENV'] === 'production' || process.argv.includes('build');
1370
-
1371
- if (isProductionBuild && !hasConfiguredSiteUrl) {
1372
- throw new Error(
1373
- 'MODERN_PUBLIC_SITE_URL must be set for production builds so canonical and hreflang URLs use the deployed origin.',
1374
- );
1375
- }
1376
-
1377
- const siteUrl = hasConfiguredSiteUrl
1378
- ? configuredSiteUrl
1379
- : \`http://localhost:\${port}\`;
1448
+ const siteUrl =
1449
+ process.env['MODERN_PUBLIC_SITE_URL'] ??
1450
+ process.env['${createCloudflarePublicUrlEnv(app)}'] ??
1451
+ \`http://localhost:\${port}\`;
1380
1452
 
1381
1453
  export default defineConfig(
1382
1454
  presetUltramodern(
@@ -1403,13 +1475,14 @@ ${bffConfig} output: {
1403
1475
  tanstackRouterPlugin(),
1404
1476
  i18nPlugin({
1405
1477
  backend: {
1406
- enabled: false,
1478
+ enabled: true,
1407
1479
  },
1408
1480
  reactI18next: false,
1409
1481
  localeDetection: {
1410
1482
  fallbackLanguage: 'en',
1411
1483
  languages: ['en', 'cs'],
1412
1484
  localePathRedirect: true,
1485
+ localisedUrls: ultramodernLocalisedUrls as Record<string, Record<string, string>>,
1413
1486
  ignoreRedirectRoutes: [
1414
1487
  '/@mf-types',
1415
1488
  '/bundles',
@@ -1442,6 +1515,7 @@ ${bffPluginEntry} moduleFederationPlugin(),
1442
1515
  deploy: {
1443
1516
  target: 'cloudflare',
1444
1517
  worker: {
1518
+ name: cloudflareWorkerName,
1445
1519
  ssr: true,
1446
1520
  },
1447
1521
  },
@@ -1510,13 +1584,24 @@ ${entries.map(([key, entryValue])=>` '${key}': '${entryValue}',`).join('\n')}
1510
1584
  function createRemoteManifestEnv(remote) {
1511
1585
  return `REMOTE_${toEnvSegment(remote.domain ?? remote.id)}_MF_MANIFEST`;
1512
1586
  }
1513
- function createShellModuleFederationConfig(remotes = remoteApps) {
1514
- const remoteEntries = remotes.map((remote)=>{
1587
+ function createModuleFederationRemotesConfig(app, remotes = remoteApps) {
1588
+ const remoteEntries = resolveRemoteRefs(app, remotes).map((remote)=>{
1515
1589
  const key = remoteDependencyAlias(remote);
1516
1590
  return ` ${key}:
1517
1591
  process.env['${createRemoteManifestEnv(remote)}'] ??
1518
1592
  '${remote.mfName}@http://localhost:${remote.port}/mf-manifest.json',`;
1519
1593
  }).join('\n');
1594
+ if (!remoteEntries) return '';
1595
+ return ` remotes: {
1596
+ ${remoteEntries}
1597
+ },
1598
+ `;
1599
+ }
1600
+ function createShellModuleFederationConfig(remotes = remoteApps) {
1601
+ const shellHost = {
1602
+ ...shellApp,
1603
+ remoteRefs: remotes.map((remote)=>remote.id)
1604
+ };
1520
1605
  return `// @effect-diagnostics nodeBuiltinImport:off processEnv:off
1521
1606
  import { createRequire } from 'node:module';
1522
1607
  import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
@@ -1540,10 +1625,7 @@ export default createModuleFederationConfig({
1540
1625
  },
1541
1626
  filename: 'remoteEntry.js',
1542
1627
  name: '${shellApp.mfName}',
1543
- remotes: {
1544
- ${remoteEntries}
1545
- },
1546
- ${createSharedModuleFederationConfig()},
1628
+ ${createModuleFederationRemotesConfig(shellHost, remotes)}${createSharedModuleFederationConfig()},
1547
1629
  });
1548
1630
  `;
1549
1631
  }
@@ -1570,7 +1652,7 @@ export const ultramodernApiMarker = {
1570
1652
  } as const;
1571
1653
  `;
1572
1654
  }
1573
- function createRemoteModuleFederationConfig(app) {
1655
+ function createRemoteModuleFederationConfig(app, remotes = remoteApps) {
1574
1656
  const exposes = formatTsObjectLiteral(app.exposes ?? {});
1575
1657
  return `// @effect-diagnostics nodeBuiltinImport:off
1576
1658
  import { createRequire } from 'node:module';
@@ -1596,12 +1678,248 @@ export default createModuleFederationConfig({
1596
1678
  exposes: ${exposes},
1597
1679
  filename: 'remoteEntry.js',
1598
1680
  name: '${app.mfName}',
1599
- ${createSharedModuleFederationConfig()},
1681
+ ${createModuleFederationRemotesConfig(app, remotes)}${createSharedModuleFederationConfig()},
1600
1682
  });
1601
1683
  `;
1602
1684
  }
1603
- function remoteWidgetFile(app) {
1604
- return `${app.domain ?? app.id.replace(/^remote-/, '')}-widget`;
1685
+ function appI18nNamespace(app) {
1686
+ return 'shell' === app.kind ? 'shell' : app.domain ?? app.id;
1687
+ }
1688
+ function createRouteOwnedI18nPaths(app) {
1689
+ const namespace = appI18nNamespace(app);
1690
+ const base = {
1691
+ mfBoundaryId: app.mfName,
1692
+ namespace,
1693
+ ownerAppId: app.id
1694
+ };
1695
+ if ('shell' === app.kind) return [
1696
+ {
1697
+ ...base,
1698
+ canonicalPath: '/',
1699
+ id: 'shell-home',
1700
+ localisedPaths: {
1701
+ cs: '/',
1702
+ en: '/'
1703
+ },
1704
+ titleKey: 'shell.title'
1705
+ }
1706
+ ];
1707
+ if ('explore' === app.domain) return [
1708
+ {
1709
+ ...base,
1710
+ canonicalPath: '/',
1711
+ id: 'explore-home',
1712
+ localisedPaths: {
1713
+ cs: '/',
1714
+ en: '/'
1715
+ },
1716
+ titleKey: 'explore.title'
1717
+ },
1718
+ {
1719
+ ...base,
1720
+ canonicalPath: '/tractors',
1721
+ id: 'explore-listing',
1722
+ localisedPaths: {
1723
+ cs: '/traktory',
1724
+ en: '/tractors'
1725
+ },
1726
+ titleKey: 'explore.routes.listing'
1727
+ },
1728
+ {
1729
+ ...base,
1730
+ canonicalPath: '/stores',
1731
+ id: 'explore-store-picker',
1732
+ localisedPaths: {
1733
+ cs: '/prodejci',
1734
+ en: '/stores'
1735
+ },
1736
+ titleKey: 'explore.routes.storePicker'
1737
+ },
1738
+ {
1739
+ ...base,
1740
+ canonicalPath: '/unavailable',
1741
+ id: 'explore-unavailable',
1742
+ localisedPaths: {
1743
+ cs: '/nedostupne',
1744
+ en: '/unavailable'
1745
+ },
1746
+ titleKey: 'explore.routes.unavailable'
1747
+ }
1748
+ ];
1749
+ if ('decide' === app.domain) return [
1750
+ {
1751
+ ...base,
1752
+ canonicalPath: '/',
1753
+ id: 'decide-home',
1754
+ localisedPaths: {
1755
+ cs: '/',
1756
+ en: '/'
1757
+ },
1758
+ titleKey: 'decide.title'
1759
+ },
1760
+ {
1761
+ ...base,
1762
+ canonicalPath: '/tractors',
1763
+ id: 'decide-listing-parent',
1764
+ localisedPaths: {
1765
+ cs: '/traktory',
1766
+ en: '/tractors'
1767
+ },
1768
+ titleKey: 'decide.routes.listing'
1769
+ },
1770
+ {
1771
+ ...base,
1772
+ canonicalPath: '/tractors/:slug',
1773
+ id: 'decide-product-detail',
1774
+ localisedPaths: {
1775
+ cs: '/traktory/:slug',
1776
+ en: '/tractors/:slug'
1777
+ },
1778
+ titleKey: 'decide.routes.productDetail'
1779
+ },
1780
+ {
1781
+ ...base,
1782
+ canonicalPath: '/unavailable',
1783
+ id: 'decide-unavailable',
1784
+ localisedPaths: {
1785
+ cs: '/nedostupne',
1786
+ en: '/unavailable'
1787
+ },
1788
+ titleKey: 'decide.routes.unavailable'
1789
+ }
1790
+ ];
1791
+ if ('checkout' === app.domain) return [
1792
+ {
1793
+ ...base,
1794
+ canonicalPath: '/',
1795
+ id: 'checkout-home',
1796
+ localisedPaths: {
1797
+ cs: '/',
1798
+ en: '/'
1799
+ },
1800
+ titleKey: 'checkout.title'
1801
+ },
1802
+ {
1803
+ ...base,
1804
+ canonicalPath: '/cart',
1805
+ id: 'checkout-cart',
1806
+ localisedPaths: {
1807
+ cs: '/kosik',
1808
+ en: '/cart'
1809
+ },
1810
+ titleKey: 'checkout.routes.cart'
1811
+ },
1812
+ {
1813
+ ...base,
1814
+ canonicalPath: '/checkout',
1815
+ id: 'checkout-start',
1816
+ localisedPaths: {
1817
+ cs: '/pokladna',
1818
+ en: '/checkout'
1819
+ },
1820
+ titleKey: 'checkout.routes.checkout'
1821
+ },
1822
+ {
1823
+ ...base,
1824
+ canonicalPath: '/checkout/thank-you',
1825
+ id: 'checkout-thank-you-parent',
1826
+ localisedPaths: {
1827
+ cs: '/pokladna/dekujeme',
1828
+ en: '/checkout/thank-you'
1829
+ },
1830
+ titleKey: 'checkout.routes.thankYou'
1831
+ },
1832
+ {
1833
+ ...base,
1834
+ canonicalPath: '/checkout/thank-you/:orderId?',
1835
+ id: 'checkout-thank-you',
1836
+ localisedPaths: {
1837
+ cs: '/pokladna/dekujeme/:orderId?',
1838
+ en: '/checkout/thank-you/:orderId?'
1839
+ },
1840
+ titleKey: 'checkout.routes.thankYou'
1841
+ },
1842
+ {
1843
+ ...base,
1844
+ canonicalPath: '/unavailable',
1845
+ id: 'checkout-unavailable',
1846
+ localisedPaths: {
1847
+ cs: '/nedostupne',
1848
+ en: '/unavailable'
1849
+ },
1850
+ titleKey: 'checkout.routes.unavailable'
1851
+ }
1852
+ ];
1853
+ return [
1854
+ {
1855
+ ...base,
1856
+ canonicalPath: '/',
1857
+ id: `${app.id}-home`,
1858
+ localisedPaths: {
1859
+ cs: '/',
1860
+ en: '/'
1861
+ },
1862
+ titleKey: `${namespace}.title`
1863
+ }
1864
+ ];
1865
+ }
1866
+ function createLocalisedUrlsMap(app) {
1867
+ return Object.fromEntries(createRouteOwnedI18nPaths(app).filter((route)=>'/' !== route.canonicalPath).map((route)=>[
1868
+ route.canonicalPath,
1869
+ route.localisedPaths
1870
+ ]));
1871
+ }
1872
+ function createRouteMetadataModule(app) {
1873
+ const routes = createRouteOwnedI18nPaths(app);
1874
+ const localisedUrls = createLocalisedUrlsMap(app);
1875
+ const namespace = appI18nNamespace(app);
1876
+ return `export const ultramodernRouteNamespace = '${namespace}' as const;
1877
+
1878
+ export const ultramodernRouteMetadata = ${JSON.stringify(routes, null, 2)} as const;
1879
+
1880
+ export const ultramodernLocalisedUrls = ${JSON.stringify(localisedUrls, null, 2)} as const;
1881
+
1882
+ export const ultramodernRouteConfig = {
1883
+ source: 'route-owned',
1884
+ namespace: ultramodernRouteNamespace,
1885
+ localisedUrls: ultramodernLocalisedUrls,
1886
+ routes: ultramodernRouteMetadata,
1887
+ } as const;
1888
+ `;
1889
+ }
1890
+ function routeSegmentToDirectory(segment) {
1891
+ if (segment.startsWith(':')) {
1892
+ const name = segment.slice(1).replace(/\?$/u, '');
1893
+ return segment.endsWith('?') ? `[${name}$]` : `[${name}]`;
1894
+ }
1895
+ return segment;
1896
+ }
1897
+ function createRoutePageFilePath(app, canonicalPath) {
1898
+ const segments = canonicalPath.split('/').filter(Boolean).map(routeSegmentToDirectory);
1899
+ return `${app.directory}/src/routes/[lang]/${[
1900
+ ...segments,
1901
+ 'page.tsx'
1902
+ ].join('/')}`;
1903
+ }
1904
+ function createRouteAliasPage(canonicalPath) {
1905
+ const depth = canonicalPath.split('/').filter(Boolean).length;
1906
+ const rootPageImport = `${'../'.repeat(depth)}page`;
1907
+ return `export { default } from '${rootPageImport}';
1908
+ `;
1909
+ }
1910
+ function createAppEnvDts(app, remotes = remoteApps) {
1911
+ const remoteModuleDeclarations = resolveRemoteRefs(app, remotes).flatMap((remote)=>Object.keys(remote.exposes ?? {}).filter((expose)=>'./Route' !== expose).map((expose)=>{
1912
+ const moduleName = `${remoteDependencyAlias(remote)}/${expose.replace(/^\.\//u, '')}`;
1913
+ return `declare module '${moduleName}' {
1914
+ const Component: import('react').ComponentType<Record<string, never>>;
1915
+ export default Component;
1916
+ }
1917
+ `;
1918
+ })).join('\n');
1919
+ return `/// <reference types='@modern-js/app-tools/types' />
1920
+
1921
+ declare const ULTRAMODERN_SITE_URL: string;
1922
+ ${remoteModuleDeclarations ? `\n${remoteModuleDeclarations}` : ''}`;
1605
1923
  }
1606
1924
  function createServiceModernConfigFor(service = effectService) {
1607
1925
  return `// @effect-diagnostics processEnv:off
@@ -1639,16 +1957,20 @@ export default defineConfig(
1639
1957
  `;
1640
1958
  }
1641
1959
  function createAppRuntimeConfig(app) {
1960
+ const namespace = appI18nNamespace(app);
1642
1961
  const resources = {
1643
1962
  cs: {
1963
+ [namespace]: createAppLocaleMessages(app, 'cs'),
1644
1964
  translation: createAppLocaleMessages(app, 'cs')
1645
1965
  },
1646
1966
  en: {
1967
+ [namespace]: createAppLocaleMessages(app, 'en'),
1647
1968
  translation: createAppLocaleMessages(app, 'en')
1648
1969
  }
1649
1970
  };
1650
1971
  return `import { defineRuntimeConfig } from '@modern-js/runtime';
1651
1972
  import { createInstance } from 'i18next';
1973
+ import { ultramodernRouteNamespace } from './routes/ultramodern-route-metadata';
1652
1974
 
1653
1975
  const i18nInstance = createInstance();
1654
1976
 
@@ -1656,12 +1978,12 @@ export default defineRuntimeConfig({
1656
1978
  i18n: {
1657
1979
  i18nInstance,
1658
1980
  initOptions: {
1659
- defaultNS: 'translation',
1981
+ defaultNS: ultramodernRouteNamespace,
1660
1982
  fallbackLng: 'en',
1661
1983
  interpolation: {
1662
1984
  escapeValue: false,
1663
1985
  },
1664
- ns: ['translation'],
1986
+ ns: [ultramodernRouteNamespace, 'translation'],
1665
1987
  resources: ${JSON.stringify(resources, null, 8).split('\n').join('\n ')},
1666
1988
  supportedLngs: ['en', 'cs'],
1667
1989
  },
@@ -1672,10 +1994,16 @@ export default defineRuntimeConfig({
1672
1994
  });
1673
1995
  `;
1674
1996
  }
1675
- function createAppStyles(enableTailwind) {
1676
- return `${enableTailwind ? "@import 'tailwindcss';\n\n" : ''}:root {
1677
- color: #10231c;
1678
- background: #f1eadc;
1997
+ function createCssTokenImport(scope) {
1998
+ return `@import '${ultramodern_workspace_packageName(scope, 'shared-design-tokens')}/tokens.css';\n`;
1999
+ }
2000
+ function createShellStyles(enableTailwind, scope) {
2001
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2002
+
2003
+ @layer ultramodern-shell-base {
2004
+ :root {
2005
+ color: var(--um-color-foreground);
2006
+ background: var(--um-color-canvas);
1679
2007
  font-family:
1680
2008
  Geist,
1681
2009
  Inter,
@@ -1703,9 +2031,52 @@ nav {
1703
2031
  }
1704
2032
 
1705
2033
  a {
1706
- color: #166b4b;
2034
+ color: var(--um-color-link);
2035
+ }
2036
+ }
2037
+
2038
+ @layer ultramodern-shell-overlay {
2039
+ .boundary-overlay {
2040
+ inset: 0;
2041
+ pointer-events: none;
2042
+ position: fixed;
2043
+ z-index: 70;
2044
+ }
2045
+
2046
+ .boundary-overlay__box {
2047
+ border: 0.0625rem solid var(--boundary-color);
2048
+ border-radius: 0.55rem;
2049
+ box-shadow:
2050
+ 0 0 0 0.0625rem rgba(255, 255, 255, 0.72),
2051
+ 0 0.35rem 1.25rem color-mix(in srgb, var(--boundary-color) 20%, transparent);
2052
+ position: fixed;
2053
+ }
2054
+
2055
+ .boundary-overlay__label {
2056
+ background: color-mix(in srgb, var(--boundary-color) 88%, white);
2057
+ border-radius: 999px;
2058
+ color: #0b0a08;
2059
+ font-size: 0.7rem;
2060
+ font-weight: 850;
2061
+ line-height: 1;
2062
+ padding: 0.3rem 0.55rem;
2063
+ position: absolute;
2064
+ right: 0.35rem;
2065
+ top: 0.35rem;
2066
+ white-space: nowrap;
2067
+ }
2068
+
2069
+ .boundary-overlay__box[data-label-placement="above"] .boundary-overlay__label {
2070
+ bottom: calc(100% + 0.25rem);
2071
+ top: auto;
1707
2072
  }
2073
+ }
2074
+ `;
2075
+ }
2076
+ function createRemoteStyles(enableTailwind, scope, app) {
2077
+ if ('commerce' === app.domain) return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
1708
2078
 
2079
+ @layer ultramodern-remote-${app.domain} {
1709
2080
  .commerce-shell {
1710
2081
  background: #f1eadc;
1711
2082
  color: #0b0a08;
@@ -1933,41 +2304,6 @@ a {
1933
2304
  width: 1rem;
1934
2305
  }
1935
2306
 
1936
- .boundary-overlay {
1937
- inset: 0;
1938
- pointer-events: none;
1939
- position: fixed;
1940
- z-index: 70;
1941
- }
1942
-
1943
- .boundary-overlay__box {
1944
- border: 0.0625rem solid var(--boundary-color);
1945
- border-radius: 0.55rem;
1946
- box-shadow:
1947
- 0 0 0 0.0625rem rgba(255, 255, 255, 0.72),
1948
- 0 0.35rem 1.25rem color-mix(in srgb, var(--boundary-color) 20%, transparent);
1949
- position: fixed;
1950
- }
1951
-
1952
- .boundary-overlay__label {
1953
- background: color-mix(in srgb, var(--boundary-color) 88%, white);
1954
- border-radius: 999px;
1955
- color: #0b0a08;
1956
- font-size: 0.7rem;
1957
- font-weight: 850;
1958
- line-height: 1;
1959
- padding: 0.3rem 0.55rem;
1960
- position: absolute;
1961
- right: 0.35rem;
1962
- top: 0.35rem;
1963
- white-space: nowrap;
1964
- }
1965
-
1966
- .boundary-overlay__box[data-label-placement="above"] .boundary-overlay__label {
1967
- bottom: calc(100% + 0.25rem);
1968
- top: auto;
1969
- }
1970
-
1971
2307
  @media (max-width: 860px) {
1972
2308
  .commerce-header,
1973
2309
  .commerce-footer,
@@ -1987,8 +2323,78 @@ a {
1987
2323
  min-height: 20rem;
1988
2324
  }
1989
2325
  }
2326
+ }
2327
+ `;
2328
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2329
+
2330
+ @layer ultramodern-remote-${app.domain ?? app.id} {
2331
+ [data-app-id="${app.id}"] {
2332
+ color: var(--um-color-foreground);
2333
+ background: var(--um-color-surface);
2334
+ font-family:
2335
+ Geist,
2336
+ Inter,
2337
+ ui-sans-serif,
2338
+ system-ui,
2339
+ -apple-system,
2340
+ BlinkMacSystemFont,
2341
+ "Segoe UI",
2342
+ sans-serif;
2343
+ min-height: 100vh;
2344
+ }
2345
+
2346
+ [data-app-id="${app.id}"] main {
2347
+ min-height: 100vh;
2348
+ padding: 2rem;
2349
+ }
2350
+
2351
+ [data-app-id="${app.id}"] nav {
2352
+ display: flex;
2353
+ gap: 0.75rem;
2354
+ margin-bottom: 2rem;
2355
+ }
2356
+
2357
+ [data-app-id="${app.id}"] a {
2358
+ color: var(--um-color-link);
2359
+ }
2360
+
2361
+ [data-mf-remote="${app.id}"] {
2362
+ border: 0.0625rem solid color-mix(in srgb, var(--um-color-accent) 30%, transparent);
2363
+ border-radius: 0.5rem;
2364
+ padding: 1rem;
2365
+ }
2366
+ }
2367
+ `;
2368
+ }
2369
+ function createServiceStyles(enableTailwind, scope, service) {
2370
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2371
+
2372
+ @layer ultramodern-effect-service {
2373
+ [data-app-id="${service.id}"] {
2374
+ color: var(--um-color-foreground);
2375
+ background: var(--um-color-surface);
2376
+ font-family:
2377
+ Geist,
2378
+ Inter,
2379
+ ui-sans-serif,
2380
+ system-ui,
2381
+ -apple-system,
2382
+ BlinkMacSystemFont,
2383
+ "Segoe UI",
2384
+ sans-serif;
2385
+ min-height: 100vh;
2386
+ }
2387
+
2388
+ [data-app-id="${service.id}"] main {
2389
+ min-height: 100vh;
2390
+ padding: 2rem;
2391
+ }
2392
+ }
1990
2393
  `;
1991
2394
  }
2395
+ function createAppStyles(enableTailwind, scope, app) {
2396
+ return 'shell' === app.kind ? createShellStyles(enableTailwind, scope) : createRemoteStyles(enableTailwind, scope, app);
2397
+ }
1992
2398
  function createPostcssConfig() {
1993
2399
  return `export default {
1994
2400
  plugins: {
@@ -2010,57 +2416,177 @@ function createLocalizedHeadComponent() {
2010
2416
  const supportedLanguages = ['en', 'cs'] as const;
2011
2417
  type SupportedLanguage = (typeof supportedLanguages)[number];
2012
2418
 
2013
- const localizedPath = (language: SupportedLanguage) => \`/\${language}\`;
2419
+ const localisedUrls = ultramodernLocalisedUrls as Record<
2420
+ string,
2421
+ Record<SupportedLanguage, string>
2422
+ >;
2014
2423
 
2015
- const absoluteUrl = (pathname: string) => {
2016
- const origin = ULTRAMODERN_SITE_URL.replace(/\\/+$/u, '');
2017
- return \`\${origin}\${pathname}\`;
2424
+ const isSupportedLanguage = (value: string): value is SupportedLanguage =>
2425
+ supportedLanguages.includes(value as SupportedLanguage);
2426
+
2427
+ const normalisePath = (pathname: string) => {
2428
+ const normalised = pathname.replace(/\\/+$/u, '').replace(/\\/+/gu, '/');
2429
+ return normalised.length > 0 ? normalised : '/';
2018
2430
  };
2019
- const LocalizedHead = () => {
2020
- const canonicalPath = localizedPath(fallbackLanguage);
2021
2431
 
2022
- return (
2023
- <>
2024
- <link rel="canonical" href={absoluteUrl(canonicalPath)} />
2025
- {supportedLanguages.map(code => (
2026
- <link
2027
- href={absoluteUrl(localizedPath(code))}
2028
- hrefLang={code}
2029
- key={code}
2030
- rel="alternate"
2031
- />
2032
- ))}
2033
- <link
2034
- href={absoluteUrl(localizedPath(fallbackLanguage))}
2035
- hrefLang="x-default"
2036
- rel="alternate"
2037
- />
2038
- </>
2039
- );
2432
+ const stripLanguagePrefix = (pathname: string) => {
2433
+ const segments = normalisePath(pathname).split('/').filter(Boolean);
2434
+ if (segments.length > 0 && isSupportedLanguage(segments[0] ?? '')) {
2435
+ segments.shift();
2436
+ }
2437
+ return \`/\${segments.join('/')}\`;
2040
2438
  };
2041
- `;
2042
- }
2043
- function createShellPage() {
2044
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2045
- import { ultramodernUiMarker } from '../../ultramodern-build';
2046
2439
 
2047
- const languageCodes = ['en', 'cs'] as const;
2440
+ const escapeRegExp = (value: string) =>
2441
+ value.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
2048
2442
 
2049
- const remoteKeys = ['commerce', 'identity', 'designSystem'] as const;
2443
+ const paramName = (segment: string) => segment.slice(1).replace(/\\?$/u, '');
2050
2444
 
2051
- ${createLocalizedHeadComponent()}
2052
- export default function ShellHome() {
2053
- const { i18nInstance, language } = useModernI18n();
2054
- const t = i18nInstance.t.bind(i18nInstance);
2445
+ const matchPattern = (pathname: string, pattern: string) => {
2446
+ const names: string[] = [];
2447
+ const source = normalisePath(pattern)
2448
+ .split('/')
2449
+ .filter(Boolean)
2450
+ .map(segment => {
2451
+ if (segment.startsWith(':')) {
2452
+ names.push(paramName(segment));
2453
+ return segment.endsWith('?') ? '(?:/([^/]+))?' : '/([^/]+)';
2454
+ }
2455
+ return \`/\${escapeRegExp(segment)}\`;
2456
+ })
2457
+ .join('');
2458
+ const match = new RegExp(\`^\${source || '/'}$\`).exec(normalisePath(pathname));
2055
2459
 
2056
- return (
2057
- <main>
2460
+ if (!match) {
2461
+ return undefined;
2462
+ }
2463
+
2464
+ return names.reduce<Record<string, string>>((params, name, index) => {
2465
+ params[name] = decodeURIComponent(match[index + 1] ?? '');
2466
+ return params;
2467
+ }, {});
2468
+ };
2469
+
2470
+ const buildPath = (pattern: string, params: Record<string, string>) => {
2471
+ const path = normalisePath(pattern)
2472
+ .split('/')
2473
+ .filter(Boolean)
2474
+ .map(segment => {
2475
+ if (!segment.startsWith(':')) {
2476
+ return segment;
2477
+ }
2478
+ const value = params[paramName(segment)];
2479
+ return value ? encodeURIComponent(value) : '';
2480
+ })
2481
+ .filter(Boolean)
2482
+ .join('/');
2483
+
2484
+ return \`/\${path}\`;
2485
+ };
2486
+
2487
+ const resolveLocalisedPath = (
2488
+ pathname: string,
2489
+ targetLanguage: SupportedLanguage,
2490
+ ) => {
2491
+ const pathWithoutLanguage = stripLanguagePrefix(pathname);
2492
+
2493
+ for (const entry of Object.values(localisedUrls)) {
2494
+ const targetPattern = entry[targetLanguage];
2495
+ if (!targetPattern) {
2496
+ continue;
2497
+ }
2498
+
2499
+ for (const language of supportedLanguages) {
2500
+ const sourcePattern = entry[language];
2501
+ const params = sourcePattern
2502
+ ? matchPattern(pathWithoutLanguage, sourcePattern)
2503
+ : undefined;
2504
+ if (params) {
2505
+ return buildPath(targetPattern, params);
2506
+ }
2507
+ }
2508
+ }
2509
+
2510
+ return pathWithoutLanguage;
2511
+ };
2512
+
2513
+ const localizedPath = (pathname: string, language: SupportedLanguage) => {
2514
+ const pathWithoutLanguage = resolveLocalisedPath(pathname, language);
2515
+ return pathWithoutLanguage === '/' ? \`/\${language}\` : \`/\${language}\${pathWithoutLanguage}\`;
2516
+ };
2517
+
2518
+ const absoluteUrl = (pathname: string) => {
2519
+ const origin = ULTRAMODERN_SITE_URL.replace(/\\/+$/u, '');
2520
+ return \`\${origin}\${pathname}\`;
2521
+ };
2522
+
2523
+ const locationSuffix = (location: {
2524
+ hash?: unknown;
2525
+ search?: unknown;
2526
+ searchStr?: unknown;
2527
+ }) => {
2528
+ const locationSearch =
2529
+ typeof location.searchStr === 'string'
2530
+ ? location.searchStr
2531
+ : typeof location.search === 'string'
2532
+ ? location.search
2533
+ : '';
2534
+ const locationHash = typeof location.hash === 'string' ? location.hash : '';
2535
+
2536
+ return \`\${locationSearch}\${locationHash}\`;
2537
+ };
2538
+
2539
+ const LocalizedHead = () => {
2540
+ const location = useLocation();
2541
+ const canonicalPath = localizedPath(location.pathname, fallbackLanguage);
2542
+
2543
+ return (
2544
+ <Helmet>
2545
+ <link rel="canonical" href={absoluteUrl(canonicalPath)} />
2546
+ {supportedLanguages.map(code => (
2547
+ <link
2548
+ href={absoluteUrl(localizedPath(location.pathname, code))}
2549
+ hrefLang={code}
2550
+ key={code}
2551
+ rel="alternate"
2552
+ />
2553
+ ))}
2554
+ <link
2555
+ href={absoluteUrl(localizedPath(location.pathname, fallbackLanguage))}
2556
+ hrefLang="x-default"
2557
+ rel="alternate"
2558
+ />
2559
+ </Helmet>
2560
+ );
2561
+ };
2562
+ `;
2563
+ }
2564
+ function createShellPage() {
2565
+ return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2566
+ import { Helmet } from '@modern-js/runtime/head';
2567
+ import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2568
+ import { ultramodernLocalisedUrls } from '../ultramodern-route-metadata';
2569
+ import { ultramodernUiMarker } from '../../ultramodern-build';
2570
+
2571
+ const languageCodes = ['en', 'cs'] as const;
2572
+
2573
+ const remoteKeys = ['explore', 'decide', 'checkout'] as const;
2574
+
2575
+ ${createLocalizedHeadComponent()}
2576
+ export default function ShellHome() {
2577
+ const { i18nInstance, language } = useModernI18n();
2578
+ const t = i18nInstance.t.bind(i18nInstance);
2579
+ const location = useLocation();
2580
+ const suffix = locationSuffix(location);
2581
+
2582
+ return (
2583
+ <main>
2058
2584
  <LocalizedHead />
2059
2585
  <nav aria-label={t('shell.language.switcher')}>
2060
2586
  {languageCodes.map(code => (
2061
2587
  <a
2062
2588
  aria-current={language === code ? 'page' : undefined}
2063
- href={\`/\${code}\`}
2589
+ href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
2064
2590
  key={code}
2065
2591
  >
2066
2592
  {t(\`shell.language.\${code}\`)}
@@ -2083,11 +2609,13 @@ export default function ShellHome() {
2083
2609
  `;
2084
2610
  }
2085
2611
  function createRemotePage(app) {
2086
- if ('remote-commerce' === app.id) return createCommerceRemotePage(app);
2087
2612
  const effectBffImport = appHasEffectApi(app) ? `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2613
+ import { Helmet } from '@modern-js/runtime/head';
2614
+ import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2088
2615
  import { useEffect, useState } from 'react';
2616
+ import { ultramodernLocalisedUrls } from '../ultramodern-route-metadata';
2089
2617
  import { ultramodernUiMarker } from '../../ultramodern-build';
2090
- ` : "import { useModernI18n } from '@modern-js/plugin-i18n/runtime';\nimport { ultramodernUiMarker } from '../../ultramodern-build';\n";
2618
+ ` : "import { useModernI18n } from '@modern-js/plugin-i18n/runtime';\nimport { Helmet } from '@modern-js/runtime/head';\nimport { useLocation } from '@modern-js/plugin-tanstack/runtime';\nimport { ultramodernLocalisedUrls } from '../ultramodern-route-metadata';\nimport { ultramodernUiMarker } from '../../ultramodern-build';\n";
2091
2619
  const effectBffState = appHasEffectApi(app) ? ` const [effectApiStatus, setEffectApiStatus] = useState('pending');
2092
2620
 
2093
2621
  useEffect(() => {
@@ -2119,6 +2647,8 @@ ${createLocalizedHeadComponent()}
2119
2647
  export default function ${toPascalCase(app.id)}Home() {
2120
2648
  const { i18nInstance, language } = useModernI18n();
2121
2649
  const t = i18nInstance.t.bind(i18nInstance);
2650
+ const location = useLocation();
2651
+ const suffix = locationSuffix(location);
2122
2652
  ${effectBffState} return (
2123
2653
  <main>
2124
2654
  <LocalizedHead />
@@ -2126,7 +2656,7 @@ ${effectBffState} return (
2126
2656
  {supportedLanguages.map(code => (
2127
2657
  <a
2128
2658
  aria-current={language === code ? 'page' : undefined}
2129
- href={\`/\${code}\`}
2659
+ href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
2130
2660
  key={code}
2131
2661
  >
2132
2662
  {t(\`${app.domain}.language.\${code}\`)}
@@ -2143,399 +2673,6 @@ ${effectBffMarkup} </main>
2143
2673
  }
2144
2674
  `;
2145
2675
  }
2146
- function createCommerceRemotePage(app) {
2147
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2148
- import { useEffect, useState, type CSSProperties } from 'react';
2149
- import { ultramodernUiMarker } from '../../ultramodern-build';
2150
-
2151
- const languageCodes = ['en', 'cs'] as const;
2152
-
2153
- const boundaryDefinitions = [
2154
- {
2155
- color: '#ff5a57',
2156
- id: 'explore',
2157
- labelKey: 'commerce.boundaries.explore',
2158
- },
2159
- {
2160
- color: '#24d671',
2161
- id: 'decide',
2162
- labelKey: 'commerce.boundaries.decide',
2163
- },
2164
- {
2165
- color: '#f4d044',
2166
- id: 'checkout',
2167
- labelKey: 'commerce.boundaries.checkout',
2168
- },
2169
- ] as const;
2170
-
2171
- type BoundaryId = (typeof boundaryDefinitions)[number]['id'];
2172
- type BoundaryDefinition = (typeof boundaryDefinitions)[number];
2173
-
2174
- const boundaryMetadata: Record<BoundaryId, BoundaryDefinition> = {
2175
- checkout: boundaryDefinitions[2],
2176
- decide: boundaryDefinitions[1],
2177
- explore: boundaryDefinitions[0],
2178
- };
2179
-
2180
- const products = [
2181
- {
2182
- id: 'field-loader-112',
2183
- titleKey: 'commerce.products.fieldLoader.title',
2184
- descriptionKey: 'commerce.products.fieldLoader.description',
2185
- priceKey: 'commerce.products.fieldLoader.price',
2186
- powerKey: 'commerce.products.fieldLoader.power',
2187
- availabilityKey: 'commerce.products.fieldLoader.availability',
2188
- },
2189
- {
2190
- id: 'orchard-tractor',
2191
- titleKey: 'commerce.products.orchard.title',
2192
- badgeKey: 'commerce.products.orchard.badge',
2193
- },
2194
- {
2195
- id: 'autonomy-kit',
2196
- titleKey: 'commerce.products.autonomy.title',
2197
- badgeKey: 'commerce.products.autonomy.badge',
2198
- },
2199
- ] as const;
2200
-
2201
- type ProductId = (typeof products)[number]['id'];
2202
- type CartState = Partial<Record<ProductId, number>>;
2203
-
2204
- type BoundaryLabels = Record<BoundaryId, string>;
2205
- type BoundaryBox = {
2206
- color: string;
2207
- height: number;
2208
- id: BoundaryId;
2209
- label: string;
2210
- labelPlacement: 'above' | 'inside';
2211
- left: number;
2212
- top: number;
2213
- width: number;
2214
- };
2215
-
2216
- const featuredProduct = products[0];
2217
- const recommendations = [products[1], products[2]] as const;
2218
-
2219
- ${createLocalizedHeadComponent()}
2220
- const isBoundaryId = (value: string): value is BoundaryId =>
2221
- Object.prototype.hasOwnProperty.call(boundaryMetadata, value);
2222
-
2223
- function collectBoundaryBoxes(labels: BoundaryLabels): BoundaryBox[] {
2224
- return Array.from(
2225
- document.querySelectorAll<HTMLElement>('[data-boundary], [data-boundary-page]'),
2226
- )
2227
- .map(element => {
2228
- const id = element.dataset.boundary ?? element.dataset.boundaryPage;
2229
-
2230
- if (id === undefined || !isBoundaryId(id)) {
2231
- return undefined;
2232
- }
2233
-
2234
- const rect = element.getBoundingClientRect();
2235
-
2236
- if (rect.width <= 0 || rect.height <= 0) {
2237
- return undefined;
2238
- }
2239
-
2240
- return {
2241
- color: boundaryMetadata[id].color,
2242
- height: rect.height,
2243
- id,
2244
- label: labels[id],
2245
- labelPlacement: rect.top > 28 ? 'above' : 'inside',
2246
- left: rect.left,
2247
- top: rect.top,
2248
- width: rect.width,
2249
- };
2250
- })
2251
- .filter((box): box is BoundaryBox => box !== undefined);
2252
- }
2253
-
2254
- function BoundaryOverlay({
2255
- labels,
2256
- visible,
2257
- }: {
2258
- labels: BoundaryLabels;
2259
- visible: boolean;
2260
- }) {
2261
- const [boxes, setBoxes] = useState<BoundaryBox[]>([]);
2262
-
2263
- useEffect(() => {
2264
- if (!visible) {
2265
- setBoxes([]);
2266
- return;
2267
- }
2268
-
2269
- let animationFrame = 0;
2270
- const update = () => {
2271
- cancelAnimationFrame(animationFrame);
2272
- animationFrame = requestAnimationFrame(() => {
2273
- setBoxes(collectBoundaryBoxes(labels));
2274
- });
2275
- };
2276
- const observer = new ResizeObserver(update);
2277
-
2278
- observer.observe(document.body);
2279
- update();
2280
- window.addEventListener('resize', update);
2281
- window.addEventListener('scroll', update, true);
2282
-
2283
- return () => {
2284
- cancelAnimationFrame(animationFrame);
2285
- observer.disconnect();
2286
- window.removeEventListener('resize', update);
2287
- window.removeEventListener('scroll', update, true);
2288
- };
2289
- }, [labels, visible]);
2290
-
2291
- if (!visible) {
2292
- return null;
2293
- }
2294
-
2295
- return (
2296
- <div aria-hidden="true" className="boundary-overlay">
2297
- {boxes.map((box, index) => (
2298
- <div
2299
- className="boundary-overlay__box"
2300
- data-boundary-id={box.id}
2301
- data-label-placement={box.labelPlacement}
2302
- key={\`\${box.id}-\${index}\`}
2303
- style={{
2304
- '--boundary-color': box.color,
2305
- height: box.height,
2306
- left: box.left,
2307
- top: box.top,
2308
- width: box.width,
2309
- } as CSSProperties}
2310
- >
2311
- <span className="boundary-overlay__label">{box.label}</span>
2312
- </div>
2313
- ))}
2314
- </div>
2315
- );
2316
- }
2317
-
2318
- export default function ${toPascalCase(app.id)}Home() {
2319
- const { i18nInstance, language } = useModernI18n();
2320
- const t = i18nInstance.t.bind(i18nInstance);
2321
- const [cart, setCart] = useState<CartState>({});
2322
- const [showBoundaries, setShowBoundaries] = useState(false);
2323
- const [effectApiStatus, setEffectApiStatus] = useState('pending');
2324
- const boundaryLabels = {
2325
- checkout: t('commerce.boundaries.checkout'),
2326
- decide: t('commerce.boundaries.decide'),
2327
- explore: t('commerce.boundaries.explore'),
2328
- } satisfies BoundaryLabels;
2329
- const cartLines = products
2330
- .map(product => ({
2331
- product,
2332
- quantity: cart[product.id] ?? 0,
2333
- }))
2334
- .filter(line => line.quantity > 0);
2335
- const cartCount = cartLines.reduce((total, line) => total + line.quantity, 0);
2336
-
2337
- useEffect(() => {
2338
- void fetch('${effectApiPrefix(app)}/effect/${effectApiStem(app)}?limit=1', {
2339
- headers: {
2340
- accept: 'application/json',
2341
- },
2342
- })
2343
- .then(response => {
2344
- if (!response.ok) {
2345
- throw new Error(\`Effect BFF request failed: \${response.status}\`);
2346
- }
2347
-
2348
- return response.json() as Promise<{ items?: Array<{ title?: string }> }>;
2349
- })
2350
- .then(data => {
2351
- setEffectApiStatus(data.items[0]?.title ?? 'empty');
2352
- })
2353
- .catch(() => {
2354
- setEffectApiStatus('unavailable');
2355
- });
2356
- }, []);
2357
-
2358
- const addToCart = (id: ProductId) => {
2359
- setCart(current => ({
2360
- ...current,
2361
- [id]: (current[id] ?? 0) + 1,
2362
- }));
2363
- };
2364
-
2365
- const reduceQuantity = (id: ProductId) => {
2366
- setCart(current => {
2367
- const quantity = current[id] ?? 0;
2368
- const next = { ...current };
2369
-
2370
- if (quantity <= 1) {
2371
- delete next[id];
2372
- } else {
2373
- next[id] = quantity - 1;
2374
- }
2375
-
2376
- return next;
2377
- });
2378
- };
2379
-
2380
- const removeFromCart = (id: ProductId) => {
2381
- setCart(current => {
2382
- const next = { ...current };
2383
-
2384
- delete next[id];
2385
- return next;
2386
- });
2387
- };
2388
-
2389
- return (
2390
- <main className="commerce-shell">
2391
- <LocalizedHead />
2392
- <BoundaryOverlay labels={boundaryLabels} visible={showBoundaries} />
2393
- <header className="commerce-header" data-boundary="explore">
2394
- <strong className="commerce-logo">{t('commerce.brand')}</strong>
2395
- <nav aria-label={t('commerce.navigation.primary')} className="commerce-nav">
2396
- <a className="commerce-pill" href="#machines">
2397
- {t('commerce.navigation.machines')}
2398
- </a>
2399
- <a className="commerce-pill" href="#checkout">
2400
- {t('commerce.navigation.checkout')}
2401
- </a>
2402
- </nav>
2403
- <div className="commerce-actions">
2404
- <a className="commerce-cart-button" data-boundary="checkout" href="#cart">
2405
- {t('commerce.cart.button', { count: cartCount })}
2406
- </a>
2407
- <nav aria-label={t('commerce.language.switcher')} className="commerce-language">
2408
- {languageCodes.map(code => (
2409
- <a
2410
- aria-current={language === code ? 'page' : undefined}
2411
- className="commerce-pill"
2412
- href={\`/\${code}\`}
2413
- key={code}
2414
- >
2415
- {t(\`commerce.language.\${code}\`)}
2416
- </a>
2417
- ))}
2418
- </nav>
2419
- </div>
2420
- </header>
2421
-
2422
- <div className="commerce-page">
2423
- <section className="commerce-product" data-boundary-page="decide" id="machines">
2424
- <div
2425
- aria-label={t('commerce.products.fieldLoader.imageAlt')}
2426
- className="commerce-product-media"
2427
- role="img"
2428
- />
2429
- <div>
2430
- <p className="commerce-eyebrow">{t('commerce.detail.eyebrow')}</p>
2431
- <h1 className="commerce-title">{t(featuredProduct.titleKey)}</h1>
2432
- <p className="commerce-lede">{t(featuredProduct.descriptionKey)}</p>
2433
- <div className="commerce-facts">
2434
- <div className="commerce-fact">
2435
- <span>{t('commerce.detail.price')}</span>
2436
- <strong>{t(featuredProduct.priceKey)}</strong>
2437
- </div>
2438
- <div className="commerce-fact">
2439
- <span>{t('commerce.detail.power')}</span>
2440
- <strong>{t(featuredProduct.powerKey)}</strong>
2441
- </div>
2442
- <div className="commerce-fact">
2443
- <span>{t('commerce.detail.availability')}</span>
2444
- <strong>{t(featuredProduct.availabilityKey)}</strong>
2445
- </div>
2446
- </div>
2447
- <div className="commerce-checkout" data-boundary="checkout" id="checkout">
2448
- <button
2449
- className="commerce-button"
2450
- onClick={() => addToCart(featuredProduct.id)}
2451
- type="button"
2452
- >
2453
- {t('commerce.cart.add')}
2454
- </button>
2455
- <a className="commerce-link-button" href="#cart">
2456
- {t('commerce.cart.view')}
2457
- </a>
2458
- </div>
2459
- </div>
2460
- </section>
2461
-
2462
- <section data-boundary="explore">
2463
- <h2 className="commerce-section-title">{t('commerce.recommendations.title')}</h2>
2464
- <div className="commerce-grid">
2465
- {recommendations.map(product => (
2466
- <article className="commerce-card" key={product.id}>
2467
- <span>{t(product.badgeKey)}</span>
2468
- <strong>{t(product.titleKey)}</strong>
2469
- </article>
2470
- ))}
2471
- </div>
2472
- </section>
2473
-
2474
- <section className="commerce-cart-panel" data-boundary="checkout" id="cart">
2475
- <h2>{t('commerce.cart.title')}</h2>
2476
- {cartLines.length === 0 ? (
2477
- <p>{t('commerce.cart.empty')}</p>
2478
- ) : (
2479
- cartLines.map(line => (
2480
- <div className="commerce-cart-line" key={line.product.id}>
2481
- <strong>{t(line.product.titleKey)}</strong>
2482
- <div className="commerce-quantity">
2483
- <button
2484
- aria-label={t('commerce.cart.decrease', {
2485
- name: t(line.product.titleKey),
2486
- })}
2487
- className="commerce-quantity-button"
2488
- onClick={() => reduceQuantity(line.product.id)}
2489
- type="button"
2490
- >
2491
- -
2492
- </button>
2493
- <span>{line.quantity}</span>
2494
- <button
2495
- aria-label={t('commerce.cart.increase', {
2496
- name: t(line.product.titleKey),
2497
- })}
2498
- className="commerce-quantity-button"
2499
- onClick={() => addToCart(line.product.id)}
2500
- type="button"
2501
- >
2502
- +
2503
- </button>
2504
- <button
2505
- className="commerce-link-button"
2506
- onClick={() => removeFromCart(line.product.id)}
2507
- type="button"
2508
- >
2509
- {t('commerce.cart.remove')}
2510
- </button>
2511
- </div>
2512
- </div>
2513
- ))
2514
- )}
2515
- </section>
2516
- </div>
2517
-
2518
- <footer className="commerce-footer" data-boundary="explore">
2519
- <span>{t('commerce.footer.stack')}</span>
2520
- <span data-testid="effect-bff-status">{effectApiStatus}</span>
2521
- <span data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
2522
- {ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
2523
- </span>
2524
- </footer>
2525
-
2526
- <label className="commerce-boundary-toggle">
2527
- <input
2528
- checked={showBoundaries}
2529
- onChange={event => setShowBoundaries(event.currentTarget.checked)}
2530
- type="checkbox"
2531
- />
2532
- {t('commerce.boundaries.toggle')}
2533
- </label>
2534
- </main>
2535
- );
2536
- }
2537
- `;
2538
- }
2539
2676
  function createLayout(appId) {
2540
2677
  return `import { Outlet } from '@modern-js/plugin-tanstack/runtime';
2541
2678
  import './index.css';
@@ -2550,7 +2687,18 @@ export default function Layout() {
2550
2687
  `;
2551
2688
  }
2552
2689
  function createRemoteEntry(app) {
2553
- return `export { default } from './components/${remoteWidgetFile(app)}';
2690
+ if (app.exposes?.['./ProductPage']) return `export { default } from './components/product-page';
2691
+ `;
2692
+ if (app.exposes?.['./CartPage']) return `export { default } from './components/cart-page';
2693
+ `;
2694
+ return `export default function ${toPascalCase(app.domain ?? app.id)}Route() {
2695
+ return (
2696
+ <section data-mf-remote="${app.id}" data-mf-expose="./Route">
2697
+ <h2>${app.displayName}</h2>
2698
+ <p>Route surface for ${app.domain ?? app.id}.</p>
2699
+ </section>
2700
+ );
2701
+ }
2554
2702
  `;
2555
2703
  }
2556
2704
  function createRemoteWidget(app) {
@@ -2566,16 +2714,57 @@ function createRemoteWidget(app) {
2566
2714
  }
2567
2715
  `;
2568
2716
  }
2717
+ function createRemoteExposeComponent(app, expose) {
2718
+ if ('./Widget' === expose) return createRemoteWidget(app);
2719
+ const componentName = `${toPascalCase(app.domain ?? app.id)}${toPascalCase(expose.replace(/^\.\//u, ''))}`;
2720
+ if ('remote-decide' === app.id && './ProductPage' === expose) return `import AddToCart from 'checkout/AddToCart';
2721
+ import Recommendations from 'explore/Recommendations';
2722
+
2723
+ export default function ${componentName}() {
2724
+ return (
2725
+ <section data-mf-remote="${app.id}" data-mf-expose="${expose}">
2726
+ <p>Decide owns tractor product selection.</p>
2727
+ <h2>Field Loader 112</h2>
2728
+ <p>Hydraulic-ready compact tractor with guided implement matching.</p>
2729
+ <AddToCart />
2730
+ <Recommendations />
2731
+ </section>
2732
+ );
2733
+ }
2734
+ `;
2735
+ return `export default function ${componentName}() {
2736
+ return (
2737
+ <section data-mf-remote="${app.id}" data-mf-expose="${expose}">
2738
+ <h2>${app.displayName} ${expose.replace(/^\.\//u, '')}</h2>
2739
+ <p>Module Federation surface owned by ${app.ownership.team}.</p>
2740
+ </section>
2741
+ );
2742
+ }
2743
+ `;
2744
+ }
2745
+ function remoteComponentOutputPath(app, expose) {
2746
+ const exposePath = app.exposes?.[expose];
2747
+ if (!exposePath?.startsWith('./src/components/')) return;
2748
+ return `${app.directory}/${exposePath.replace(/^\.\//u, '')}`;
2749
+ }
2569
2750
  function createAppLocaleMessages(app, language) {
2570
2751
  const czechLabels = {
2571
- commerce: {
2572
- role: 'obchod',
2573
- title: 'Obchodní remote'
2752
+ checkout: {
2753
+ role: 'pokladna',
2754
+ title: 'Pokladní remote'
2755
+ },
2756
+ decide: {
2757
+ role: 'rozhodování',
2758
+ title: 'Rozhodovací remote'
2574
2759
  },
2575
2760
  'design-system': {
2576
2761
  role: 'design system',
2577
2762
  title: 'Design system remote'
2578
2763
  },
2764
+ explore: {
2765
+ role: 'procházení',
2766
+ title: 'Průzkumný remote'
2767
+ },
2579
2768
  identity: {
2580
2769
  role: 'identita',
2581
2770
  title: 'Identitní remote'
@@ -2589,9 +2778,12 @@ function createAppLocaleMessages(app, language) {
2589
2778
  switcher: 'en' === language ? 'Language' : 'Jazyk'
2590
2779
  },
2591
2780
  remotes: {
2592
- commerce: 'en' === language ? 'Commerce Remote' : 'Obchodní remote',
2593
- designSystem: 'en' === language ? 'Design System Remote' : 'Design system remote',
2594
- identity: 'en' === language ? 'Identity Remote' : 'Identitní remote'
2781
+ checkout: 'en' === language ? 'Checkout Remote' : 'Checkout remote',
2782
+ decide: 'en' === language ? 'Decide Remote' : 'Decide remote',
2783
+ explore: 'en' === language ? 'Explore Remote' : 'Explore remote'
2784
+ },
2785
+ routes: {
2786
+ home: 'en' === language ? 'Home' : 'Domů'
2595
2787
  },
2596
2788
  title: 'en' === language ? 'UltraModern SuperApp Shell' : 'UltraModern SuperApp shell'
2597
2789
  }
@@ -2601,69 +2793,6 @@ function createAppLocaleMessages(app, language) {
2601
2793
  role: domain,
2602
2794
  title: `${app.displayName} CZ`
2603
2795
  };
2604
- if ('commerce' === domain) return {
2605
- commerce: {
2606
- boundaries: {
2607
- checkout: 'en' === language ? 'checkout' : 'pokladna',
2608
- decide: 'en' === language ? 'decide' : 'rozhodování',
2609
- explore: 'en' === language ? 'explore' : 'procházení',
2610
- toggle: 'en' === language ? 'show team boundaries' : 'zobrazit hranice týmů'
2611
- },
2612
- brand: 'Acre & Iron',
2613
- cart: {
2614
- add: 'en' === language ? 'Add to cart' : 'Přidat do košíku',
2615
- button: 'en' === language ? 'Your cart ({{count}})' : 'Košík ({{count}})',
2616
- decrease: 'en' === language ? 'Decrease {{name}} quantity' : 'Snížit množství položky {{name}}',
2617
- empty: 'en' === language ? 'Your cart is empty.' : 'Košík je prázdný.',
2618
- increase: 'en' === language ? 'Increase {{name}} quantity' : 'Zvýšit množství položky {{name}}',
2619
- remove: 'en' === language ? 'Remove' : 'Odebrat',
2620
- title: 'en' === language ? 'Cart' : 'Košík',
2621
- view: 'en' === language ? 'View cart' : 'Zobrazit košík'
2622
- },
2623
- detail: {
2624
- availability: 'en' === language ? 'Availability' : 'Dostupnost',
2625
- eyebrow: 'en' === language ? 'Machine detail' : 'Detail stroje',
2626
- power: 'en' === language ? 'Power' : 'Výkon',
2627
- price: 'en' === language ? 'Price' : 'Cena'
2628
- },
2629
- footer: {
2630
- stack: 'en' === language ? 'SPA, SSR-ready Module Federation, React, Effect BFF' : 'SPA, SSR-ready Module Federation, React, Effect BFF'
2631
- },
2632
- language: {
2633
- cs: 'en' === language ? 'Czech' : 'Čeština',
2634
- en: 'en' === language ? 'English' : 'Angličtina',
2635
- switcher: 'en' === language ? 'Language' : 'Jazyk'
2636
- },
2637
- navigation: {
2638
- checkout: 'en' === language ? 'Checkout' : 'Pokladna',
2639
- machines: 'en' === language ? 'Machines' : 'Stroje',
2640
- primary: 'en' === language ? 'Primary commerce navigation' : 'Hlavní navigace obchodu'
2641
- },
2642
- products: {
2643
- autonomy: {
2644
- badge: 'en' === language ? 'AI-first option' : 'AI varianta',
2645
- title: 'en' === language ? 'Autonomy Retrofit Kit' : 'Sada pro autonomní řízení'
2646
- },
2647
- fieldLoader: {
2648
- availability: 'en' === language ? 'In stock' : 'Skladem',
2649
- description: 'en' === language ? 'A loader-ready tractor for feed, hay, gravel, and winter road work.' : 'Traktor připravený na nakladač pro krmivo, seno, štěrk i zimní údržbu cest.',
2650
- imageAlt: 'en' === language ? 'Field Loader 112 tractor working on a bright farm lane' : 'Traktor Field Loader 112 pracuje na světlé polní cestě',
2651
- power: '112 hp',
2652
- price: 'EUR 42,500',
2653
- title: 'Field Loader 112'
2654
- },
2655
- orchard: {
2656
- badge: 'en' === language ? 'Best for tight rows' : 'Nejlepší do úzkých řádků',
2657
- title: 'en' === language ? 'Narrow Orchard Tractor' : 'Úzký sadový traktor'
2658
- }
2659
- },
2660
- recommendations: {
2661
- title: 'en' === language ? 'Compare alternatives' : 'Porovnat alternativy'
2662
- },
2663
- role: 'en' === language ? 'commerce' : 'obchod',
2664
- title: 'en' === language ? app.displayName : czechLabel.title
2665
- }
2666
- };
2667
2796
  return {
2668
2797
  [domain]: {
2669
2798
  language: {
@@ -2672,6 +2801,16 @@ function createAppLocaleMessages(app, language) {
2672
2801
  switcher: 'en' === language ? 'Language' : 'Jazyk'
2673
2802
  },
2674
2803
  role: 'en' === language ? app.domain ?? app.kind : czechLabel.role,
2804
+ routes: {
2805
+ cart: 'en' === language ? 'Cart' : 'Košík',
2806
+ checkout: 'en' === language ? 'Checkout' : 'Pokladna',
2807
+ home: 'en' === language ? 'Home' : 'Domů',
2808
+ listing: 'en' === language ? 'Tractors' : 'Traktory',
2809
+ productDetail: 'en' === language ? 'Tractor detail' : 'Detail traktoru',
2810
+ storePicker: 'en' === language ? 'Store picker' : 'Výběr prodejce',
2811
+ thankYou: 'en' === language ? 'Order confirmation' : 'Potvrzení objednávky',
2812
+ unavailable: 'en' === language ? 'Unavailable' : 'Nedostupné'
2813
+ },
2675
2814
  title: 'en' === language ? app.displayName : czechLabel.title
2676
2815
  }
2677
2816
  };
@@ -2706,6 +2845,18 @@ function createDesignTokens() {
2706
2845
  } as const;
2707
2846
  `;
2708
2847
  }
2848
+ function createSharedDesignTokensCss() {
2849
+ return `@layer ultramodern-shared-tokens {
2850
+ :root {
2851
+ --um-color-accent: #2f8f68;
2852
+ --um-color-canvas: #f1eadc;
2853
+ --um-color-foreground: #133225;
2854
+ --um-color-link: #166b4b;
2855
+ --um-color-surface: #f6fbf7;
2856
+ }
2857
+ }
2858
+ `;
2859
+ }
2709
2860
  function serviceEffectApiExport(service = effectService) {
2710
2861
  return `${toCamelCase(effectApiStem(service))}EffectApi`;
2711
2862
  }
@@ -2718,6 +2869,12 @@ function serviceEffectApiName(service = effectService) {
2718
2869
  function serviceEffectSchemaExport(service = effectService) {
2719
2870
  return `${toCamelCase(effectApiStem(service))}ItemSchema`;
2720
2871
  }
2872
+ function serviceEffectMarkerSchemaExport(service = effectService) {
2873
+ return `${toCamelCase(effectApiStem(service))}MarkerSchema`;
2874
+ }
2875
+ function serviceEffectReadinessSchemaExport(service = effectService) {
2876
+ return `${toCamelCase(effectApiStem(service))}ReadinessSchema`;
2877
+ }
2721
2878
  function serviceEffectErrorStem(service = effectService) {
2722
2879
  const stem = effectApiStem(service);
2723
2880
  return 'recommendations' === stem ? 'recommendation' : stem;
@@ -2743,6 +2900,8 @@ function createEffectSharedApiImports() {
2743
2900
  }
2744
2901
  function createEffectSharedApiContract(service = effectService) {
2745
2902
  const schemaExport = serviceEffectSchemaExport(service);
2903
+ const markerSchemaExport = serviceEffectMarkerSchemaExport(service);
2904
+ const readinessSchemaExport = serviceEffectReadinessSchemaExport(service);
2746
2905
  const createPayloadSchemaExport = serviceEffectCreatePayloadSchemaExport(service);
2747
2906
  const notFoundErrorExport = serviceEffectNotFoundErrorExport(service);
2748
2907
  const notFoundSchemaExport = serviceEffectNotFoundSchemaExport(service);
@@ -2751,19 +2910,33 @@ function createEffectSharedApiContract(service = effectService) {
2751
2910
  const groupName = serviceEffectGroupName(service);
2752
2911
  const stem = effectApiStem(service);
2753
2912
  const servicePrefix = effectApiPrefix(service);
2754
- return `export const ${schemaExport} = Schema.Struct({
2913
+ return `export const ${markerSchemaExport} = Schema.Struct({
2914
+ appId: Schema.String,
2915
+ packageName: Schema.String,
2916
+ version: Schema.String,
2917
+ build: Schema.String,
2918
+ deployProfile: Schema.String,
2919
+ surface: Schema.String,
2920
+ });
2921
+
2922
+ export const ${schemaExport} = Schema.Struct({
2755
2923
  id: Schema.String,
2756
- marker: Schema.Struct({
2757
- appId: Schema.String,
2758
- packageName: Schema.String,
2759
- version: Schema.String,
2760
- build: Schema.String,
2761
- deployProfile: Schema.String,
2762
- surface: Schema.String,
2763
- }),
2924
+ marker: ${markerSchemaExport},
2764
2925
  title: Schema.String,
2765
2926
  });
2766
2927
 
2928
+ export const ${readinessSchemaExport} = Schema.Struct({
2929
+ checks: Schema.Struct({
2930
+ effectBff: Schema.Literal('ready'),
2931
+ moduleFederation: Schema.Literal('ready'),
2932
+ ssr: Schema.Literal('ready'),
2933
+ translations: Schema.Literal('ready'),
2934
+ }),
2935
+ marker: ${markerSchemaExport},
2936
+ status: Schema.Literal('ready'),
2937
+ versionSkew: Schema.Literal('none'),
2938
+ });
2939
+
2767
2940
  export const ${createPayloadSchemaExport} = Schema.Struct({
2768
2941
  title: Schema.String,
2769
2942
  });
@@ -2799,6 +2972,11 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
2799
2972
  }),
2800
2973
  }),
2801
2974
  )
2975
+ .add(
2976
+ HttpApiEndpoint.get('readiness', '/effect/${stem}/readiness', {
2977
+ success: ${readinessSchemaExport},
2978
+ }),
2979
+ )
2802
2980
  .add(
2803
2981
  HttpApiEndpoint.get('get', '/effect/${stem}/:id', {
2804
2982
  params: {
@@ -2825,6 +3003,12 @@ export const ${groupName}OperationContexts = {
2825
3003
  method: 'GET',
2826
3004
  source: 'generated-client',
2827
3005
  },
3006
+ readiness: {
3007
+ operationId: '${apiName}:${groupName}:readiness',
3008
+ routePath: '/effect/${stem}/readiness',
3009
+ method: 'GET',
3010
+ source: 'generated-client',
3011
+ },
2828
3012
  get: {
2829
3013
  operationId: '${apiName}:${groupName}:get',
2830
3014
  routePath: '/effect/${stem}/:id',
@@ -2843,6 +3027,7 @@ export const ${groupName}ApiContract = {
2843
3027
  basePath: '${servicePrefix}/effect/${stem}',
2844
3028
  ownerId: '${service.id}',
2845
3029
  servicePrefix: '${servicePrefix}',
3030
+ readinessPath: '${servicePrefix}/effect/${stem}/readiness',
2846
3031
  } as const;
2847
3032
  `;
2848
3033
  }
@@ -2911,6 +3096,24 @@ const ${groupName}Layer = HttpApiBuilder.group(
2911
3096
  }),
2912
3097
  ),
2913
3098
  )
3099
+ .handle('readiness', () =>
3100
+ Effect.succeed({
3101
+ checks: {
3102
+ effectBff: 'ready' as const,
3103
+ moduleFederation: 'ready' as const,
3104
+ ssr: 'ready' as const,
3105
+ translations: 'ready' as const,
3106
+ },
3107
+ marker: ultramodernApiMarker,
3108
+ status: 'ready' as const,
3109
+ versionSkew: 'none' as const,
3110
+ }).pipe(
3111
+ Effect.withSpan('ultramodern.effect.${groupName}.readiness', {
3112
+ attributes: operationAttributes(${groupName}OperationContexts.readiness),
3113
+ kind: 'server',
3114
+ }),
3115
+ ),
3116
+ )
2914
3117
  .handle('get', ({ params }) => {
2915
3118
  const item = ${groupName}Items.find(item => item.id === params.id);
2916
3119
  return (item !== undefined
@@ -2960,6 +3163,7 @@ function createEffectClient(service, contractImportPath) {
2960
3163
  const clientOptionsName = `${toPascalCase(stem)}ClientOptions`;
2961
3164
  const createClientName = `create${toPascalCase(stem)}Client`;
2962
3165
  const listName = `list${toPascalCase(stem)}`;
3166
+ const readinessName = `get${toPascalCase(stem)}Readiness`;
2963
3167
  const getName = `get${toPascalCase(singular)}`;
2964
3168
  const createName = `create${toPascalCase(singular)}`;
2965
3169
  return `import {
@@ -3004,6 +3208,20 @@ export function ${listName}(
3004
3208
  );
3005
3209
  }
3006
3210
 
3211
+ export function ${readinessName}(
3212
+ options: ${clientOptionsName} = {},
3213
+ ) {
3214
+ return runEffectRequest(
3215
+ ${createClientName}({
3216
+ ...options,
3217
+ operationContext:
3218
+ options.operationContext ?? ${groupName}OperationContexts.readiness,
3219
+ }),
3220
+ ).then(client =>
3221
+ runEffectRequest(client.${groupName}.readiness({})),
3222
+ );
3223
+ }
3224
+
3007
3225
  export function ${getName}(
3008
3226
  id: string,
3009
3227
  options: ${clientOptionsName} = {},
@@ -3039,17 +3257,141 @@ export function ${createName}(
3039
3257
  }
3040
3258
  function createShellEffectClient(scope) {
3041
3259
  return `export {
3042
- createRecommendation,
3043
- createRecommendationsClient,
3044
- getRecommendation,
3045
- listRecommendations,
3046
- type RecommendationsClientOptions,
3047
- } from '${ultramodern_workspace_packageName(scope, 'remote-commerce')}/effect/client';
3260
+ createCheckout,
3261
+ createCheckoutClient,
3262
+ getCheckout,
3263
+ getCheckoutReadiness,
3264
+ listCheckout,
3265
+ type CheckoutClientOptions,
3266
+ } from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/effect/client';
3267
+
3268
+ export {
3269
+ createDecide,
3270
+ createDecideClient,
3271
+ getDecide,
3272
+ getDecideReadiness,
3273
+ listDecide,
3274
+ type DecideClientOptions,
3275
+ } from '${ultramodern_workspace_packageName(scope, 'remote-decide')}/effect/client';
3276
+
3277
+ export {
3278
+ createExplore,
3279
+ createExploreClient,
3280
+ getExplore,
3281
+ getExploreReadiness,
3282
+ listExplore,
3283
+ type ExploreClientOptions,
3284
+ } from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/effect/client';
3048
3285
  `;
3049
3286
  }
3050
3287
  function toPascalCase(value) {
3051
3288
  return value.split(/[-_]+/).filter(Boolean).map((part)=>`${part.charAt(0).toUpperCase()}${part.slice(1)}`).join('');
3052
3289
  }
3290
+ function createEffectReadinessContract(app) {
3291
+ const stem = effectApiStem(app);
3292
+ return {
3293
+ endpoint: `/effect/${stem}/readiness`,
3294
+ marker: {
3295
+ ui: 'ultramodernUiMarker',
3296
+ api: 'ultramodernApiMarker',
3297
+ skew: 'none'
3298
+ },
3299
+ checks: [
3300
+ 'moduleFederation',
3301
+ 'ssr',
3302
+ 'translations',
3303
+ 'effectBff'
3304
+ ]
3305
+ };
3306
+ }
3307
+ function createEffectRequestContextContract() {
3308
+ return {
3309
+ propagatedHeaders: [
3310
+ 'accept-language',
3311
+ 'authorization',
3312
+ 'traceparent',
3313
+ 'x-correlation-id',
3314
+ 'x-tenant-id',
3315
+ 'x-ultramodern-env',
3316
+ 'x-vertical-version-id'
3317
+ ],
3318
+ source: 'shell-to-vertical-effect-client'
3319
+ };
3320
+ }
3321
+ function createEffectDomainOperations(app) {
3322
+ const stem = effectApiStem(app);
3323
+ const group = serviceEffectGroupName(app);
3324
+ const basePath = `/effect/${stem}`;
3325
+ if ('checkout' === stem) return {
3326
+ cartSnapshot: {
3327
+ client: 'listCheckout',
3328
+ method: 'GET',
3329
+ path: basePath,
3330
+ resource: 'cart',
3331
+ owner: app.id
3332
+ },
3333
+ cartMutation: {
3334
+ client: 'createCheckout',
3335
+ method: 'POST',
3336
+ path: basePath,
3337
+ resource: 'cart-line',
3338
+ owner: app.id
3339
+ },
3340
+ orderConfirmation: {
3341
+ client: 'getCheckout',
3342
+ method: 'GET',
3343
+ path: `${basePath}/:id`,
3344
+ resource: 'order',
3345
+ owner: app.id
3346
+ }
3347
+ };
3348
+ if ('decide' === stem) return {
3349
+ productDetail: {
3350
+ client: 'getDecide',
3351
+ method: 'GET',
3352
+ path: `${basePath}/:id`,
3353
+ resource: 'product-detail',
3354
+ owner: app.id
3355
+ },
3356
+ configurationDraft: {
3357
+ client: 'createDecide',
3358
+ method: 'POST',
3359
+ path: basePath,
3360
+ resource: 'configuration',
3361
+ owner: app.id
3362
+ },
3363
+ productList: {
3364
+ client: 'listDecide',
3365
+ method: 'GET',
3366
+ path: basePath,
3367
+ resource: 'products',
3368
+ owner: app.id
3369
+ }
3370
+ };
3371
+ return {
3372
+ recommendationFeed: {
3373
+ client: `list${toPascalCase(stem)}`,
3374
+ method: 'GET',
3375
+ path: basePath,
3376
+ resource: 'recommendations',
3377
+ owner: app.id
3378
+ },
3379
+ recommendationDetail: {
3380
+ client: `get${toPascalCase(serviceEffectErrorStem(app))}`,
3381
+ method: 'GET',
3382
+ path: `${basePath}/:id`,
3383
+ resource: 'recommendation',
3384
+ owner: app.id
3385
+ },
3386
+ recommendationCreate: {
3387
+ client: `create${toPascalCase(serviceEffectErrorStem(app))}`,
3388
+ method: 'POST',
3389
+ path: basePath,
3390
+ resource: group,
3391
+ owner: app.id
3392
+ }
3393
+ };
3394
+ }
3053
3395
  function effectApiTopologyMetadata(app) {
3054
3396
  if (!appHasEffectApi(app)) return;
3055
3397
  return {
@@ -3069,7 +3411,10 @@ function effectApiTopologyMetadata(app) {
3069
3411
  },
3070
3412
  serverEntry: `${app.directory}/api/effect/index.ts`,
3071
3413
  basePath: `${app.effectApi.prefix}/effect/${app.effectApi.stem}`,
3072
- consumedBy: app.effectApi.consumedBy
3414
+ consumedBy: app.effectApi.consumedBy,
3415
+ readiness: createEffectReadinessContract(app),
3416
+ requestContext: createEffectRequestContextContract(),
3417
+ domainOperations: createEffectDomainOperations(app)
3073
3418
  }
3074
3419
  };
3075
3420
  }
@@ -3088,14 +3433,11 @@ function createTopology(scope) {
3088
3433
  moduleFederation: {
3089
3434
  role: 'host',
3090
3435
  name: shellApp.mfName,
3091
- remotes: remoteApps.map((remote)=>({
3092
- id: remote.id,
3093
- name: remote.mfName,
3094
- manifestUrl: `http://localhost:${remote.port}/mf-manifest.json`
3095
- })),
3436
+ remotes: createModuleFederationRemoteContracts(shellApp),
3096
3437
  ssr: true,
3097
3438
  sharedContractVersion: 'mf-ssr-contract-v1'
3098
3439
  },
3440
+ cloudflare: createCloudflareDeployContract(scope, shellApp),
3099
3441
  ownership: shellApp.ownership
3100
3442
  },
3101
3443
  remotes: remoteApps.map((remote)=>({
@@ -3108,6 +3450,10 @@ function createTopology(scope) {
3108
3450
  name: remote.mfName,
3109
3451
  manifestUrl: `http://localhost:${remote.port}/mf-manifest.json`,
3110
3452
  exposes: Object.keys(remote.exposes ?? {}),
3453
+ ...remote.remoteRefs?.length ? {
3454
+ remoteRefs: remote.remoteRefs,
3455
+ remotes: createModuleFederationRemoteContracts(remote)
3456
+ } : {},
3111
3457
  ssr: true,
3112
3458
  fallbackTelemetryEvent: 'modernjs:mv-runtime-parity',
3113
3459
  sharedContractVersion: 'mf-ssr-contract-v1'
@@ -3115,6 +3461,7 @@ function createTopology(scope) {
3115
3461
  ...effectApiTopologyMetadata(remote) ? {
3116
3462
  api: effectApiTopologyMetadata(remote)
3117
3463
  } : {},
3464
+ cloudflare: createCloudflareDeployContract(scope, remote),
3118
3465
  ownership: remote.ownership
3119
3466
  })),
3120
3467
  effectServices: [],
@@ -3225,6 +3572,11 @@ function createEffectOperationContract(target) {
3225
3572
  path: `/effect/${stem}`,
3226
3573
  source: 'generated-client'
3227
3574
  },
3575
+ readiness: {
3576
+ method: 'GET',
3577
+ path: `/effect/${stem}/readiness`,
3578
+ source: 'generated-client'
3579
+ },
3228
3580
  get: {
3229
3581
  method: 'GET',
3230
3582
  path: `/effect/${stem}/:id`,
@@ -3281,7 +3633,143 @@ function createAppConfigContract(app) {
3281
3633
  } : {}
3282
3634
  };
3283
3635
  }
3284
- function createStylingContract(enableTailwind) {
3636
+ function cssLayerName(app) {
3637
+ if ('shell' === app.kind) return 'ultramodern-shell-base';
3638
+ return `ultramodern-remote-${app.domain ?? app.id}`;
3639
+ }
3640
+ function cssRole(app) {
3641
+ if ('shell' === app.kind) return 'shell-base-overlay';
3642
+ return 'horizontal-remote' === app.kind ? 'horizontal-remote-css' : 'vertical-remote-css';
3643
+ }
3644
+ function cssClassPrefix(app) {
3645
+ if ('shell' === app.kind) return 'shell-';
3646
+ return `${app.domain ?? app.id.replace(/^remote-/, '')}-`;
3647
+ }
3648
+ function createCssDedupeContract(scope) {
3649
+ return {
3650
+ strategy: 'shared-token-package-plus-css-content-hash',
3651
+ sharedPackage: ultramodern_workspace_packageName(scope, 'shared-design-tokens'),
3652
+ sharedLayers: [
3653
+ 'ultramodern-shared-tokens'
3654
+ ],
3655
+ runtimeLoad: 'once-per-content-hash',
3656
+ duplicateBaseStylesAllowed: false
3657
+ };
3658
+ }
3659
+ function createCssSsrContract(app) {
3660
+ return {
3661
+ cloudflare: true,
3662
+ firstPaintRequired: true,
3663
+ linkEmission: 'modern-ssr-css-assets',
3664
+ remoteCss: 'shell' === app.kind ? 'host-preloads-shell-and-shared-css' : 'remote-manifest-owned-css'
3665
+ };
3666
+ }
3667
+ function createAppCssFederationContract(scope, app) {
3668
+ const ownedLayers = 'shell' === app.kind ? [
3669
+ 'ultramodern-shell-base',
3670
+ 'ultramodern-shell-overlay'
3671
+ ] : [
3672
+ cssLayerName(app)
3673
+ ];
3674
+ return {
3675
+ owner: {
3676
+ id: app.id,
3677
+ package: ultramodern_workspace_packageName(scope, app.packageSuffix),
3678
+ team: app.ownership.team
3679
+ },
3680
+ role: cssRole(app),
3681
+ rootSelector: `[data-app-id="${app.id}"]`,
3682
+ classPrefix: cssClassPrefix(app),
3683
+ layers: {
3684
+ shared: [
3685
+ 'ultramodern-shared-tokens'
3686
+ ],
3687
+ owned: ownedLayers,
3688
+ imports: 'shell' === app.kind ? [
3689
+ 'ultramodern-shared-tokens'
3690
+ ] : [
3691
+ 'ultramodern-shared-tokens'
3692
+ ]
3693
+ },
3694
+ entrypoints: {
3695
+ layoutImport: 'src/routes/layout.tsx',
3696
+ css: [
3697
+ 'src/routes/index.css'
3698
+ ],
3699
+ ...'shell' !== app.kind ? {
3700
+ remoteEntry: 'src/remote-entry.tsx'
3701
+ } : {}
3702
+ },
3703
+ assets: {
3704
+ shared: [
3705
+ `${ultramodern_workspace_packageName(scope, 'shared-design-tokens')}/tokens.css`
3706
+ ],
3707
+ owned: [
3708
+ 'src/routes/index.css'
3709
+ ],
3710
+ emittedBy: 'modern-rspack-css-extraction',
3711
+ contentHash: true
3712
+ },
3713
+ dedupe: createCssDedupeContract(scope),
3714
+ ssr: createCssSsrContract(app)
3715
+ };
3716
+ }
3717
+ function createCssFederationContract(scope) {
3718
+ return {
3719
+ schemaVersion: 1,
3720
+ sharedDesignTokens: {
3721
+ owner: {
3722
+ id: 'shared-design-tokens',
3723
+ package: ultramodern_workspace_packageName(scope, 'shared-design-tokens'),
3724
+ team: 'super-app-platform'
3725
+ },
3726
+ role: 'shared-design-tokens',
3727
+ rootSelector: ':root',
3728
+ classPrefix: '--um-',
3729
+ layers: {
3730
+ owned: [
3731
+ 'ultramodern-shared-tokens'
3732
+ ]
3733
+ },
3734
+ entrypoints: {
3735
+ css: [
3736
+ 'packages/shared-design-tokens/src/tokens.css'
3737
+ ],
3738
+ typescript: [
3739
+ 'packages/shared-design-tokens/src/index.ts'
3740
+ ]
3741
+ },
3742
+ assets: {
3743
+ exports: [
3744
+ './tokens.css'
3745
+ ],
3746
+ css: [
3747
+ 'packages/shared-design-tokens/src/tokens.css'
3748
+ ]
3749
+ },
3750
+ dedupe: createCssDedupeContract(scope),
3751
+ ssr: {
3752
+ cloudflare: true,
3753
+ firstPaintRequired: true,
3754
+ importedByApps: true
3755
+ }
3756
+ },
3757
+ ownershipRules: {
3758
+ shell: [
3759
+ 'base',
3760
+ 'overlay'
3761
+ ],
3762
+ remotes: [
3763
+ 'vertical-css'
3764
+ ],
3765
+ forbiddenRemoteLayers: [
3766
+ 'ultramodern-shell-base',
3767
+ 'ultramodern-shell-overlay'
3768
+ ]
3769
+ }
3770
+ };
3771
+ }
3772
+ function createStylingContract(scope, app, enableTailwind) {
3285
3773
  return {
3286
3774
  tailwind: enableTailwind,
3287
3775
  ...enableTailwind ? {
@@ -3291,21 +3779,28 @@ function createStylingContract(enableTailwind) {
3291
3779
  contentGlobs: [
3292
3780
  './src/**/*.{js,jsx,ts,tsx}'
3293
3781
  ]
3294
- } : {}
3782
+ } : {},
3783
+ federation: createAppCssFederationContract(scope, app)
3295
3784
  };
3296
3785
  }
3297
3786
  function createAppGeneratedContract(scope, app, apps, enableTailwind) {
3298
- const remoteAppsForShell = apps.filter((candidate)=>'shell' !== candidate.kind && candidate.mfName);
3787
+ const appWithResolvedRefs = 'shell' === app.kind ? {
3788
+ ...app,
3789
+ remoteRefs: apps.filter((candidate)=>'shell' !== candidate.kind).map((candidate)=>candidate.id)
3790
+ } : app;
3791
+ const consumedRemotes = createModuleFederationRemoteContracts(appWithResolvedRefs, apps);
3299
3792
  return {
3300
3793
  id: app.id,
3301
3794
  package: ultramodern_workspace_packageName(scope, app.packageSuffix),
3302
3795
  path: app.directory,
3303
3796
  kind: app.kind,
3304
3797
  config: createAppConfigContract(app),
3305
- styling: createStylingContract(enableTailwind),
3798
+ styling: createStylingContract(scope, app, enableTailwind),
3306
3799
  deploy: {
3307
3800
  target: 'cloudflare',
3801
+ cloudflare: createCloudflareDeployContract(scope, app),
3308
3802
  worker: {
3803
+ name: createCloudflareWorkerName(scope, app),
3309
3804
  ssr: true
3310
3805
  },
3311
3806
  output: {
@@ -3319,25 +3814,42 @@ function createAppGeneratedContract(scope, app, apps, enableTailwind) {
3319
3814
  },
3320
3815
  i18n: {
3321
3816
  plugin: '@modern-js/plugin-i18n',
3322
- backend: false,
3817
+ backend: {
3818
+ enabled: true,
3819
+ loadPath: '/locales/{{lng}}/{{ns}}.json'
3820
+ },
3323
3821
  reactI18next: false,
3324
3822
  languages: [
3325
3823
  'en',
3326
3824
  'cs'
3327
3825
  ],
3328
3826
  fallbackLanguage: 'en',
3329
- publicDir: './locales'
3827
+ namespace: appI18nNamespace(app),
3828
+ namespaces: [
3829
+ appI18nNamespace(app),
3830
+ 'translation'
3831
+ ],
3832
+ publicDir: './locales',
3833
+ localisedUrls: createLocalisedUrlsMap(app),
3834
+ resourceOwnership: {
3835
+ ownerAppId: app.id,
3836
+ source: 'route-owned',
3837
+ staticJson: `./locales/{lng}/${appI18nNamespace(app)}.json`
3838
+ }
3839
+ },
3840
+ routes: {
3841
+ source: 'route-owned',
3842
+ metadataExport: './src/routes/ultramodern-route-metadata',
3843
+ localisedUrls: createLocalisedUrlsMap(app),
3844
+ owned: createRouteOwnedI18nPaths(app),
3845
+ generatedRouteMap: true,
3846
+ manualOverrides: []
3330
3847
  },
3331
3848
  moduleFederation: {
3332
3849
  name: app.mfName,
3333
- ...'shell' === app.kind ? {
3334
- remotes: remoteAppsForShell.map((remote)=>({
3335
- id: remote.id,
3336
- alias: remoteDependencyAlias(remote),
3337
- name: remote.mfName,
3338
- manifestEnv: createRemoteManifestEnv(remote),
3339
- manifestUrl: `http://localhost:${remote.port}/mf-manifest.json`
3340
- }))
3850
+ ...appWithResolvedRefs.remoteRefs?.length ? {
3851
+ remoteRefs: appWithResolvedRefs.remoteRefs,
3852
+ remotes: consumedRemotes
3341
3853
  } : {},
3342
3854
  exposes: Object.keys(app.exposes ?? {}),
3343
3855
  dts: {
@@ -3358,48 +3870,6 @@ function createAppGeneratedContract(scope, app, apps, enableTailwind) {
3358
3870
  apiSurface: 'effect-bff'
3359
3871
  } : {}
3360
3872
  },
3361
- ...'commerce' === app.domain ? {
3362
- boundaryVisualization: {
3363
- mode: 'overlay',
3364
- layoutAffecting: false,
3365
- toggle: 'user-controlled',
3366
- boundaries: [
3367
- {
3368
- id: 'explore',
3369
- labelKey: 'commerce.boundaries.explore',
3370
- owner: 'team-explore',
3371
- color: '#ff5a57',
3372
- owns: [
3373
- 'header',
3374
- 'footer',
3375
- 'recommendations',
3376
- 'catalog'
3377
- ]
3378
- },
3379
- {
3380
- id: 'decide',
3381
- labelKey: 'commerce.boundaries.decide',
3382
- owner: 'team-decide',
3383
- color: '#24d671',
3384
- owns: [
3385
- 'product-detail',
3386
- 'variant-selection'
3387
- ]
3388
- },
3389
- {
3390
- id: 'checkout',
3391
- labelKey: 'commerce.boundaries.checkout',
3392
- owner: 'team-checkout',
3393
- color: '#f4d044',
3394
- owns: [
3395
- 'add-to-cart',
3396
- 'cart-link',
3397
- 'cart-lines'
3398
- ]
3399
- }
3400
- ]
3401
- }
3402
- } : {},
3403
3873
  ...appHasEffectApi(app) ? {
3404
3874
  effect: {
3405
3875
  runtime: 'effect',
@@ -3409,6 +3879,9 @@ function createAppGeneratedContract(scope, app, apps, enableTailwind) {
3409
3879
  workerEntry: 'worker/__modern_bff_effect.js',
3410
3880
  contract: './shared/effect/api',
3411
3881
  client: './effect/client',
3882
+ readiness: createEffectReadinessContract(app),
3883
+ requestContext: createEffectRequestContextContract(),
3884
+ domainOperations: createEffectDomainOperations(app),
3412
3885
  ...createEffectOperationContract(app)
3413
3886
  }
3414
3887
  } : {}
@@ -3437,6 +3910,7 @@ function createGeneratedContract(scope, apps = [
3437
3910
  zephyrAgent: ZEPHYR_AGENT_VERSION,
3438
3911
  wrangler: WRANGLER_VERSION
3439
3912
  },
3913
+ cssFederation: createCssFederationContract(scope),
3440
3914
  apps: apps.map((app)=>createAppGeneratedContract(scope, app, apps, enableTailwind))
3441
3915
  };
3442
3916
  }
@@ -3559,16 +4033,670 @@ function createTemplateManifest(modernVersion, packageSource) {
3559
4033
  }
3560
4034
  };
3561
4035
  }
4036
+ function createAssertMfTypesScript(remotes = remoteApps) {
4037
+ return `import fs from 'node:fs';
4038
+ import path from 'node:path';
4039
+
4040
+ const root = process.cwd();
4041
+ const generatedContractPath = path.join(
4042
+ root,
4043
+ '.modernjs/ultramodern-generated-contract.json',
4044
+ );
4045
+ const generatedContract = fs.existsSync(generatedContractPath)
4046
+ ? JSON.parse(fs.readFileSync(generatedContractPath, 'utf-8'))
4047
+ : undefined;
4048
+ const defaultAppDirs = ${JSON.stringify(remotes.map((remote)=>remote.directory), null, 2)};
4049
+
4050
+ const candidateDirs = process.argv.slice(2);
4051
+ const appDirs = candidateDirs.length
4052
+ ? candidateDirs
4053
+ : fs.existsSync(path.join(root, 'module-federation.config.ts'))
4054
+ ? ['.']
4055
+ : defaultAppDirs;
4056
+
4057
+ for (const appDir of appDirs) {
4058
+ const configPath = path.join(root, appDir, 'module-federation.config.ts');
4059
+ if (!fs.existsSync(configPath)) {
4060
+ throw new Error(
4061
+ \`Missing Module Federation config: \${path.relative(root, configPath)}\`,
4062
+ );
4063
+ }
4064
+
4065
+ const contractEntry = generatedContract?.apps?.find(
4066
+ app => app.path === appDir.replace(/\\\\/g, '/'),
4067
+ );
4068
+ if (
4069
+ contractEntry &&
4070
+ contractEntry.moduleFederation?.dts?.compilerInstance !==
4071
+ '--package typescript -- tsc'
4072
+ ) {
4073
+ throw new Error(
4074
+ \`Module Federation DTS must use the workspace TypeScript compiler: \${appDir}\`,
4075
+ );
4076
+ }
4077
+
4078
+ if (contractEntry && contractEntry.moduleFederation?.exposes?.length === 0) {
4079
+ continue;
4080
+ }
4081
+
4082
+ const typesArchivePath = path.join(root, appDir, 'dist/@mf-types.zip');
4083
+ if (!fs.existsSync(typesArchivePath)) {
4084
+ throw new Error(
4085
+ \`Missing Module Federation DTS archive: \${path.relative(root, typesArchivePath)}\`,
4086
+ );
4087
+ }
4088
+
4089
+ const stats = fs.statSync(typesArchivePath);
4090
+ if (stats.size === 0) {
4091
+ throw new Error(
4092
+ \`Empty Module Federation DTS archive: \${path.relative(root, typesArchivePath)}\`,
4093
+ );
4094
+ }
4095
+ }
4096
+ `;
4097
+ }
4098
+ function createWorkspaceValidationScript(scope, enableTailwind, remotes = remoteApps) {
4099
+ const verticals = remotes.filter(appHasEffectApi).map((remote)=>({
4100
+ id: remote.id,
4101
+ domain: remote.domain,
4102
+ stem: remote.effectApi.stem,
4103
+ group: serviceEffectGroupName(remote),
4104
+ path: remote.directory,
4105
+ mfName: remote.mfName,
4106
+ apiPrefix: remote.effectApi.prefix,
4107
+ packageName: ultramodern_workspace_packageName(scope, remote.packageSuffix),
4108
+ exposes: Object.keys(remote.exposes ?? {}),
4109
+ componentPaths: Object.keys(remote.exposes ?? {}).map((expose)=>remoteComponentOutputPath(remote, expose)).filter((componentPath)=>Boolean(componentPath)),
4110
+ namespace: appI18nNamespace(remote),
4111
+ routePagePaths: createRouteOwnedI18nPaths(remote).filter((route)=>'/' !== route.canonicalPath).map((route)=>createRoutePageFilePath(remote, route.canonicalPath)),
4112
+ localisedUrls: createLocalisedUrlsMap(remote),
4113
+ remoteRefs: remote.remoteRefs ?? []
4114
+ }));
4115
+ const shellNamespace = appI18nNamespace(shellApp);
4116
+ const oldRemotePaths = [
4117
+ 'apps/remotes/remote-commerce',
4118
+ 'apps/remotes/remote-identity',
4119
+ 'apps/remotes/remote-design-system'
4120
+ ];
4121
+ return `import { execFileSync } from 'node:child_process';
4122
+ import fs from 'node:fs';
4123
+ import path from 'node:path';
4124
+
4125
+ const root = process.cwd();
4126
+ const packageScope = '${scope}';
4127
+ const expectedPnpmVersion = '${PNPM_VERSION}';
4128
+ const tailwindEnabled = ${JSON.stringify(enableTailwind)};
4129
+ const fullStackVerticals = ${JSON.stringify(verticals, null, 2)};
4130
+ const shellNamespace = ${JSON.stringify(shellNamespace)};
4131
+ const oldRemotePaths = ${JSON.stringify(oldRemotePaths, null, 2)};
4132
+
4133
+ const readText = relativePath => fs.readFileSync(path.join(root, relativePath), 'utf-8');
4134
+ const readJson = relativePath => JSON.parse(readText(relativePath));
4135
+ const assert = (condition, message) => {
4136
+ if (!condition) {
4137
+ throw new Error(message);
4138
+ }
4139
+ };
4140
+ const assertExists = relativePath => {
4141
+ assert(fs.existsSync(path.join(root, relativePath)), \`Missing \${relativePath}\`);
4142
+ };
4143
+ const assertNotExists = relativePath => {
4144
+ assert(!fs.existsSync(path.join(root, relativePath)), \`Unexpected \${relativePath}\`);
4145
+ };
4146
+ const expectedWorkerName = packageSuffix => \`\${packageScope}-\${packageSuffix}\`.slice(0, 63);
4147
+
4148
+ const activePnpmVersion = execFileSync('pnpm', ['--version'], {
4149
+ cwd: root,
4150
+ encoding: 'utf-8',
4151
+ stdio: ['ignore', 'pipe', 'pipe'],
4152
+ }).trim();
4153
+
4154
+ assert(
4155
+ activePnpmVersion === expectedPnpmVersion,
4156
+ \`Generated workspace requires pnpm \${expectedPnpmVersion}; active pnpm is \${activePnpmVersion}. Run mise install, then rerun through mise exec -- pnpm ...\`,
4157
+ );
4158
+
4159
+ const requiredPaths = [
4160
+ 'AGENTS.md',
4161
+ '.gitignore',
4162
+ 'package.json',
4163
+ 'pnpm-workspace.yaml',
4164
+ 'tsconfig.base.json',
4165
+ 'oxlint.config.ts',
4166
+ 'oxfmt.config.ts',
4167
+ '.github/renovate.json',
4168
+ '.github/workflows/ultramodern-workspace-gates.yml',
4169
+ '.agents/skills-lock.json',
4170
+ '.agents/agent-reference-repos.json',
4171
+ '.agents/rstackjs-agent-skills-LICENSE',
4172
+ 'topology/reference-topology.json',
4173
+ 'topology/ownership.json',
4174
+ 'topology/local-overlays/development.json',
4175
+ '.modernjs/ultramodern-workspace-template-manifest.json',
4176
+ '.modernjs/ultramodern-package-source.json',
4177
+ '.modernjs/ultramodern-generated-contract.json',
4178
+ 'scripts/assert-mf-types.mjs',
4179
+ 'scripts/bootstrap-agent-skills.mjs',
4180
+ 'scripts/proof-cloudflare-version.mjs',
4181
+ 'scripts/setup-agent-reference-repos.mjs',
4182
+ 'apps/shell-super-app/package.json',
4183
+ 'apps/shell-super-app/modern.config.ts',
4184
+ 'apps/shell-super-app/module-federation.config.ts',
4185
+ 'apps/shell-super-app/src/modern-app-env.d.ts',
4186
+ 'apps/shell-super-app/src/modern.runtime.ts',
4187
+ 'apps/shell-super-app/src/effect/recommendations-client.ts',
4188
+ 'apps/shell-super-app/locales/en/translation.json',
4189
+ \`apps/shell-super-app/locales/en/\${shellNamespace}.json\`,
4190
+ 'apps/shell-super-app/locales/cs/translation.json',
4191
+ \`apps/shell-super-app/locales/cs/\${shellNamespace}.json\`,
4192
+ 'apps/shell-super-app/src/routes/index.css',
4193
+ 'apps/shell-super-app/src/routes/layout.tsx',
4194
+ 'apps/shell-super-app/src/routes/ultramodern-route-metadata.ts',
4195
+ 'apps/shell-super-app/src/routes/[lang]/page.tsx',
4196
+ 'packages/shared-contracts/src/index.ts',
4197
+ 'packages/shared-design-tokens/src/index.ts',
4198
+ 'packages/shared-design-tokens/src/tokens.css',
4199
+ 'packages/shared-effect-api/src/index.ts',
4200
+ ];
4201
+
4202
+ for (const vertical of fullStackVerticals) {
4203
+ requiredPaths.push(
4204
+ \`\${vertical.path}/package.json\`,
4205
+ \`\${vertical.path}/modern.config.ts\`,
4206
+ \`\${vertical.path}/module-federation.config.ts\`,
4207
+ \`\${vertical.path}/api/effect/index.ts\`,
4208
+ \`\${vertical.path}/shared/effect/api.ts\`,
4209
+ \`\${vertical.path}/src/effect/\${vertical.stem}-client.ts\`,
4210
+ \`\${vertical.path}/src/modern-app-env.d.ts\`,
4211
+ \`\${vertical.path}/src/modern.runtime.ts\`,
4212
+ \`\${vertical.path}/src/remote-entry.tsx\`,
4213
+ ...vertical.componentPaths,
4214
+ \`\${vertical.path}/locales/en/translation.json\`,
4215
+ \`\${vertical.path}/locales/en/\${vertical.namespace}.json\`,
4216
+ \`\${vertical.path}/locales/cs/translation.json\`,
4217
+ \`\${vertical.path}/locales/cs/\${vertical.namespace}.json\`,
4218
+ \`\${vertical.path}/src/routes/index.css\`,
4219
+ \`\${vertical.path}/src/routes/layout.tsx\`,
4220
+ \`\${vertical.path}/src/routes/ultramodern-route-metadata.ts\`,
4221
+ \`\${vertical.path}/src/routes/[lang]/page.tsx\`,
4222
+ ...vertical.routePagePaths,
4223
+ );
4224
+ }
4225
+
4226
+ if (tailwindEnabled) {
4227
+ requiredPaths.push(
4228
+ 'apps/shell-super-app/postcss.config.mjs',
4229
+ 'apps/shell-super-app/tailwind.config.ts',
4230
+ ...fullStackVerticals.flatMap(vertical => [
4231
+ \`\${vertical.path}/postcss.config.mjs\`,
4232
+ \`\${vertical.path}/tailwind.config.ts\`,
4233
+ ]),
4234
+ );
4235
+ }
4236
+
4237
+ for (const requiredPath of requiredPaths) {
4238
+ assertExists(requiredPath);
4239
+ }
4240
+ for (const oldRemotePath of oldRemotePaths) {
4241
+ assertNotExists(oldRemotePath);
4242
+ }
4243
+ assertNotExists('services/service-recommendations-effect');
4244
+
4245
+ const rootPackage = readJson('package.json');
4246
+ const packageSource = readJson('.modernjs/ultramodern-package-source.json');
4247
+ const generatedContract = readJson('.modernjs/ultramodern-generated-contract.json');
4248
+ const topology = readJson('topology/reference-topology.json');
4249
+ const ownership = readJson('topology/ownership.json');
4250
+ const overlay = readJson('topology/local-overlays/development.json');
4251
+
4252
+ assert(rootPackage.private === true, 'Root package must be private');
4253
+ assert(rootPackage.packageManager === \`pnpm@\${expectedPnpmVersion}\`, 'Root must pin pnpm');
4254
+ assert(rootPackage.modernjs?.preset === 'presetUltramodern', 'Root must declare presetUltramodern');
4255
+ assert(rootPackage.modernjs?.packageSource?.config === './.modernjs/ultramodern-package-source.json', 'Root must point at package source metadata');
4256
+ assert(rootPackage.modernjs?.packageSource?.strategy === packageSource.strategy, 'Root package source strategy must match metadata');
4257
+ assert(packageSource.strategy === 'workspace' || packageSource.strategy === 'install', 'Package source strategy must be workspace or install');
4258
+ assert(packageSource.generatedWorkspacePackages?.specifier === 'workspace:*', 'Generated workspace packages must keep workspace:* links');
4259
+ assert(
4260
+ rootPackage.scripts?.build ===
4261
+ 'pnpm -r --filter "./apps/remotes/**" run build && pnpm --filter "./apps/shell-super-app" run build && pnpm ultramodern:assert-mf-types',
4262
+ 'Root build script must build remotes before shell',
4263
+ );
4264
+ assert(rootPackage.scripts?.['ultramodern:check'] === 'node ./scripts/validate-ultramodern-workspace.mjs', 'Root must expose ultramodern:check');
4265
+ assert(rootPackage.scripts?.['ultramodern:assert-mf-types'] === 'node ./scripts/assert-mf-types.mjs', 'Root must expose ultramodern:assert-mf-types');
4266
+ assert(rootPackage.scripts?.['cloudflare:deploy']?.includes('run cloudflare:deploy'), 'Root must expose cloudflare:deploy');
4267
+ assert(rootPackage.scripts?.['cloudflare:proof'] === 'node ./scripts/proof-cloudflare-version.mjs --out .codex/reports/cloudflare-version-proof/public-url-proof.json', 'Root must expose cloudflare:proof');
4268
+
4269
+ const expectedAppIds = ['shell-super-app', ...fullStackVerticals.map(vertical => vertical.id)];
4270
+ assert(
4271
+ JSON.stringify(generatedContract.apps?.map(app => app.id)) === JSON.stringify(expectedAppIds),
4272
+ 'Generated contract must contain shell plus the Tractor full-stack remotes',
4273
+ );
4274
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.owner?.id === 'shared-design-tokens', 'CSS federation must declare shared design token ownership');
4275
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.role === 'shared-design-tokens', 'CSS federation must mark shared-design-tokens as token owner');
4276
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.rootSelector === ':root', 'Shared design tokens must declare their root selector');
4277
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.classPrefix === '--um-', 'Shared design tokens must declare their CSS custom property prefix');
4278
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.layers?.owned?.includes('ultramodern-shared-tokens'), 'Shared design tokens must own the shared token CSS layer');
4279
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.entrypoints?.css?.includes('packages/shared-design-tokens/src/tokens.css'), 'Shared design tokens must declare their CSS entrypoint');
4280
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.assets?.exports?.includes('./tokens.css'), 'Shared design tokens must export their CSS asset');
4281
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.dedupe?.duplicateBaseStylesAllowed === false, 'Shared design token CSS must be deduplicated');
4282
+ assert(generatedContract.cssFederation?.sharedDesignTokens?.ssr?.firstPaintRequired === true, 'Shared design token CSS must be required for SSR first paint');
4283
+
4284
+ const shellPackage = readJson('apps/shell-super-app/package.json');
4285
+ const expectedZephyrDependencies = Object.fromEntries(
4286
+ fullStackVerticals.map(vertical => [
4287
+ vertical.domain,
4288
+ \`\${vertical.packageName}@workspace:*\`,
4289
+ ]),
4290
+ );
4291
+ assert(
4292
+ JSON.stringify(shellPackage['zephyr:dependencies']) ===
4293
+ JSON.stringify(expectedZephyrDependencies),
4294
+ 'Shell Zephyr dependencies must reference every Tractor remote package',
4295
+ );
4296
+ const shellContract = generatedContract.apps?.find(app => app.id === 'shell-super-app');
4297
+ assert(shellContract?.deploy?.cloudflare?.workerName === expectedWorkerName('shell-super-app'), 'Shell Cloudflare workerName is incorrect');
4298
+ assert(shellContract?.deploy?.cloudflare?.publicUrlEnv === 'ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP', 'Shell Cloudflare public URL env is incorrect');
4299
+ assert(topology.shell?.cloudflare?.workerName === expectedWorkerName('shell-super-app'), 'Shell topology Cloudflare workerName is incorrect');
4300
+ assert(shellContract?.styling?.federation?.owner?.id === 'shell-super-app', 'Shell CSS federation owner is missing');
4301
+ assert(shellContract?.styling?.federation?.role === 'shell-base-overlay', 'Shell must own base and overlay CSS');
4302
+ assert(shellContract?.styling?.federation?.rootSelector === '[data-app-id="shell-super-app"]', 'Shell CSS root selector is incorrect');
4303
+ assert(shellContract?.styling?.federation?.classPrefix === 'shell-', 'Shell CSS class prefix is incorrect');
4304
+ assert(shellContract?.styling?.federation?.layers?.owned?.includes('ultramodern-shell-base'), 'Shell must own the base CSS layer');
4305
+ assert(shellContract?.styling?.federation?.layers?.owned?.includes('ultramodern-shell-overlay'), 'Shell must own the overlay CSS layer');
4306
+ assert(shellContract?.styling?.federation?.entrypoints?.css?.includes('src/routes/index.css'), 'Shell CSS entrypoint is missing');
4307
+ assert(shellContract?.styling?.federation?.assets?.shared?.some(asset => asset.endsWith('/shared-design-tokens/tokens.css')), 'Shell must import the shared design token CSS asset');
4308
+ assert(shellContract?.styling?.federation?.dedupe?.duplicateBaseStylesAllowed === false, 'Shell CSS contract must forbid duplicated base styles');
4309
+ assert(shellContract?.styling?.federation?.ssr?.firstPaintRequired === true, 'Shell CSS must be required for SSR first paint');
4310
+ assert(
4311
+ topology.shell?.remoteRefs?.join(',') === fullStackVerticals.map(vertical => vertical.id).join(','),
4312
+ 'Topology shell remoteRefs must match Tractor remotes',
4313
+ );
4314
+ assert(topology.remotes?.length === fullStackVerticals.length, 'Topology must contain only Tractor remotes');
4315
+ assert((topology.effectServices ?? []).length === 0, 'Default APIs must be vertical-owned, not effectServices');
4316
+
4317
+ for (const vertical of fullStackVerticals) {
4318
+ const packageJson = readJson(\`\${vertical.path}/package.json\`);
4319
+ assert(packageJson.name === vertical.packageName, \`\${vertical.id} package name is incorrect\`);
4320
+ assert(packageJson.scripts?.['cloudflare:deploy'] === 'MODERNJS_DEPLOY=cloudflare modern deploy', \`\${vertical.id} must expose cloudflare:deploy\`);
4321
+ assert(packageJson.scripts?.['cloudflare:proof']?.includes(\`--app \${vertical.id}\`), \`\${vertical.id} must expose cloudflare:proof\`);
4322
+ assert(packageJson.dependencies?.['@modern-js/plugin-bff'], \`\${vertical.id} must depend on plugin-bff\`);
4323
+ assert(packageJson.exports?.['./effect/client'] === \`./src/effect/\${vertical.stem}-client.ts\`, \`\${vertical.id} must export its Effect client\`);
4324
+ assert(packageJson.exports?.['./shared/effect/api'] === './shared/effect/api.ts', \`\${vertical.id} must export its Effect API contract\`);
4325
+ const expectedVerticalZephyrDependencies = Object.fromEntries(
4326
+ fullStackVerticals
4327
+ .filter(candidate => vertical.remoteRefs.includes(candidate.id))
4328
+ .map(candidate => [
4329
+ candidate.domain,
4330
+ \`\${candidate.packageName}@workspace:*\`,
4331
+ ]),
4332
+ );
4333
+ assert(
4334
+ JSON.stringify(packageJson['zephyr:dependencies']) ===
4335
+ JSON.stringify(expectedVerticalZephyrDependencies),
4336
+ \`\${vertical.id} Zephyr dependencies must match declared MF remote refs\`,
4337
+ );
4338
+
4339
+ const contractEntry = generatedContract.apps?.find(app => app.id === vertical.id);
4340
+ assert(contractEntry?.path === vertical.path, \`\${vertical.id} generated contract path is incorrect\`);
4341
+ assert(contractEntry?.kind === 'vertical', \`\${vertical.id} generated contract kind is incorrect\`);
4342
+ assert(contractEntry?.deploy?.cloudflare?.workerName === expectedWorkerName(vertical.id), \`\${vertical.id} Cloudflare workerName is incorrect\`);
4343
+ assert(contractEntry?.deploy?.cloudflare?.publicUrlEnv === \`ULTRAMODERN_PUBLIC_URL_\${vertical.id.replace(/-/g, '_').toUpperCase()}\`, \`\${vertical.id} Cloudflare public URL env is incorrect\`);
4344
+ assert(contractEntry?.deploy?.cloudflare?.routes?.effectReadiness === \`\${vertical.apiPrefix}/effect/\${vertical.stem}/readiness\`, \`\${vertical.id} Cloudflare proof readiness route is incorrect\`);
4345
+ assert(contractEntry?.moduleFederation?.name === vertical.mfName, \`\${vertical.id} MF name is incorrect\`);
4346
+ assert(JSON.stringify(contractEntry?.moduleFederation?.exposes) === JSON.stringify(vertical.exposes), \`\${vertical.id} MF exposes are incorrect\`);
4347
+ assert(contractEntry?.moduleFederation?.dts?.compilerInstance === '--package typescript -- tsc', \`\${vertical.id} must keep mandatory DTS compiler\`);
4348
+ assert(JSON.stringify(contractEntry?.moduleFederation?.remoteRefs ?? []) === JSON.stringify(vertical.remoteRefs), \`\${vertical.id} MF remoteRefs are incorrect\`);
4349
+ assert(
4350
+ JSON.stringify((contractEntry?.moduleFederation?.remotes ?? []).map(remote => remote.id)) ===
4351
+ JSON.stringify(vertical.remoteRefs),
4352
+ \`\${vertical.id} MF consumed remotes are incorrect\`,
4353
+ );
4354
+ assert(contractEntry?.effect?.prefix === vertical.apiPrefix, \`\${vertical.id} Effect API prefix is incorrect\`);
4355
+ assert(contractEntry?.effect?.group === vertical.group, \`\${vertical.id} Effect group is incorrect\`);
4356
+ assert(contractEntry?.effect?.readiness?.endpoint === \`/effect/\${vertical.stem}/readiness\`, \`\${vertical.id} readiness endpoint is incorrect\`);
4357
+ assert(contractEntry?.effect?.operations?.readiness?.path === \`/effect/\${vertical.stem}/readiness\`, \`\${vertical.id} readiness operation is missing\`);
4358
+ assert(contractEntry?.effect?.requestContext?.propagatedHeaders?.includes('traceparent'), \`\${vertical.id} trace context propagation is missing\`);
4359
+ assert(Object.keys(contractEntry?.effect?.domainOperations ?? {}).length >= 3, \`\${vertical.id} domain operations are missing\`);
4360
+ assert(contractEntry?.i18n?.languages?.includes('en') && contractEntry?.i18n?.languages?.includes('cs'), \`\${vertical.id} must declare i18n languages\`);
4361
+ assert(contractEntry?.i18n?.namespace === vertical.namespace, \`\${vertical.id} i18n namespace is incorrect\`);
4362
+ assert(
4363
+ JSON.stringify(contractEntry?.i18n?.localisedUrls) === JSON.stringify(vertical.localisedUrls),
4364
+ \`\${vertical.id} localisedUrls must come from route metadata\`,
4365
+ );
4366
+ assert(contractEntry?.routes?.source === 'route-owned', \`\${vertical.id} routes must be route-owned\`);
4367
+ assert(contractEntry?.routes?.metadataExport === './src/routes/ultramodern-route-metadata', \`\${vertical.id} route metadata export is incorrect\`);
4368
+ assert(contractEntry?.styling?.federation?.owner?.id === vertical.id, \`\${vertical.id} CSS federation owner is missing\`);
4369
+ assert(contractEntry?.styling?.federation?.role === 'vertical-remote-css', \`\${vertical.id} must own only vertical CSS\`);
4370
+ assert(contractEntry?.styling?.federation?.rootSelector === \`[data-app-id="\${vertical.id}"]\`, \`\${vertical.id} CSS root selector is incorrect\`);
4371
+ assert(contractEntry?.styling?.federation?.classPrefix === \`\${vertical.domain}-\`, \`\${vertical.id} CSS class prefix is incorrect\`);
4372
+ assert(contractEntry?.styling?.federation?.layers?.owned?.includes(\`ultramodern-remote-\${vertical.domain}\`), \`\${vertical.id} remote CSS layer is missing\`);
4373
+ assert(!contractEntry?.styling?.federation?.layers?.owned?.includes('ultramodern-shell-base'), \`\${vertical.id} must not own shell base CSS\`);
4374
+ assert(contractEntry?.styling?.federation?.entrypoints?.remoteEntry === 'src/remote-entry.tsx', \`\${vertical.id} remote CSS contract must include remote entry\`);
4375
+ assert(contractEntry?.styling?.federation?.assets?.shared?.some(asset => asset.endsWith('/shared-design-tokens/tokens.css')), \`\${vertical.id} must import shared design token CSS\`);
4376
+ assert(contractEntry?.styling?.federation?.dedupe?.runtimeLoad === 'once-per-content-hash', \`\${vertical.id} CSS dedupe strategy is incorrect\`);
4377
+ assert(contractEntry?.styling?.federation?.ssr?.remoteCss === 'remote-manifest-owned-css', \`\${vertical.id} SSR CSS loading contract is incorrect\`);
4378
+
4379
+ const topologyEntry = topology.remotes?.find(remote => remote.id === vertical.id);
4380
+ assert(topologyEntry?.kind === 'vertical', \`\${vertical.id} topology kind is incorrect\`);
4381
+ assert(topologyEntry?.package === vertical.packageName, \`\${vertical.id} topology package is incorrect\`);
4382
+ assert(topologyEntry?.cloudflare?.workerName === expectedWorkerName(vertical.id), \`\${vertical.id} topology Cloudflare workerName is incorrect\`);
4383
+ assert(topologyEntry?.moduleFederation?.name === vertical.mfName, \`\${vertical.id} topology MF name is incorrect\`);
4384
+ assert(JSON.stringify(topologyEntry?.moduleFederation?.exposes) === JSON.stringify(vertical.exposes), \`\${vertical.id} topology exposes are incorrect\`);
4385
+ assert(JSON.stringify(topologyEntry?.moduleFederation?.remoteRefs ?? []) === JSON.stringify(vertical.remoteRefs), \`\${vertical.id} topology remoteRefs are incorrect\`);
4386
+ assert(topologyEntry?.api?.effect?.bff?.prefix === vertical.apiPrefix, \`\${vertical.id} topology API prefix is incorrect\`);
4387
+ assert(topologyEntry?.api?.effect?.serverEntry === \`\${vertical.path}/api/effect/index.ts\`, \`\${vertical.id} topology server entry is incorrect\`);
4388
+ assert(topologyEntry?.api?.effect?.readiness?.endpoint === \`/effect/\${vertical.stem}/readiness\`, \`\${vertical.id} topology readiness endpoint is incorrect\`);
4389
+ assert(Object.keys(topologyEntry?.api?.effect?.domainOperations ?? {}).length >= 3, \`\${vertical.id} topology domain operations are missing\`);
4390
+
4391
+ assert(ownership.owners?.some(owner => owner.id === vertical.id && owner.path === vertical.path), \`\${vertical.id} ownership entry is missing\`);
4392
+ assert(overlay.ports?.[vertical.id], \`\${vertical.id} development port is missing\`);
4393
+ assert(overlay.manifests?.[vertical.id]?.includes('/mf-manifest.json'), \`\${vertical.id} development manifest is missing\`);
4394
+ assert(overlay.apis?.[vertical.id]?.endsWith(vertical.apiPrefix), \`\${vertical.id} development API URL is missing\`);
4395
+ }
4396
+
4397
+ console.log('UltraModern workspace scaffold validated');
4398
+ `;
4399
+ }
4400
+ function createCloudflareVersionProofScript() {
4401
+ return `#!/usr/bin/env node
4402
+ import fs from 'node:fs';
4403
+ import path from 'node:path';
4404
+ import { fileURLToPath } from 'node:url';
4405
+
4406
+ const workspaceRoot = path.resolve(
4407
+ path.dirname(fileURLToPath(import.meta.url)),
4408
+ '..',
4409
+ );
4410
+ const contractPath = path.join(
4411
+ workspaceRoot,
4412
+ '.modernjs/ultramodern-generated-contract.json',
4413
+ );
4414
+ const defaultOut = path.join(
4415
+ workspaceRoot,
4416
+ '.codex/reports/cloudflare-version-proof/public-url-proof.json',
4417
+ );
4418
+
4419
+ function readJson(filePath) {
4420
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
4421
+ }
4422
+
4423
+ function parseArgs(argv) {
4424
+ const parsed = {
4425
+ appId: undefined,
4426
+ out: defaultOut,
4427
+ requirePublicUrls: false,
4428
+ };
4429
+
4430
+ for (let index = 0; index < argv.length; index += 1) {
4431
+ const arg = argv[index];
4432
+ if (arg === '--app') {
4433
+ parsed.appId = argv[index + 1];
4434
+ index += 1;
4435
+ } else if (arg === '--out') {
4436
+ parsed.out = argv[index + 1];
4437
+ index += 1;
4438
+ } else if (arg === '--require-public-urls') {
4439
+ parsed.requirePublicUrls = true;
4440
+ } else if (arg === '--help' || arg === '-h') {
4441
+ parsed.help = true;
4442
+ } else {
4443
+ throw new Error(\`Unknown argument: \${arg}\`);
4444
+ }
4445
+ }
4446
+
4447
+ return parsed;
4448
+ }
4449
+
4450
+ function printHelp() {
4451
+ process.stdout.write(\`Usage:
4452
+ node scripts/proof-cloudflare-version.mjs [--app remote-explore] [--out evidence.json] [--require-public-urls]
4453
+
4454
+ Set each app's public URL using the contract env key, for example:
4455
+ ULTRAMODERN_PUBLIC_URL_REMOTE_EXPLORE=https://remote-explore.example.workers.dev
4456
+ \`);
4457
+ }
4458
+
4459
+ function joinUrl(baseUrl, routePath) {
4460
+ return new URL(routePath, baseUrl.endsWith('/') ? baseUrl : \`\${baseUrl}/\`);
4461
+ }
4462
+
4463
+ async function fetchText(url) {
4464
+ const response = await fetch(url);
4465
+ return {
4466
+ ok: response.ok,
4467
+ status: response.status,
4468
+ contentType: response.headers.get('content-type'),
4469
+ body: await response.text(),
4470
+ };
4471
+ }
4472
+
4473
+ function parseMaybeJson(body) {
4474
+ try {
4475
+ return JSON.parse(body);
4476
+ } catch {
4477
+ return undefined;
4478
+ }
4479
+ }
4480
+
4481
+ function markerFromJson(value) {
4482
+ if (!value || typeof value !== 'object') {
4483
+ return undefined;
4484
+ }
4485
+ if (value.marker && typeof value.marker.build === 'string') {
4486
+ return value.marker.build;
4487
+ }
4488
+ if (typeof value.build === 'string') {
4489
+ return value.build;
4490
+ }
4491
+ for (const nested of Object.values(value)) {
4492
+ if (Array.isArray(nested)) {
4493
+ for (const item of nested) {
4494
+ const marker = markerFromJson(item);
4495
+ if (marker) {
4496
+ return marker;
4497
+ }
4498
+ }
4499
+ } else {
4500
+ const marker = markerFromJson(nested);
4501
+ if (marker) {
4502
+ return marker;
4503
+ }
4504
+ }
4505
+ }
4506
+ return undefined;
4507
+ }
4508
+
4509
+ function extractUiMarker(html) {
4510
+ return html.match(/data-build-marker=["']([^"']+)["']/u)?.[1];
4511
+ }
4512
+
4513
+ function assert(condition, message) {
4514
+ if (!condition) {
4515
+ throw new Error(message);
4516
+ }
4517
+ }
4518
+
4519
+ async function validateApp(app, publicUrl) {
4520
+ const cloudflare = app.deploy?.cloudflare;
4521
+ const routes = cloudflare?.routes ?? {};
4522
+ const evidence = {
4523
+ appId: app.id,
4524
+ publicUrl,
4525
+ workerName: cloudflare?.workerName,
4526
+ publicUrlEnv: cloudflare?.publicUrlEnv,
4527
+ assertions: [],
4528
+ };
4529
+
4530
+ const ssrRoute = routes.ssr ?? '/en';
4531
+ const ssr = await fetchText(joinUrl(publicUrl, ssrRoute));
4532
+ evidence.assertions.push({
4533
+ type: 'ssr',
4534
+ route: ssrRoute,
4535
+ status: ssr.ok ? 'pass' : 'fail',
4536
+ statusCode: ssr.status,
4537
+ });
4538
+ assert(ssr.ok, \`\${app.id} SSR route returned HTTP \${ssr.status}\`);
4539
+
4540
+ const uiMarker = extractUiMarker(ssr.body);
4541
+ evidence.assertions.push({
4542
+ type: 'ui-marker',
4543
+ expected: app.marker?.build,
4544
+ actual: uiMarker,
4545
+ status: uiMarker === app.marker?.build ? 'pass' : 'fail',
4546
+ });
4547
+ assert(uiMarker === app.marker?.build, \`\${app.id} UI marker mismatch\`);
4548
+
4549
+ const cssRootSelector = app.styling?.federation?.rootSelector;
4550
+ const expectedAppId = cssRootSelector?.match(/data-app-id="([^"]+)"/u)?.[1];
4551
+ evidence.assertions.push({
4552
+ type: 'css-root-marker',
4553
+ expected: cssRootSelector,
4554
+ status:
4555
+ expectedAppId && ssr.body.includes(\`data-app-id="\${expectedAppId}"\`)
4556
+ ? 'pass'
4557
+ : 'fail',
4558
+ });
4559
+ assert(
4560
+ expectedAppId && ssr.body.includes(\`data-app-id="\${expectedAppId}"\`),
4561
+ \`\${app.id} SSR response is missing CSS root marker \${cssRootSelector}\`,
4562
+ );
4563
+
4564
+ const manifestRoute = routes.mfManifest ?? '/mf-manifest.json';
4565
+ const manifest = await fetchText(joinUrl(publicUrl, manifestRoute));
4566
+ evidence.assertions.push({
4567
+ type: 'mf-manifest',
4568
+ route: manifestRoute,
4569
+ status: manifest.ok ? 'pass' : 'fail',
4570
+ statusCode: manifest.status,
4571
+ });
4572
+ assert(
4573
+ manifest.ok,
4574
+ \`\${app.id} MF manifest returned HTTP \${manifest.status}\`,
4575
+ );
4576
+
4577
+ const localeRoute = routes.locale ?? \`/locales/en/\${app.i18n?.namespace}.json\`;
4578
+ const locale = await fetchText(joinUrl(publicUrl, localeRoute));
4579
+ const localeJson = parseMaybeJson(locale.body);
4580
+ evidence.assertions.push({
4581
+ type: 'i18n-marker',
4582
+ namespace: app.i18n?.namespace,
4583
+ route: localeRoute,
4584
+ status:
4585
+ locale.ok &&
4586
+ localeJson &&
4587
+ Object.hasOwn(localeJson, app.i18n?.namespace)
4588
+ ? 'pass'
4589
+ : 'fail',
4590
+ statusCode: locale.status,
4591
+ });
4592
+ assert(locale.ok, \`\${app.id} locale JSON returned HTTP \${locale.status}\`);
4593
+ assert(
4594
+ localeJson && Object.hasOwn(localeJson, app.i18n?.namespace),
4595
+ \`\${app.id} locale JSON is missing namespace \${app.i18n?.namespace}\`,
4596
+ );
4597
+
4598
+ if (routes.effectReadiness) {
4599
+ const readiness = await fetchText(joinUrl(publicUrl, routes.effectReadiness));
4600
+ const readinessJson = parseMaybeJson(readiness.body);
4601
+ const apiMarker = markerFromJson(readinessJson);
4602
+ evidence.assertions.push({
4603
+ type: 'api-marker',
4604
+ route: routes.effectReadiness,
4605
+ expected: app.marker?.build,
4606
+ actual: apiMarker,
4607
+ status: readiness.ok && apiMarker === app.marker?.build ? 'pass' : 'fail',
4608
+ statusCode: readiness.status,
4609
+ });
4610
+ assert(
4611
+ readiness.ok,
4612
+ \`\${app.id} Effect readiness returned HTTP \${readiness.status}\`,
4613
+ );
4614
+ assert(apiMarker === app.marker?.build, \`\${app.id} API marker mismatch\`);
4615
+ }
4616
+
4617
+ return evidence;
4618
+ }
4619
+
4620
+ async function main(argv = process.argv.slice(2)) {
4621
+ const args = parseArgs(argv);
4622
+ if (args.help) {
4623
+ printHelp();
4624
+ return 0;
4625
+ }
4626
+
4627
+ const contract = readJson(contractPath);
4628
+ const apps = args.appId
4629
+ ? contract.apps.filter(app => app.id === args.appId)
4630
+ : contract.apps;
4631
+ assert(apps.length > 0, \`No generated app matched \${args.appId}\`);
4632
+
4633
+ const results = [];
4634
+ const skipped = [];
4635
+ for (const app of apps) {
4636
+ const publicUrlEnv = app.deploy?.cloudflare?.publicUrlEnv;
4637
+ const publicUrl = publicUrlEnv && process.env[publicUrlEnv];
4638
+ if (!publicUrl) {
4639
+ const skippedEntry = {
4640
+ appId: app.id,
4641
+ status: args.requirePublicUrls ? 'fail' : 'skipped',
4642
+ publicUrlEnv,
4643
+ reason: 'public URL environment variable is not set',
4644
+ };
4645
+ skipped.push(skippedEntry);
4646
+ if (args.requirePublicUrls) {
4647
+ throw new Error(\`\${app.id} requires \${publicUrlEnv}\`);
4648
+ }
4649
+ continue;
4650
+ }
4651
+ results.push(await validateApp(app, publicUrl));
4652
+ }
4653
+
4654
+ const report = {
4655
+ schemaVersion: 1,
4656
+ generatedAt: new Date().toISOString(),
4657
+ status: results.length > 0 ? 'pass' : 'skipped',
4658
+ contractPath,
4659
+ results,
4660
+ skipped,
4661
+ };
4662
+
4663
+ fs.mkdirSync(path.dirname(args.out), { recursive: true });
4664
+ fs.writeFileSync(args.out, \`\${JSON.stringify(report, null, 2)}\\n\`);
4665
+ process.stdout.write(
4666
+ \`[cloudflare-version-proof] \${report.status}: \${args.out}\\n\`,
4667
+ );
4668
+ return 0;
4669
+ }
4670
+
4671
+ main().then(
4672
+ exitCode => {
4673
+ process.exitCode = exitCode;
4674
+ },
4675
+ error => {
4676
+ process.stderr.write(\`[cloudflare-version-proof] \${error.message}\\n\`);
4677
+ process.exitCode = 1;
4678
+ },
4679
+ );
4680
+ `;
4681
+ }
4682
+ function writeGeneratedWorkspaceScripts(targetDir, scope, enableTailwind) {
4683
+ writeFileReplacing(targetDir, "scripts/assert-mf-types.mjs", createAssertMfTypesScript());
4684
+ writeFileReplacing(targetDir, "scripts/validate-ultramodern-workspace.mjs", createWorkspaceValidationScript(scope, enableTailwind));
4685
+ writeFileReplacing(targetDir, "scripts/proof-cloudflare-version.mjs", createCloudflareVersionProofScript());
4686
+ }
3562
4687
  function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
3563
4688
  writeJson(targetDir, `${app.directory}/package.json`, createAppPackage(scope, app, packageSource, enableTailwind));
3564
4689
  writeJson(targetDir, `${app.directory}/tsconfig.json`, createPackageTsConfig(app.directory, appHasEffectApi(app)));
3565
- writeFile(targetDir, `${app.directory}/src/modern-app-env.d.ts`, "/// <reference types='@modern-js/app-tools/types' />\n\ndeclare const ULTRAMODERN_SITE_URL: string;\n");
4690
+ writeFile(targetDir, `${app.directory}/src/modern-app-env.d.ts`, createAppEnvDts(app));
3566
4691
  writeFile(targetDir, `${app.directory}/src/ultramodern-build.ts`, createUltramodernBuildModule(scope, app));
3567
- writeFile(targetDir, `${app.directory}/modern.config.ts`, createAppModernConfig(app));
4692
+ writeFile(targetDir, `${app.directory}/src/routes/ultramodern-route-metadata.ts`, createRouteMetadataModule(app));
4693
+ writeFile(targetDir, `${app.directory}/modern.config.ts`, createAppModernConfig(scope, app));
3568
4694
  writeFile(targetDir, `${app.directory}/src/modern.runtime.ts`, createAppRuntimeConfig(app));
3569
4695
  writeJson(targetDir, `${app.directory}/locales/en/translation.json`, createAppLocaleMessages(app, 'en'));
4696
+ writeJson(targetDir, `${app.directory}/locales/en/${appI18nNamespace(app)}.json`, createAppLocaleMessages(app, 'en'));
3570
4697
  writeJson(targetDir, `${app.directory}/locales/cs/translation.json`, createAppLocaleMessages(app, 'cs'));
3571
- writeFile(targetDir, `${app.directory}/src/routes/index.css`, createAppStyles(enableTailwind));
4698
+ writeJson(targetDir, `${app.directory}/locales/cs/${appI18nNamespace(app)}.json`, createAppLocaleMessages(app, 'cs'));
4699
+ writeFile(targetDir, `${app.directory}/src/routes/index.css`, createAppStyles(enableTailwind, scope, app));
3572
4700
  if (enableTailwind) {
3573
4701
  writeFile(targetDir, `${app.directory}/postcss.config.mjs`, createPostcssConfig());
3574
4702
  writeFile(targetDir, `${app.directory}/tailwind.config.ts`, createTailwindConfig());
@@ -3576,6 +4704,7 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
3576
4704
  writeFile(targetDir, `${app.directory}/module-federation.config.ts`, 'shell' === app.kind ? createShellModuleFederationConfig() : createRemoteModuleFederationConfig(app));
3577
4705
  writeFile(targetDir, `${app.directory}/src/routes/layout.tsx`, createLayout(app.id));
3578
4706
  writeFile(targetDir, `${app.directory}/src/routes/[lang]/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
4707
+ for (const route of createRouteOwnedI18nPaths(app))if ('/' !== route.canonicalPath) writeFile(targetDir, createRoutePageFilePath(app, route.canonicalPath), createRouteAliasPage(route.canonicalPath));
3579
4708
  if ('shell' === app.kind) writeFile(targetDir, `${app.directory}/src/effect/recommendations-client.ts`, createShellEffectClient(scope));
3580
4709
  if (appHasEffectApi(app)) {
3581
4710
  writeFile(targetDir, `${app.directory}/shared/effect/api.ts`, createEffectSharedApi(app));
@@ -3584,7 +4713,10 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
3584
4713
  }
3585
4714
  if ('vertical' === app.kind || 'horizontal-remote' === app.kind) {
3586
4715
  writeFile(targetDir, `${app.directory}/src/remote-entry.tsx`, createRemoteEntry(app));
3587
- writeFile(targetDir, `${app.directory}/src/components/${remoteWidgetFile(app)}.tsx`, createRemoteWidget(app));
4716
+ for (const expose of Object.keys(app.exposes ?? {})){
4717
+ const outputPath = remoteComponentOutputPath(app, expose);
4718
+ if (outputPath) writeFile(targetDir, outputPath, createRemoteExposeComponent(app, expose));
4719
+ }
3588
4720
  }
3589
4721
  if ('horizontal-design-system' === app.kind) {
3590
4722
  writeFile(targetDir, `${app.directory}/src/components/button.tsx`, createDesignButton());
@@ -3601,7 +4733,7 @@ function writeEffectService(targetDir, scope, packageSource, enableTailwind, ser
3601
4733
  return <main>${service.id} Effect service</main>;
3602
4734
  }
3603
4735
  `);
3604
- writeFile(targetDir, `${service.directory}/src/routes/index.css`, createAppStyles(enableTailwind));
4736
+ writeFile(targetDir, `${service.directory}/src/routes/index.css`, createServiceStyles(enableTailwind, scope, service));
3605
4737
  if (enableTailwind) {
3606
4738
  writeFile(targetDir, `${service.directory}/postcss.config.mjs`, createPostcssConfig());
3607
4739
  writeFile(targetDir, `${service.directory}/tailwind.config.ts`, createTailwindConfig());
@@ -3619,6 +4751,7 @@ function writeGenericSharedPackage(targetDir, scope, packageSource, sharedPackag
3619
4751
  });
3620
4752
  writeFile(targetDir, `${sharedPackage.directory}/src/index.ts`, `export const packageId = '${sharedPackage.id}';
3621
4753
  `);
4754
+ if ('shared-design-tokens' === sharedPackage.id) writeFile(targetDir, `${sharedPackage.directory}/src/tokens.css`, createSharedDesignTokensCss());
3622
4755
  }
3623
4756
  function writeSharedPackages(targetDir, scope, packageSource) {
3624
4757
  for (const sharedPackage of sharedPackages){
@@ -3644,6 +4777,7 @@ function writeSharedPackages(targetDir, scope, packageSource) {
3644
4777
  },
3645
4778
  } as const;
3646
4779
  `);
4780
+ writeFile(targetDir, 'packages/shared-design-tokens/src/tokens.css', createSharedDesignTokensCss());
3647
4781
  writeFile(targetDir, 'packages/shared-effect-api/src/index.ts', createEffectSharedApi());
3648
4782
  }
3649
4783
  function readJsonFile(filePath) {
@@ -3742,6 +4876,10 @@ function remoteTopologyEntry(scope, remote) {
3742
4876
  name: remote.mfName,
3743
4877
  manifestUrl: `http://localhost:${remote.port}/mf-manifest.json`,
3744
4878
  exposes: Object.keys(remote.exposes ?? {}),
4879
+ ...remote.remoteRefs?.length ? {
4880
+ remoteRefs: remote.remoteRefs,
4881
+ remotes: createModuleFederationRemoteContracts(remote)
4882
+ } : {},
3745
4883
  ssr: true,
3746
4884
  fallbackTelemetryEvent: 'modernjs:mv-runtime-parity',
3747
4885
  sharedContractVersion: 'mf-ssr-contract-v1'
@@ -3780,6 +4918,17 @@ function remotesFromTopology(topology, ports) {
3780
4918
  portEnv: '',
3781
4919
  port: 'number' == typeof ports[remote.id] ? ports[remote.id] : 0,
3782
4920
  mfName: remote.moduleFederation?.name ?? `remote${toPascalCase(remote.id)}`,
4921
+ ...Array.isArray(remote.moduleFederation?.exposes) ? {
4922
+ exposes: Object.fromEntries(remote.moduleFederation.exposes.map((expose)=>[
4923
+ expose,
4924
+ ''
4925
+ ]))
4926
+ } : {},
4927
+ ...Array.isArray(remote.moduleFederation?.remoteRefs) ? {
4928
+ remoteRefs: remote.moduleFederation.remoteRefs
4929
+ } : Array.isArray(remote.moduleFederation?.remotes) ? {
4930
+ remoteRefs: remote.moduleFederation.remotes.map((entry)=>entry.id).filter((id)=>'string' == typeof id)
4931
+ } : {},
3783
4932
  ...effectApi ? {
3784
4933
  effectApi
3785
4934
  } : {},
@@ -3837,7 +4986,10 @@ function addUltramodernMicroVertical(options) {
3837
4986
  writeJsonFile(ownershipPath, ownership);
3838
4987
  writeJsonFile(overlayPath, overlay);
3839
4988
  writeJsonFile(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH), createGeneratedContract(scope, [
3840
- shellApp,
4989
+ {
4990
+ ...shellApp,
4991
+ remoteRefs: remotesFromTopology(topology, overlay.ports).map((remote)=>remote.id)
4992
+ },
3841
4993
  ...remotesFromTopology(topology, overlay.ports)
3842
4994
  ], enableTailwind));
3843
4995
  const shellConfigPath = node_path.join(options.workspaceRoot, `${shellApp.directory}/module-federation.config.ts`);
@@ -3940,6 +5092,7 @@ function generateUltramodernWorkspace(options) {
3940
5092
  writeApp(options.targetDir, scope, shellApp, packageSource, enableTailwind);
3941
5093
  for (const remote of remoteApps)writeApp(options.targetDir, scope, remote, packageSource, enableTailwind);
3942
5094
  writeSharedPackages(options.targetDir, scope, packageSource);
5095
+ writeGeneratedWorkspaceScripts(options.targetDir, scope, enableTailwind);
3943
5096
  }
3944
5097
  const src_dirname = node_path.dirname(fileURLToPath(import.meta.url));
3945
5098
  const templateDir = node_path.resolve(src_dirname, '..', 'template');