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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/cjs/index.cjs +1 -1
  2. package/dist/cjs/locale/en.cjs +2 -2
  3. package/dist/cjs/locale/zh.cjs +2 -2
  4. package/dist/cjs/ultramodern-tooling/config.cjs +9 -91
  5. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +13 -40
  6. package/dist/cjs/ultramodern-workspace/contracts.cjs +2 -0
  7. package/dist/cjs/ultramodern-workspace/demo-components.cjs +12 -12
  8. package/dist/cjs/ultramodern-workspace/descriptors.cjs +0 -4
  9. package/dist/cjs/ultramodern-workspace/effect-api.cjs +74 -75
  10. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +1 -2
  11. package/dist/cjs/ultramodern-workspace/module-federation.cjs +3 -2
  12. package/dist/cjs/ultramodern-workspace/package-json.cjs +6 -5
  13. package/dist/cjs/ultramodern-workspace/policy.cjs +1 -1
  14. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +7 -0
  15. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +4 -4
  16. package/dist/esm/index.js +1 -1
  17. package/dist/esm/locale/en.js +2 -2
  18. package/dist/esm/locale/zh.js +2 -2
  19. package/dist/esm/ultramodern-tooling/config.js +10 -92
  20. package/dist/esm/ultramodern-workspace/add-vertical.js +14 -41
  21. package/dist/esm/ultramodern-workspace/contracts.js +2 -0
  22. package/dist/esm/ultramodern-workspace/demo-components.js +12 -12
  23. package/dist/esm/ultramodern-workspace/descriptors.js +1 -2
  24. package/dist/esm/ultramodern-workspace/effect-api.js +74 -75
  25. package/dist/esm/ultramodern-workspace/mf-validation.js +1 -2
  26. package/dist/esm/ultramodern-workspace/module-federation.js +3 -2
  27. package/dist/esm/ultramodern-workspace/package-json.js +6 -5
  28. package/dist/esm/ultramodern-workspace/policy.js +1 -1
  29. package/dist/esm/ultramodern-workspace/workspace-scripts.js +5 -1
  30. package/dist/esm/ultramodern-workspace/write-workspace.js +4 -4
  31. package/dist/esm-node/index.js +1 -1
  32. package/dist/esm-node/locale/en.js +2 -2
  33. package/dist/esm-node/locale/zh.js +2 -2
  34. package/dist/esm-node/ultramodern-tooling/config.js +10 -92
  35. package/dist/esm-node/ultramodern-workspace/add-vertical.js +14 -41
  36. package/dist/esm-node/ultramodern-workspace/contracts.js +2 -0
  37. package/dist/esm-node/ultramodern-workspace/demo-components.js +12 -12
  38. package/dist/esm-node/ultramodern-workspace/descriptors.js +1 -2
  39. package/dist/esm-node/ultramodern-workspace/effect-api.js +74 -75
  40. package/dist/esm-node/ultramodern-workspace/mf-validation.js +1 -2
  41. package/dist/esm-node/ultramodern-workspace/module-federation.js +3 -2
  42. package/dist/esm-node/ultramodern-workspace/package-json.js +6 -5
  43. package/dist/esm-node/ultramodern-workspace/policy.js +1 -1
  44. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +5 -1
  45. package/dist/esm-node/ultramodern-workspace/write-workspace.js +4 -4
  46. package/dist/types/ultramodern-tooling/config.d.ts +1 -2
  47. package/dist/types/ultramodern-workspace/descriptors.d.ts +0 -1
  48. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +1 -0
  49. package/package.json +3 -3
  50. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +1 -11
  51. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mjs +339 -0
  52. package/templates/workspace-scripts/generate-public-surface-assets.mjs +14 -12
  53. package/templates/workspace-scripts/proof-cloudflare-version.mjs +3 -13
  54. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +3 -3
  55. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +1 -9
  56. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +82 -86
@@ -16,11 +16,11 @@ const expectedCloudflareDeployScript = {{expectedCloudflareDeployScriptJson}};
16
16
  const expectedCloudflareSecurity = {{expectedCloudflareSecurityJson}};
17
17
  const publicSurfaceManagedSourceAssetPaths = {{publicSurfaceManagedSourceAssetPathsJson}};
18
18
  const compactConfigPath = '.modernjs/ultramodern.json';
19
- const legacyGeneratedContractPath =
20
- '.modernjs/ultramodern-generated-contract.json';
21
- const legacyPackageSourcePath = '.modernjs/ultramodern-package-source.json';
22
- const legacyTemplateManifestPath =
23
- '.modernjs/ultramodern-workspace-template-manifest.json';
19
+ const retiredMetadataPaths = [
20
+ '.modernjs/ultramodern-generated-contract.json',
21
+ '.modernjs/ultramodern-package-source.json',
22
+ '.modernjs/ultramodern-workspace-template-manifest.json',
23
+ ];
24
24
  const modernPackageCohort = [
25
25
  '@modern-js/create',
26
26
  '@modern-js/code-tools',
@@ -86,11 +86,7 @@ const assertArray = (value, contract, fixArea) => {
86
86
  };
87
87
  const findById = (entries, id) =>
88
88
  Array.isArray(entries) ? entries.find(entry => entry?.id === id) : undefined;
89
- const exists = relativePath => fs.existsSync(path.join(root, relativePath));
90
- const hasCompactConfig = exists(compactConfigPath);
91
- const generatedContractLabel = hasCompactConfig
92
- ? compactConfigPath
93
- : legacyGeneratedContractPath;
89
+ const generatedContractLabel = compactConfigPath;
94
90
  const toKebabCase = value =>
95
91
  String(value)
96
92
  .trim()
@@ -115,10 +111,25 @@ const packageNameFor = (scope, suffix) => `@${scope}/${suffix}`;
115
111
  const normalizeRelativePath = value =>
116
112
  String(value ?? '').replace(/\\/gu, '/').replace(/^\.\/+/u, '');
117
113
  const appNamespace = app => (app.kind === 'shell' ? 'shell' : (app.domain ?? app.id));
114
+ const tailwindPrefixDigitWords = [
115
+ 'zero',
116
+ 'one',
117
+ 'two',
118
+ 'three',
119
+ 'four',
120
+ 'five',
121
+ 'six',
122
+ 'seven',
123
+ 'eight',
124
+ 'nine',
125
+ ];
118
126
  const tailwindPrefixFor = app =>
119
127
  app.kind === 'shell'
120
128
  ? 'shell'
121
- : String(app.domain ?? app.id).toLowerCase().replace(/[^a-z0-9]/gu, '');
129
+ : String(app.domain ?? app.id)
130
+ .toLowerCase()
131
+ .replace(/[^a-z0-9]/gu, '')
132
+ .replace(/[0-9]/gu, digit => tailwindPrefixDigitWords[Number(digit)]);
122
133
  const buildMarkerFor = app =>
123
134
  crypto
124
135
  .createHash('sha256')
@@ -385,7 +396,7 @@ const createCloudflareRoutes = app => ({
385
396
  locale: `/locales/en/${appNamespace(app)}.json`,
386
397
  ...(app.effectApi
387
398
  ? {
388
- effectReadiness: `${app.effectApi.prefix}/effect/${app.effectApi.stem}/readiness`,
399
+ apiReadiness: `${app.effectApi.prefix}/${app.effectApi.stem}/readiness`,
389
400
  }
390
401
  : {}),
391
402
  });
@@ -406,13 +417,13 @@ const createCloudflareDeploy = app => ({
406
417
  },
407
418
  });
408
419
  const createEffectReadiness = app => ({
409
- endpoint: `/effect/${app.effectApi.stem}/readiness`,
420
+ endpoint: `/${app.effectApi.stem}/readiness`,
410
421
  marker: {
411
422
  ui: 'ultramodernUiMarker',
412
423
  api: 'ultramodernApiMarker',
413
424
  skew: 'none',
414
425
  },
415
- checks: ['moduleFederation', 'ssr', 'translations', 'effectBff'],
426
+ checks: ['moduleFederation', 'ssr', 'translations', 'api'],
416
427
  });
417
428
  const createEffectRequestContext = () => ({
418
429
  propagatedHeaders: [
@@ -424,12 +435,12 @@ const createEffectRequestContext = () => ({
424
435
  'x-ultramodern-env',
425
436
  'x-vertical-version-id',
426
437
  ],
427
- source: 'shell-to-vertical-effect-client',
438
+ source: 'shell-to-vertical-api-client',
428
439
  });
429
440
  const createEffectDomainOperations = app => {
430
441
  const stem = app.effectApi.stem;
431
442
  const group = toCamelCase(stem);
432
- const basePath = `/effect/${stem}`;
443
+ const basePath = `/${stem}`;
433
444
  return {
434
445
  workspaceFeed: {
435
446
  client: `list${toPascalCase(stem)}`,
@@ -459,7 +470,7 @@ const createEffectOperationContract = app => ({
459
470
  operations: {
460
471
  readiness: {
461
472
  method: 'GET',
462
- path: `/effect/${app.effectApi.stem}/readiness`,
473
+ path: `/${app.effectApi.stem}/readiness`,
463
474
  source: 'generated-client',
464
475
  },
465
476
  },
@@ -627,18 +638,19 @@ const createAppContract = (app, apps) => ({
627
638
  build: buildMarkerFor(app),
628
639
  deployProfile: 'cloudflare-ssr-mf-effect-v1',
629
640
  uiSurface: 'ui',
630
- ...(app.effectApi ? { apiSurface: 'effect-bff' } : {}),
641
+ ...(app.effectApi ? { apiSurface: 'api' } : {}),
631
642
  },
632
643
  ...(app.effectApi
633
644
  ? {
634
- effect: {
645
+ api: {
635
646
  runtime: 'effect',
636
647
  import: '@modern-js/plugin-bff/effect-edge',
637
648
  prefix: app.effectApi.prefix,
638
649
  openapi: '/openapi.json',
650
+ strictEffectApproach: true,
639
651
  workerEntry: 'worker/__modern_bff_effect.js',
640
- contract: './shared/effect/api',
641
- client: './effect/client',
652
+ contract: './api',
653
+ client: './api/client',
642
654
  readiness: createEffectReadiness(app),
643
655
  requestContext: createEffectRequestContext(),
644
656
  domainOperations: createEffectDomainOperations(app),
@@ -751,16 +763,10 @@ const synthesizeGeneratedContractFromCompact = config => {
751
763
  };
752
764
  };
753
765
  const readPackageSourceView = config => {
754
- if (config) {
755
- return synthesizePackageSourceFromCompact(config);
756
- }
757
- return readJson(legacyPackageSourcePath);
766
+ return synthesizePackageSourceFromCompact(config);
758
767
  };
759
768
  const readGeneratedContractView = config => {
760
- if (config) {
761
- return synthesizeGeneratedContractFromCompact(config);
762
- }
763
- return readJson(legacyGeneratedContractPath);
769
+ return synthesizeGeneratedContractFromCompact(config);
764
770
  };
765
771
  const expectedManifestUrl = vertical =>
766
772
  `http://localhost:${vertical.port}/mf-manifest.json`;
@@ -787,9 +793,9 @@ const requiredMicroVerticalPaths = vertical => [
787
793
  `${vertical.path}/tsconfig.mf-types.json`,
788
794
  `${vertical.path}/modern.config.ts`,
789
795
  `${vertical.path}/module-federation.config.ts`,
790
- `${vertical.path}/api/effect/index.ts`,
791
- `${vertical.path}/shared/effect/api.ts`,
792
- `${vertical.path}/src/effect/${vertical.stem}-client.ts`,
796
+ `${vertical.path}/api/index.ts`,
797
+ `${vertical.path}/shared/api.ts`,
798
+ `${vertical.path}/src/api/${vertical.stem}-client.ts`,
793
799
  `${vertical.path}/src/modern-app-env.d.ts`,
794
800
  `${vertical.path}/src/modern.runtime.ts`,
795
801
  `${vertical.path}/src/federation-entry.tsx`,
@@ -865,7 +871,7 @@ const assertMicroVerticalContractGraph = ({
865
871
  assertObject(
866
872
  overlay.apis,
867
873
  'topology/local-overlays/development.json apis',
868
- 'restore generated local Effect API overlays',
874
+ 'restore generated local API overlays',
869
875
  );
870
876
  assertArray(
871
877
  generatedContract.apps,
@@ -958,9 +964,9 @@ const assertMicroVerticalContractGraph = ({
958
964
  remoteContractSubset,
959
965
  ),
960
966
  },
961
- effect: {
962
- prefix: topologyEntry.api?.effect?.bff?.prefix,
963
- serverEntry: topologyEntry.api?.effect?.serverEntry,
967
+ api: {
968
+ prefix: topologyEntry.api?.bff?.prefix,
969
+ serverEntry: topologyEntry.api?.serverEntry,
964
970
  },
965
971
  },
966
972
  {
@@ -974,9 +980,9 @@ const assertMicroVerticalContractGraph = ({
974
980
  verticalRefs: expectedRefs,
975
981
  remotes: expectedRemoteSubsetsForRefs(expectedRefs),
976
982
  },
977
- effect: {
983
+ api: {
978
984
  prefix: vertical.apiPrefix,
979
- serverEntry: `${vertical.path}/api/effect/index.ts`,
985
+ serverEntry: `${vertical.path}/api/index.ts`,
980
986
  },
981
987
  },
982
988
  `topology/reference-topology.json verticals.${vertical.id}`,
@@ -1017,14 +1023,14 @@ const assertMicroVerticalContractGraph = ({
1017
1023
  overlay.apis[vertical.id],
1018
1024
  expectedApiUrl(vertical),
1019
1025
  `topology/local-overlays/development.json apis.${vertical.id}`,
1020
- 'restore generated local Effect API overlay',
1026
+ 'restore generated local API overlay',
1021
1027
  );
1022
1028
 
1023
1029
  assertSameJson(
1024
1030
  shellPackage.dependencies?.[vertical.packageName],
1025
1031
  'workspace:*',
1026
1032
  `apps/shell-super-app/package.json dependencies.${vertical.packageName}`,
1027
- 'restore shell dependency for the MicroVertical Effect API consumer',
1033
+ 'restore shell dependency for the MicroVertical API consumer',
1028
1034
  );
1029
1035
  assertSameJson(
1030
1036
  shellPackage['zephyr:dependencies']?.[vertical.zephyrAlias],
@@ -1051,10 +1057,10 @@ const assertMicroVerticalContractGraph = ({
1051
1057
  remoteContractSubset,
1052
1058
  ),
1053
1059
  },
1054
- effect: {
1055
- prefix: contractEntry.effect?.prefix,
1056
- contract: contractEntry.effect?.contract,
1057
- client: contractEntry.effect?.client,
1060
+ api: {
1061
+ prefix: contractEntry.api?.prefix,
1062
+ contract: contractEntry.api?.contract,
1063
+ client: contractEntry.api?.client,
1058
1064
  },
1059
1065
  ssr: contractEntry.ssr,
1060
1066
  },
@@ -1068,10 +1074,10 @@ const assertMicroVerticalContractGraph = ({
1068
1074
  verticalRefs: expectedRefs,
1069
1075
  remotes: expectedRemoteSubsetsForRefs(expectedRefs),
1070
1076
  },
1071
- effect: {
1077
+ api: {
1072
1078
  prefix: vertical.apiPrefix,
1073
- contract: './shared/effect/api',
1074
- client: './effect/client',
1079
+ contract: './api',
1080
+ client: './api/client',
1075
1081
  },
1076
1082
  ssr: {
1077
1083
  mode: 'string',
@@ -1470,6 +1476,7 @@ const requiredPaths = [
1470
1476
  'topology/local-overlays/development.json',
1471
1477
  'scripts/assert-mf-types.mjs',
1472
1478
  'scripts/bootstrap-agent-skills.mjs',
1479
+ 'scripts/check-ultramodern-api-boundaries.mjs',
1473
1480
  'scripts/check-ultramodern-i18n-boundaries.mjs',
1474
1481
  'scripts/generate-public-surface-assets.mjs',
1475
1482
  'scripts/proof-cloudflare-version.mjs',
@@ -1485,7 +1492,7 @@ const requiredPaths = [
1485
1492
  'apps/shell-super-app/module-federation.config.ts',
1486
1493
  'apps/shell-super-app/src/modern-app-env.d.ts',
1487
1494
  'apps/shell-super-app/src/modern.runtime.ts',
1488
- 'apps/shell-super-app/src/effect/vertical-clients.ts',
1495
+ 'apps/shell-super-app/src/api/vertical-clients.ts',
1489
1496
  'apps/shell-super-app/locales/en/translation.json',
1490
1497
  `apps/shell-super-app/locales/en/${shellNamespace}.json`,
1491
1498
  'apps/shell-super-app/locales/cs/translation.json',
@@ -1520,15 +1527,7 @@ if (tailwindEnabled) {
1520
1527
  );
1521
1528
  }
1522
1529
 
1523
- if (hasCompactConfig) {
1524
- requiredPaths.push(compactConfigPath);
1525
- } else {
1526
- requiredPaths.push(
1527
- legacyTemplateManifestPath,
1528
- legacyPackageSourcePath,
1529
- legacyGeneratedContractPath,
1530
- );
1531
- }
1530
+ requiredPaths.push(compactConfigPath);
1532
1531
 
1533
1532
  for (const vertical of fullStackVerticals) {
1534
1533
  requiredMicroVerticalPaths(vertical).forEach(
@@ -1541,17 +1540,11 @@ for (const requiredPath of requiredPaths) {
1541
1540
  for (const oldRemotePath of oldRemotePaths) {
1542
1541
  assertNotExists(oldRemotePath);
1543
1542
  }
1544
- if (hasCompactConfig) {
1545
- for (const retiredMetadataPath of [
1546
- legacyTemplateManifestPath,
1547
- legacyPackageSourcePath,
1548
- legacyGeneratedContractPath,
1549
- ]) {
1550
- assertNotExists(retiredMetadataPath);
1551
- }
1543
+ for (const retiredMetadataPath of retiredMetadataPaths) {
1544
+ assertNotExists(retiredMetadataPath);
1552
1545
  }
1553
1546
  const rootPackage = readJson('package.json');
1554
- const ultramodernConfig = hasCompactConfig ? readJson(compactConfigPath) : undefined;
1547
+ const ultramodernConfig = readJson(compactConfigPath);
1555
1548
  const bridgeConfig =
1556
1549
  ultramodernConfig?.bridge?.enabled === true ? ultramodernConfig.bridge : undefined;
1557
1550
  const packageSource = readPackageSourceView(ultramodernConfig);
@@ -1595,11 +1588,8 @@ assert(
1595
1588
  assert(!workflowText.includes('FORCE_JAVASCRIPT_ACTIONS_TO_NODE24'), 'CI workflow must not carry the legacy Node 24 override');
1596
1589
  assert(rootPackage.modernjs?.preset === 'presetUltramodern', 'Root must declare presetUltramodern');
1597
1590
  assert(
1598
- rootPackage.modernjs?.packageSource?.config ===
1599
- (hasCompactConfig ? './.modernjs/ultramodern.json' : './.modernjs/ultramodern-package-source.json'),
1600
- hasCompactConfig
1601
- ? 'Root must point at compact UltraModern config'
1602
- : 'Root must point at package source metadata',
1591
+ rootPackage.modernjs?.packageSource?.config === './.modernjs/ultramodern.json',
1592
+ 'Root must point at compact UltraModern config',
1603
1593
  );
1604
1594
  assert(rootPackage.modernjs?.packageSource?.strategy === packageSource.strategy, 'Root package source strategy must match metadata');
1605
1595
  assert(packageSource.strategy === 'workspace' || packageSource.strategy === 'install', 'Package source strategy must be workspace or install');
@@ -1677,12 +1667,15 @@ if (bridgeConfig) {
1677
1667
  assert(rootPackage.scripts?.typecheck === 'node ./scripts/ultramodern-typecheck.mjs --build tsconfig.json', 'Root typecheck must run TS-Go build mode across project references');
1678
1668
  }
1679
1669
  assert(rootPackage.scripts?.['contract:check'] === 'node ./scripts/validate-ultramodern-workspace.mjs', 'Root must expose contract:check');
1670
+ assert(rootPackage.scripts?.['api:check'] === 'node ./scripts/check-ultramodern-api-boundaries.mjs', 'Root must expose api:check');
1680
1671
  assert(rootPackage.scripts?.['i18n:boundaries'] === 'node ./scripts/check-ultramodern-i18n-boundaries.mjs', 'Root must expose i18n:boundaries');
1681
1672
  assert(rootPackage.scripts?.['performance:readiness'] === 'node ./scripts/ultramodern-performance-readiness.mjs', 'Root must expose default-on performance readiness diagnostics');
1682
1673
  assert(
1683
1674
  bridgeConfig
1684
- ? rootPackage.scripts?.check?.endsWith('&& pnpm performance:readiness && pnpm bridge:check')
1685
- : rootPackage.scripts?.check?.endsWith('&& pnpm performance:readiness'),
1675
+ ? rootPackage.scripts?.check?.includes('pnpm api:check') &&
1676
+ rootPackage.scripts.check.endsWith('&& pnpm performance:readiness && pnpm bridge:check')
1677
+ : rootPackage.scripts?.check?.includes('pnpm api:check') &&
1678
+ rootPackage.scripts.check.endsWith('&& pnpm performance:readiness'),
1686
1679
  'Root check must run default-on performance readiness diagnostics and bridge gates when configured',
1687
1680
  );
1688
1681
  const performanceReadinessConfig = readText('scripts/ultramodern-performance-readiness.config.mjs');
@@ -1858,8 +1851,8 @@ for (const vertical of fullStackVerticals) {
1858
1851
  assert(packageJson.dependencies?.['@modern-js/plugin-i18n'] === expectedModernPackageSpecifier('@modern-js/plugin-i18n'), `${vertical.id} plugin-i18n dependency must match package source metadata`);
1859
1852
  assert(packageJson.dependencies?.['@modern-js/plugin-tanstack'] === expectedModernPackageSpecifier('@modern-js/plugin-tanstack'), `${vertical.id} plugin-tanstack dependency must match package source metadata`);
1860
1853
  assert(packageJson.dependencies?.['@modern-js/runtime'] === expectedModernPackageSpecifier('@modern-js/runtime'), `${vertical.id} runtime dependency must match package source metadata`);
1861
- assert(packageJson.exports?.['./effect/client'] === `./src/effect/${vertical.stem}-client.ts`, `${vertical.id} must export its Effect client`);
1862
- assert(packageJson.exports?.['./shared/effect/api'] === './shared/effect/api.ts', `${vertical.id} must export its Effect API contract`);
1854
+ assert(packageJson.exports?.['./api/client'] === `./src/api/${vertical.stem}-client.ts`, `${vertical.id} must export its API client`);
1855
+ assert(packageJson.exports?.['./api'] === './shared/api.ts', `${vertical.id} must export its API contract`);
1863
1856
  const expectedVerticalZephyrDependencies = Object.fromEntries(
1864
1857
  fullStackVerticals
1865
1858
  .filter(candidate => vertical.verticalRefs.includes(candidate.id))
@@ -1906,7 +1899,7 @@ for (const vertical of fullStackVerticals) {
1906
1899
  assert(contractEntry?.config?.performance?.readinessDiagnostics?.default === 'enabled', `${vertical.id} performance readiness diagnostics must be default-on`);
1907
1900
  assert(contractEntry?.config?.performance?.readinessDiagnostics?.failOn === 'framework-invariant', `${vertical.id} performance readiness diagnostics must only fail framework invariants by default`);
1908
1901
  assert(contractEntry?.config?.performance?.readinessDiagnostics?.optOut?.config === 'scripts/ultramodern-performance-readiness.config.mjs', `${vertical.id} performance readiness opt-out config is incorrect`);
1909
- assert(contractEntry?.deploy?.cloudflare?.routes?.effectReadiness === `${vertical.apiPrefix}/effect/${vertical.stem}/readiness`, `${vertical.id} Cloudflare proof readiness route is incorrect`);
1902
+ assert(contractEntry?.deploy?.cloudflare?.routes?.apiReadiness === `${vertical.apiPrefix}/${vertical.stem}/readiness`, `${vertical.id} Cloudflare proof readiness route is incorrect`);
1910
1903
  assert(contractEntry?.config?.rspack?.output?.uniqueName === vertical.mfName, `${vertical.id} Rspack uniqueName is incorrect`);
1911
1904
  assert(contractEntry?.config?.rspack?.output?.chunkLoadingGlobal === expectedChunkLoadingGlobal(vertical.mfName), `${vertical.id} Rspack chunkLoadingGlobal is incorrect`);
1912
1905
  assert(contractEntry?.moduleFederation?.name === vertical.mfName, `${vertical.id} MF name is incorrect`);
@@ -1920,12 +1913,14 @@ for (const vertical of fullStackVerticals) {
1920
1913
  JSON.stringify(vertical.verticalRefs),
1921
1914
  `${vertical.id} MF consumed verticals are incorrect`,
1922
1915
  );
1923
- assert(contractEntry?.effect?.prefix === vertical.apiPrefix, `${vertical.id} Effect API prefix is incorrect`);
1924
- assert(contractEntry?.effect?.group === vertical.group, `${vertical.id} Effect group is incorrect`);
1925
- assert(contractEntry?.effect?.readiness?.endpoint === `/effect/${vertical.stem}/readiness`, `${vertical.id} readiness endpoint is incorrect`);
1926
- assert(contractEntry?.effect?.operations?.readiness?.path === `/effect/${vertical.stem}/readiness`, `${vertical.id} readiness operation is missing`);
1927
- assert(contractEntry?.effect?.requestContext?.propagatedHeaders?.includes('traceparent'), `${vertical.id} trace context propagation is missing`);
1928
- assert(Object.keys(contractEntry?.effect?.domainOperations ?? {}).length >= 3, `${vertical.id} domain operations are missing`);
1916
+ assert(contractEntry?.api?.prefix === vertical.apiPrefix, `${vertical.id} API prefix is incorrect`);
1917
+ assert(contractEntry?.api?.group === vertical.group, `${vertical.id} API group is incorrect`);
1918
+ assert(contractEntry?.api?.runtime === 'effect', `${vertical.id} API runtime must be Effect`);
1919
+ assert(contractEntry?.api?.strictEffectApproach === true, `${vertical.id} strictEffectApproach must be enabled`);
1920
+ assert(contractEntry?.api?.readiness?.endpoint === `/${vertical.stem}/readiness`, `${vertical.id} readiness endpoint is incorrect`);
1921
+ assert(contractEntry?.api?.operations?.readiness?.path === `/${vertical.stem}/readiness`, `${vertical.id} readiness operation is missing`);
1922
+ assert(contractEntry?.api?.requestContext?.propagatedHeaders?.includes('traceparent'), `${vertical.id} trace context propagation is missing`);
1923
+ assert(Object.keys(contractEntry?.api?.domainOperations ?? {}).length >= 3, `${vertical.id} domain operations are missing`);
1929
1924
  assert(contractEntry?.i18n?.languages?.includes('en') && contractEntry?.i18n?.languages?.includes('cs'), `${vertical.id} must declare i18n languages`);
1930
1925
  assert(contractEntry?.i18n?.namespace === vertical.namespace, `${vertical.id} i18n namespace is incorrect`);
1931
1926
  assert(
@@ -1964,10 +1959,11 @@ for (const vertical of fullStackVerticals) {
1964
1959
  assert(topologyEntry?.moduleFederation?.name === vertical.mfName, `${vertical.id} topology MF name is incorrect`);
1965
1960
  assert(JSON.stringify(topologyEntry?.moduleFederation?.exposes) === JSON.stringify(vertical.exposes), `${vertical.id} topology exposes are incorrect`);
1966
1961
  assert(JSON.stringify(topologyEntry?.moduleFederation?.verticalRefs ?? []) === JSON.stringify(vertical.verticalRefs), `${vertical.id} topology verticalRefs are incorrect`);
1967
- assert(topologyEntry?.api?.effect?.bff?.prefix === vertical.apiPrefix, `${vertical.id} topology API prefix is incorrect`);
1968
- assert(topologyEntry?.api?.effect?.serverEntry === `${vertical.path}/api/effect/index.ts`, `${vertical.id} topology server entry is incorrect`);
1969
- assert(topologyEntry?.api?.effect?.readiness?.endpoint === `/effect/${vertical.stem}/readiness`, `${vertical.id} topology readiness endpoint is incorrect`);
1970
- assert(Object.keys(topologyEntry?.api?.effect?.domainOperations ?? {}).length >= 3, `${vertical.id} topology domain operations are missing`);
1962
+ assert(topologyEntry?.api?.bff?.prefix === vertical.apiPrefix, `${vertical.id} topology API prefix is incorrect`);
1963
+ assert(topologyEntry?.api?.bff?.strictEffectApproach === true, `${vertical.id} topology strictEffectApproach is incorrect`);
1964
+ assert(topologyEntry?.api?.serverEntry === `${vertical.path}/api/index.ts`, `${vertical.id} topology server entry is incorrect`);
1965
+ assert(topologyEntry?.api?.readiness?.endpoint === `/${vertical.stem}/readiness`, `${vertical.id} topology readiness endpoint is incorrect`);
1966
+ assert(Object.keys(topologyEntry?.api?.domainOperations ?? {}).length >= 3, `${vertical.id} topology domain operations are missing`);
1971
1967
 
1972
1968
  assert(ownership.owners?.some(owner => owner.id === vertical.id && owner.path === vertical.path), `${vertical.id} ownership entry is missing`);
1973
1969
  assert(overlay.ports?.[vertical.id], `${vertical.id} development port is missing`);