@bleedingdev/modern-js-create 3.4.0-ultramodern.9 → 3.5.0-ultramodern.1

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 (135) hide show
  1. package/README.md +49 -23
  2. package/dist/cjs/index.cjs +37 -4
  3. package/dist/cjs/locale/en.cjs +12 -2
  4. package/dist/cjs/locale/zh.cjs +12 -2
  5. package/dist/cjs/ultramodern-tooling/commands.cjs +431 -0
  6. package/dist/cjs/ultramodern-tooling/config.cjs +172 -0
  7. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +87 -75
  8. package/dist/cjs/ultramodern-workspace/{effect-api.cjs → api.cjs} +207 -208
  9. package/dist/cjs/ultramodern-workspace/bridge-config.cjs +327 -0
  10. package/dist/cjs/ultramodern-workspace/codesmith.cjs +1 -0
  11. package/dist/cjs/ultramodern-workspace/contracts.cjs +128 -657
  12. package/dist/cjs/ultramodern-workspace/demo-components.cjs +12 -12
  13. package/dist/cjs/ultramodern-workspace/descriptors.cjs +25 -25
  14. package/dist/cjs/ultramodern-workspace/fs-io.cjs +117 -0
  15. package/dist/cjs/ultramodern-workspace/generation-result.cjs +5 -5
  16. package/dist/cjs/ultramodern-workspace/index.cjs +4 -0
  17. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +571 -0
  18. package/dist/cjs/ultramodern-workspace/module-federation.cjs +39 -12
  19. package/dist/cjs/ultramodern-workspace/overlays.cjs +2 -2
  20. package/dist/cjs/ultramodern-workspace/package-json.cjs +58 -41
  21. package/dist/cjs/ultramodern-workspace/policy.cjs +4 -4
  22. package/dist/cjs/ultramodern-workspace/public-api.cjs +4 -0
  23. package/dist/cjs/ultramodern-workspace/public-surface.cjs +2 -2
  24. package/dist/cjs/ultramodern-workspace/versions.cjs +15 -0
  25. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +120 -50
  26. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +64 -21
  27. package/dist/esm/index.js +37 -4
  28. package/dist/esm/locale/en.js +12 -2
  29. package/dist/esm/locale/zh.js +12 -2
  30. package/dist/esm/ultramodern-tooling/commands.js +378 -0
  31. package/dist/esm/ultramodern-tooling/config.js +120 -0
  32. package/dist/esm/ultramodern-workspace/add-vertical.js +88 -79
  33. package/dist/esm/ultramodern-workspace/{effect-api.js → api.js} +146 -147
  34. package/dist/esm/ultramodern-workspace/bridge-config.js +270 -0
  35. package/dist/esm/ultramodern-workspace/codesmith.js +1 -0
  36. package/dist/esm/ultramodern-workspace/contracts.js +130 -611
  37. package/dist/esm/ultramodern-workspace/demo-components.js +13 -13
  38. package/dist/esm/ultramodern-workspace/descriptors.js +11 -11
  39. package/dist/esm/ultramodern-workspace/fs-io.js +116 -2
  40. package/dist/esm/ultramodern-workspace/generation-result.js +6 -6
  41. package/dist/esm/ultramodern-workspace/index.js +1 -0
  42. package/dist/esm/ultramodern-workspace/mf-validation.js +516 -0
  43. package/dist/esm/ultramodern-workspace/module-federation.js +40 -13
  44. package/dist/esm/ultramodern-workspace/overlays.js +2 -2
  45. package/dist/esm/ultramodern-workspace/package-json.js +57 -40
  46. package/dist/esm/ultramodern-workspace/policy.js +5 -5
  47. package/dist/esm/ultramodern-workspace/public-api.js +1 -0
  48. package/dist/esm/ultramodern-workspace/public-surface.js +2 -2
  49. package/dist/esm/ultramodern-workspace/versions.js +7 -1
  50. package/dist/esm/ultramodern-workspace/workspace-scripts.js +108 -34
  51. package/dist/esm/ultramodern-workspace/write-workspace.js +66 -26
  52. package/dist/esm-node/index.js +37 -4
  53. package/dist/esm-node/locale/en.js +12 -2
  54. package/dist/esm-node/locale/zh.js +12 -2
  55. package/dist/esm-node/ultramodern-tooling/commands.js +379 -0
  56. package/dist/esm-node/ultramodern-tooling/config.js +121 -0
  57. package/dist/esm-node/ultramodern-workspace/add-vertical.js +88 -79
  58. package/dist/esm-node/ultramodern-workspace/{effect-api.js → api.js} +146 -147
  59. package/dist/esm-node/ultramodern-workspace/bridge-config.js +271 -0
  60. package/dist/esm-node/ultramodern-workspace/codesmith.js +1 -0
  61. package/dist/esm-node/ultramodern-workspace/contracts.js +130 -611
  62. package/dist/esm-node/ultramodern-workspace/demo-components.js +13 -13
  63. package/dist/esm-node/ultramodern-workspace/descriptors.js +11 -11
  64. package/dist/esm-node/ultramodern-workspace/fs-io.js +116 -2
  65. package/dist/esm-node/ultramodern-workspace/generation-result.js +6 -6
  66. package/dist/esm-node/ultramodern-workspace/index.js +1 -0
  67. package/dist/esm-node/ultramodern-workspace/mf-validation.js +517 -0
  68. package/dist/esm-node/ultramodern-workspace/module-federation.js +40 -13
  69. package/dist/esm-node/ultramodern-workspace/overlays.js +2 -2
  70. package/dist/esm-node/ultramodern-workspace/package-json.js +57 -40
  71. package/dist/esm-node/ultramodern-workspace/policy.js +5 -5
  72. package/dist/esm-node/ultramodern-workspace/public-api.js +1 -0
  73. package/dist/esm-node/ultramodern-workspace/public-surface.js +2 -2
  74. package/dist/esm-node/ultramodern-workspace/versions.js +7 -1
  75. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +108 -34
  76. package/dist/esm-node/ultramodern-workspace/write-workspace.js +66 -26
  77. package/dist/types/locale/en.d.ts +10 -0
  78. package/dist/types/locale/index.d.ts +20 -0
  79. package/dist/types/locale/zh.d.ts +10 -0
  80. package/dist/types/ultramodern-tooling/commands.d.ts +1 -0
  81. package/dist/types/ultramodern-tooling/config.d.ts +43 -0
  82. package/dist/types/ultramodern-workspace/add-vertical.d.ts +5 -2
  83. package/dist/types/ultramodern-workspace/api.d.ts +73 -0
  84. package/dist/types/ultramodern-workspace/bridge-config.d.ts +64 -0
  85. package/dist/types/ultramodern-workspace/codesmith.d.ts +1 -0
  86. package/dist/types/ultramodern-workspace/contracts.d.ts +2 -17
  87. package/dist/types/ultramodern-workspace/descriptors.d.ts +10 -10
  88. package/dist/types/ultramodern-workspace/fs-io.d.ts +1 -0
  89. package/dist/types/ultramodern-workspace/index.d.ts +2 -0
  90. package/dist/types/ultramodern-workspace/mf-validation.d.ts +27 -0
  91. package/dist/types/ultramodern-workspace/package-json.d.ts +5 -4
  92. package/dist/types/ultramodern-workspace/public-api.d.ts +2 -0
  93. package/dist/types/ultramodern-workspace/types.d.ts +9 -7
  94. package/dist/types/ultramodern-workspace/versions.d.ts +6 -0
  95. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +2 -7
  96. package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -2
  97. package/package.json +5 -3
  98. package/template-workspace/{.agents → .codex}/skills-lock.json +12 -12
  99. package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +2 -0
  100. package/template-workspace/.gitignore.handlebars +3 -0
  101. package/template-workspace/AGENTS.md.handlebars +11 -5
  102. package/template-workspace/README.md.handlebars +55 -13
  103. package/template-workspace/oxfmt.config.ts +1 -0
  104. package/template-workspace/oxlint.config.ts +1 -0
  105. package/template-workspace/patches/@tanstack__router-core@1.171.13.patch +51 -0
  106. package/template-workspace/pnpm-workspace.yaml.handlebars +7 -0
  107. package/template-workspace/scripts/bootstrap-agent-skills.mjs +77 -67
  108. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +51 -8
  109. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +366 -0
  110. package/templates/workspace-scripts/{check-ultramodern-i18n-boundaries.mjs → check-ultramodern-i18n-boundaries.mts} +1 -1
  111. package/templates/workspace-scripts/generate-public-surface-assets.mjs +246 -9
  112. package/templates/workspace-scripts/proof-cloudflare-version.mjs +277 -9
  113. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +35 -10
  114. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +165 -2
  115. package/templates/workspace-scripts/ultramodern-typecheck.mjs +4 -2
  116. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +842 -84
  117. package/dist/types/ultramodern-workspace/effect-api.d.ts +0 -73
  118. /package/template-workspace/{.agents → .codex}/rstackjs-agent-skills-LICENSE +0 -0
  119. /package/template-workspace/{.agents → .codex}/skills/rsbuild-best-practices/SKILL.md +0 -0
  120. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/SKILL.md +0 -0
  121. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/command-map.md +0 -0
  122. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/common-analysis-patterns.md +0 -0
  123. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +0 -0
  124. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +0 -0
  125. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +0 -0
  126. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor.md +0 -0
  127. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +0 -0
  128. /package/template-workspace/{.agents → .codex}/skills/rslib-best-practices/SKILL.md +0 -0
  129. /package/template-workspace/{.agents → .codex}/skills/rslib-modern-package/SKILL.md +0 -0
  130. /package/template-workspace/{.agents → .codex}/skills/rspack-best-practices/SKILL.md +0 -0
  131. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/SKILL.md +0 -0
  132. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/bottlenecks.md +0 -0
  133. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/tracing-guide.md +0 -0
  134. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/scripts/analyze_trace.js +0 -0
  135. /package/template-workspace/{.agents → .codex}/skills/rstest-best-practices/SKILL.md +0 -0
@@ -0,0 +1,121 @@
1
+ import "node:module";
2
+ import node_fs from "node:fs";
3
+ import node_path from "node:path";
4
+ import { normalizeUltramodernBridgeConfig } from "../ultramodern-workspace/bridge-config.js";
5
+ import { ULTRAMODERN_CONFIG_PATH, createNeutralOwnership, shellApp } from "../ultramodern-workspace/descriptors.js";
6
+ import { toKebabCase } from "../ultramodern-workspace/naming.js";
7
+ function readJsonObject(filePath) {
8
+ const value = JSON.parse(node_fs.readFileSync(filePath, 'utf-8'));
9
+ if (null === value || 'object' != typeof value || Array.isArray(value)) throw new Error(`UltraModern config must contain a JSON object: ${filePath}`);
10
+ return value;
11
+ }
12
+ function readOptionalJsonObject(filePath) {
13
+ return node_fs.existsSync(filePath) ? readJsonObject(filePath) : {};
14
+ }
15
+ function packageScopeFromRoot(workspaceRoot1) {
16
+ const rootPackage = readOptionalJsonObject(node_path.join(workspaceRoot1, 'package.json'));
17
+ return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : node_path.basename(workspaceRoot1);
18
+ }
19
+ function normalizeCompactConfig(sourcePath, config) {
20
+ const packageSource = config.packageSource && 'object' == typeof config.packageSource ? {
21
+ strategy: 'install' === config.packageSource.strategy ? 'install' : 'workspace',
22
+ modernPackageVersion: 'string' == typeof config.packageSource.modernPackageVersion ? config.packageSource.modernPackageVersion : 'workspace:*',
23
+ registry: 'string' == typeof config.packageSource.registry ? config.packageSource.registry : void 0,
24
+ aliasScope: 'string' == typeof config.packageSource.aliasScope ? config.packageSource.aliasScope : void 0,
25
+ aliasPackageNamePrefix: 'string' == typeof config.packageSource.aliasPackageNamePrefix ? config.packageSource.aliasPackageNamePrefix : void 0
26
+ } : void 0;
27
+ return {
28
+ schemaVersion: 'number' == typeof config.schemaVersion ? config.schemaVersion : 1,
29
+ profile: 'string' == typeof config.profile ? config.profile : void 0,
30
+ source: 'compact',
31
+ sourcePath,
32
+ workspace: {
33
+ packageScope: 'string' == typeof config.workspace?.packageScope ? config.workspace.packageScope : packageScopeFromRoot(workspaceRoot)
34
+ },
35
+ packageSource,
36
+ features: {
37
+ tailwind: config.features?.tailwind !== false
38
+ },
39
+ bridge: normalizeUltramodernBridgeConfig(config.bridge),
40
+ topology: {
41
+ apps: Array.isArray(config.topology?.apps) ? config.topology.apps.map((app)=>({
42
+ id: String(app.id),
43
+ kind: 'vertical' === app.kind ? 'vertical' : 'shell',
44
+ path: 'string' == typeof app.path ? app.path : '.',
45
+ package: 'string' == typeof app.package ? app.package : void 0,
46
+ packageSuffix: 'string' == typeof app.packageSuffix ? app.packageSuffix : void 0,
47
+ displayName: 'string' == typeof app.displayName ? app.displayName : void 0,
48
+ domain: 'string' == typeof app.domain ? app.domain : void 0,
49
+ port: 'number' == typeof app.port ? app.port : void 0,
50
+ portEnv: 'string' == typeof app.portEnv ? app.portEnv : void 0,
51
+ moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
52
+ role: 'remote' === app.moduleFederation.role ? 'remote' : 'host',
53
+ name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
54
+ exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
55
+ exposePaths: null === app.moduleFederation.exposePaths || 'object' != typeof app.moduleFederation.exposePaths || Array.isArray(app.moduleFederation.exposePaths) ? void 0 : Object.fromEntries(Object.entries(app.moduleFederation.exposePaths).filter((entry)=>'string' == typeof entry[0] && 'string' == typeof entry[1])),
56
+ verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
57
+ hostOnly: true === app.moduleFederation.hostOnly,
58
+ noExposes: true === app.moduleFederation.noExposes
59
+ } : void 0,
60
+ api: app.api && 'object' == typeof app.api ? {
61
+ stem: 'string' == typeof app.api.stem ? app.api.stem : String(app.id),
62
+ prefix: 'string' == typeof app.api.prefix ? app.api.prefix : `/${String(app.id)}-api`,
63
+ consumedBy: Array.isArray(app.api.consumedBy) ? app.api.consumedBy.filter((consumer)=>'string' == typeof consumer) : [
64
+ shellApp.id,
65
+ String(app.id)
66
+ ]
67
+ } : void 0
68
+ })) : []
69
+ }
70
+ };
71
+ }
72
+ function readUltramodernConfig(workspaceRoot1 = process.cwd()) {
73
+ const compactPath = node_path.join(workspaceRoot1, ULTRAMODERN_CONFIG_PATH);
74
+ if (node_fs.existsSync(compactPath)) return normalizeCompactConfig(compactPath, readJsonObject(compactPath));
75
+ throw new Error(`Missing UltraModern config. Expected ${ULTRAMODERN_CONFIG_PATH}.`);
76
+ }
77
+ function workspaceAppsFromToolingConfig(config) {
78
+ return config.topology.apps.map((app)=>{
79
+ if ('shell' === app.kind) return {
80
+ ...shellApp,
81
+ directory: app.path,
82
+ packageSuffix: app.packageSuffix ?? shellApp.packageSuffix,
83
+ displayName: app.displayName ?? shellApp.displayName,
84
+ port: app.port ?? shellApp.port,
85
+ portEnv: app.portEnv ?? shellApp.portEnv,
86
+ mfName: app.moduleFederation?.name ?? shellApp.mfName,
87
+ verticalRefs: app.moduleFederation?.verticalRefs ?? []
88
+ };
89
+ const domain = app.domain ?? app.id;
90
+ const packageSuffix = app.packageSuffix ?? domain;
91
+ const exposePaths = app.moduleFederation?.exposePaths ?? {};
92
+ const exposes = Object.fromEntries((app.moduleFederation?.exposes ?? []).map((expose)=>{
93
+ const configuredPath = exposePaths[expose];
94
+ const inferredPath = './Route' === expose ? './src/federation-entry.tsx' : './Widget' === expose ? `./src/components/${domain}-widget.tsx` : `./src/components/${toKebabCase(expose.replace(/^\.\//u, ''))}.tsx`;
95
+ return [
96
+ expose,
97
+ configuredPath ?? inferredPath
98
+ ];
99
+ }));
100
+ return {
101
+ id: app.id,
102
+ directory: app.path,
103
+ packageSuffix,
104
+ displayName: app.displayName ?? `${domain} Vertical`,
105
+ kind: 'vertical',
106
+ domain,
107
+ portEnv: app.portEnv ?? `VERTICAL_${domain.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}_PORT`,
108
+ port: app.port ?? 0,
109
+ mfName: app.moduleFederation?.name ?? app.id,
110
+ exposes,
111
+ ...app.moduleFederation?.verticalRefs ? {
112
+ verticalRefs: app.moduleFederation.verticalRefs
113
+ } : {},
114
+ ...app.api ? {
115
+ api: app.api
116
+ } : {},
117
+ ownership: createNeutralOwnership(app.id)
118
+ };
119
+ });
120
+ }
121
+ export { readUltramodernConfig, workspaceAppsFromToolingConfig };
@@ -3,12 +3,12 @@ import node_fs from "node:fs";
3
3
  import node_os from "node:os";
4
4
  import node_path from "node:path";
5
5
  import { WORKSPACE_PACKAGE_VERSION } from "../ultramodern-package-source.js";
6
+ import { readUltramodernConfig } from "../ultramodern-tooling/config.js";
7
+ import { apiTopologyMetadata, createShellApiClient } from "./api.js";
6
8
  import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "./app-files.js";
7
- import { createGeneratedContract } from "./contracts.js";
8
9
  import { createShellPage, createShellRemoteComponents } from "./demo-components.js";
9
- import { GENERATED_CONTRACT_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
10
- import { createShellEffectClient, effectApiTopologyMetadata } from "./effect-api.js";
11
- import { readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
10
+ import { ULTRAMODERN_CONFIG_PATH, appHasApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, remoteDependencyAlias, resolveApiPrefix, shellApp, zephyrRemoteDependency } from "./descriptors.js";
11
+ import { formatGeneratedWorkspaceFiles, readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
12
12
  import { createFileSnapshot, createGenerationResult, diffFileSnapshots } from "./generation-result.js";
13
13
  import { createAppPublicLocaleMessages } from "./locales.js";
14
14
  import { createShellModuleFederationConfig } from "./module-federation.js";
@@ -20,12 +20,11 @@ import { createCloudflareDeployContract } from "./policy.js";
20
20
  import { createPublicWebAppArtifacts, rewriteWorkspaceAssetsForApp } from "./public-surface.js";
21
21
  import { isRecord } from "./types.js";
22
22
  import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
23
- import { writeApp } from "./write-workspace.js";
23
+ import { createCompactUltramodernConfig, writeApp } from "./write-workspace.js";
24
24
  const FIRST_VERTICAL_PORT = 4101;
25
25
  const TOPOLOGY_PATH = 'topology/reference-topology.json';
26
26
  const OWNERSHIP_PATH = 'topology/ownership.json';
27
27
  const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
28
- const PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
29
28
  function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
30
29
  if (packageSource) return resolvePackageSource({
31
30
  targetDir: workspaceRoot,
@@ -33,35 +32,21 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
33
32
  modernVersion,
34
33
  packageSource
35
34
  });
36
- const metadataPath = node_path.join(workspaceRoot, '.modernjs/ultramodern-package-source.json');
37
- if (!node_fs.existsSync(metadataPath)) return resolvePackageSource({
38
- targetDir: workspaceRoot,
39
- packageName: node_path.basename(workspaceRoot),
40
- modernVersion
41
- });
42
- const metadata = readJsonFile(metadataPath);
43
- const aliases = metadata.modernPackages?.aliases ?? {};
44
- const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
45
- const firstPackage = Object.keys(aliases)[0];
46
- const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
47
- const unscopedName = firstPackage?.split('/').at(-1) ?? '';
48
- const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
49
- const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
50
- return {
51
- strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
52
- modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : modernVersion,
53
- registry: metadata.modernPackages?.registry,
54
- aliasScope,
55
- aliasPackageNamePrefix
56
- };
35
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
36
+ if (node_fs.existsSync(compactPath)) {
37
+ const compactConfig = readUltramodernConfig(workspaceRoot);
38
+ if (compactConfig.packageSource) return compactConfig.packageSource;
39
+ }
40
+ throw new Error(`Missing UltraModern workspace file: ${compactPath}`);
57
41
  }
58
42
  function existingTailwindEnabled(workspaceRoot) {
59
- const contractPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
60
- if (!node_fs.existsSync(contractPath)) return true;
61
- const contract = readJsonFile(contractPath);
62
- const apps = isRecord(contract) && Array.isArray(contract.apps) ? contract.apps : [];
63
- const shell = apps.find((app)=>isRecord(app) && app.id === shellApp.id);
64
- return shell?.styling && isRecord(shell.styling) ? false !== shell.styling.tailwind : true;
43
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
44
+ if (node_fs.existsSync(compactPath)) return readUltramodernConfig(workspaceRoot).features.tailwind;
45
+ throw new Error(`Missing UltraModern workspace file: ${compactPath}`);
46
+ }
47
+ function existingBridgeConfig(workspaceRoot) {
48
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
49
+ return node_fs.existsSync(compactPath) ? readUltramodernConfig(workspaceRoot).bridge : void 0;
65
50
  }
66
51
  function assertValidVerticalName(name) {
67
52
  const normalized = toKebabCase(name);
@@ -75,17 +60,17 @@ function nextAvailablePort(ports) {
75
60
  function assertCanCreate(workspaceRoot, relativePath) {
76
61
  if (node_fs.existsSync(node_path.join(workspaceRoot, relativePath))) throw new Error(`Refusing to overwrite existing path: ${relativePath}`);
77
62
  }
78
- function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes) {
63
+ function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes, bridge) {
79
64
  const packagePath = node_path.join(workspaceRoot, 'package.json');
80
65
  const rootPackage = readJsonFile(packagePath);
81
- const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes);
66
+ const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes, bridge);
82
67
  rootPackage.scripts = generatedRootPackage.scripts;
83
68
  writeJsonFile(packagePath, rootPackage);
84
69
  }
85
- function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes) {
70
+ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes, bridge) {
86
71
  const shellHost = createShellHost(remotes);
87
72
  const publicWeb = createPublicWebAppArtifacts(shellHost);
88
- writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes));
73
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes, bridge));
89
74
  writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.json`), createAppTsConfig(shellHost, remotes));
90
75
  writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.mf-types.json`), createAppMfTypesTsConfig(shellHost));
91
76
  writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(shellHost, remotes));
@@ -103,7 +88,7 @@ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwin
103
88
  writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/routes/[lang]/page.tsx`, createShellPage(remotes));
104
89
  writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/routes/vertical-components.tsx`, createShellRemoteComponents(scope, remotes));
105
90
  writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/routes/shell-frame.tsx`, createShellFrameComponent());
106
- writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/effect/vertical-clients.ts`, createShellEffectClient(scope, remotes));
91
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/api/vertical-clients.ts`, createShellApiClient(scope, remotes));
107
92
  }
108
93
  function addShellZephyrDependency(workspaceRoot, scope, remote) {
109
94
  const packagePath = node_path.join(workspaceRoot, shellApp.directory, 'package.json');
@@ -113,7 +98,7 @@ function addShellZephyrDependency(workspaceRoot, scope, remote) {
113
98
  writeJsonFile(packagePath, shellPackage);
114
99
  }
115
100
  function addShellWorkspaceDependency(workspaceRoot, scope, remote) {
116
- if (!appHasEffectApi(remote)) return;
101
+ if (!appHasApi(remote)) return;
117
102
  const packagePath = node_path.join(workspaceRoot, shellApp.directory, 'package.json');
118
103
  const shellPackage = readJsonFile(packagePath);
119
104
  shellPackage.dependencies ??= {};
@@ -140,8 +125,8 @@ function verticalTopologyEntry(scope, vertical, remotes = []) {
140
125
  fallbackTelemetryEvent: 'modernjs:mv-runtime-parity',
141
126
  sharedContractVersion: 'mf-ssr-contract-v1'
142
127
  },
143
- ...effectApiTopologyMetadata(vertical) ? {
144
- api: effectApiTopologyMetadata(vertical)
128
+ ...apiTopologyMetadata(vertical) ? {
129
+ api: apiTopologyMetadata(vertical)
145
130
  } : {},
146
131
  cloudflare: createCloudflareDeployContract(scope, vertical),
147
132
  ownership: vertical.ownership
@@ -159,10 +144,11 @@ function verticalsFromTopology(topology, ports) {
159
144
  return (topology.verticals ?? []).map((vertical)=>{
160
145
  const domain = vertical.domain ?? String(vertical.id);
161
146
  const packageSuffix = vertical.package?.split('/').at(-1) ?? domain;
162
- const effectApi = vertical.api?.effect ? {
163
- stem: 'string' == typeof vertical.api.effect.basePath ? vertical.api.effect.basePath.split('/').filter(Boolean).at(-1) ?? domain : domain,
164
- prefix: vertical.api.effect.bff?.prefix ?? `/${domain}-api`,
165
- consumedBy: Array.isArray(vertical.api.effect.consumedBy) ? vertical.api.effect.consumedBy : [
147
+ const apiTopology = vertical.api;
148
+ const api = apiTopology?.runtime === 'effect' ? {
149
+ stem: 'string' == typeof apiTopology.basePath ? apiTopology.basePath.split('/').filter(Boolean).at(-1) ?? domain : domain,
150
+ prefix: apiTopology.bff?.prefix ?? `/${domain}-api`,
151
+ consumedBy: Array.isArray(apiTopology.consumedBy) ? apiTopology.consumedBy : [
166
152
  shellApp.id,
167
153
  vertical.id
168
154
  ]
@@ -188,8 +174,8 @@ function verticalsFromTopology(topology, ports) {
188
174
  } : Array.isArray(vertical.moduleFederation?.remotes) ? {
189
175
  verticalRefs: vertical.moduleFederation.remotes.map((entry)=>entry.id).filter((id)=>'string' == typeof id)
190
176
  } : {},
191
- ...effectApi ? {
192
- effectApi
177
+ ...api ? {
178
+ api
193
179
  } : {},
194
180
  ownership: vertical.ownership ?? createNeutralOwnership(vertical.id)
195
181
  };
@@ -204,8 +190,7 @@ function prepareAddUltramodernVertical(options) {
204
190
  const topology = readRequiredJsonObject(topologyPath);
205
191
  const ownership = readRequiredJsonObject(ownershipPath);
206
192
  const overlay = readRequiredJsonObject(overlayPath);
207
- readRequiredJsonObject(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH));
208
- readRequiredJsonObject(node_path.join(options.workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
193
+ readRequiredWorkspaceConfig(options.workspaceRoot);
209
194
  assertOptionalJsonObject(topology.shell, 'topology.shell', topologyPath);
210
195
  assertOptionalJsonArray(topology.verticals, 'topology.verticals', topologyPath);
211
196
  assertOptionalJsonArray(ownership.owners, 'ownership.owners', ownershipPath);
@@ -216,6 +201,7 @@ function prepareAddUltramodernVertical(options) {
216
201
  const scope = toPackageScope(String(rootPackage.name ?? node_path.basename(options.workspaceRoot)));
217
202
  const packageSource = existingPackageSource(options.workspaceRoot, options.modernVersion, options.packageSource);
218
203
  const enableTailwind = options.enableTailwind ?? existingTailwindEnabled(options.workspaceRoot);
204
+ const bridge = existingBridgeConfig(options.workspaceRoot);
219
205
  const existingVerticals = verticalsFromTopology(topology, overlay.ports);
220
206
  const port = nextAvailablePort(overlay.ports);
221
207
  const vertical = createVerticalDescriptor(name, port);
@@ -243,6 +229,7 @@ function prepareAddUltramodernVertical(options) {
243
229
  overlay,
244
230
  packageSource,
245
231
  enableTailwind,
232
+ bridge,
246
233
  vertical,
247
234
  updatedVerticals
248
235
  };
@@ -253,6 +240,10 @@ function readRequiredJsonObject(filePath) {
253
240
  if (!isRecord(value)) throw new Error(`UltraModern workspace file must contain a JSON object: ${filePath}`);
254
241
  return value;
255
242
  }
243
+ function readRequiredWorkspaceConfig(workspaceRoot) {
244
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
245
+ readRequiredJsonObject(compactPath);
246
+ }
256
247
  function assertOptionalJsonObject(value, label, filePath) {
257
248
  if (void 0 !== value && !isRecord(value)) throw new Error(`${label} in ${filePath} must be a JSON object`);
258
249
  }
@@ -271,9 +262,9 @@ function validateWorkspaceAppDescriptors(apps) {
271
262
  assertNonEmptyString(app.portEnv, `port env for ${appLabel}`);
272
263
  if ('number' != typeof app.port || !Number.isFinite(app.port) || app.port <= 0) throw new Error(`Invalid development port for ${appLabel}`);
273
264
  assertNonEmptyString(app.mfName, `Module Federation name for ${appLabel}`);
274
- if (app.effectApi) {
275
- assertNonEmptyString(app.effectApi.prefix, `Effect API prefix for ${appLabel}`);
276
- if (!app.effectApi.prefix.startsWith('/')) throw new Error(`Effect API prefix for ${appLabel} must start with "/"`);
265
+ if (app.api) {
266
+ assertNonEmptyString(app.api.prefix, `API prefix for ${appLabel}`);
267
+ if (!app.api.prefix.startsWith('/')) throw new Error(`API prefix for ${appLabel} must start with "/"`);
277
268
  }
278
269
  }
279
270
  }
@@ -283,7 +274,7 @@ function validateUniqueWorkspaceAppDescriptors(apps) {
283
274
  assertUniqueAppField(apps, 'output path', (app)=>normalizePath(app.directory));
284
275
  assertUniqueAppField(apps, 'Module Federation name', (app)=>app.mfName);
285
276
  assertUniqueAppField(apps, 'development port', (app)=>String(app.port));
286
- assertUniqueAppField(apps, 'Effect API prefix', (app)=>app.effectApi?.prefix);
277
+ assertUniqueAppField(apps, 'API prefix', (app)=>app.api?.prefix);
287
278
  assertUniqueAppField(apps, 'manifest environment name', (app)=>'vertical' === app.kind ? createRemoteManifestEnv(app) : void 0);
288
279
  }
289
280
  function assertUniqueAppField(apps, label, readValue) {
@@ -350,14 +341,14 @@ function createVerticalPlan(preflight, result) {
350
341
  name: vertical.mfName,
351
342
  manifestUrl
352
343
  },
353
- ...vertical.effectApi ? {
354
- effectApiPrefix: effectApiPrefix(vertical)
344
+ ...vertical.api ? {
345
+ apiPrefix: resolveApiPrefix(vertical)
355
346
  } : {},
356
347
  jsonMutations: createDryRunJsonMutations(preflight, manifestUrl),
357
348
  shellDependencyChanges: createShellDependencyChanges(scope, vertical),
358
349
  generatedContractChanges: [
359
350
  {
360
- path: GENERATED_CONTRACT_PATH,
351
+ path: ULTRAMODERN_CONFIG_PATH,
361
352
  addedAppIds: [
362
353
  vertical.id
363
354
  ],
@@ -368,12 +359,12 @@ function createVerticalPlan(preflight, result) {
368
359
  }
369
360
  function createDryRunJsonMutations(preflight, manifestUrl) {
370
361
  const { scope, vertical } = preflight;
371
- const effectApiMutation = appHasEffectApi(vertical) ? [
362
+ const apiMutation = appHasApi(vertical) ? [
372
363
  {
373
364
  path: DEVELOPMENT_OVERLAY_PATH,
374
365
  pointer: `/apis/${vertical.id}`,
375
- description: `Add local Effect API URL for ${vertical.id}`,
376
- value: `http://localhost:${vertical.port}${effectApiPrefix(vertical)}`
366
+ description: `Add local API URL for ${vertical.id}`,
367
+ value: `http://localhost:${vertical.port}${resolveApiPrefix(vertical)}`
377
368
  }
378
369
  ] : [];
379
370
  return [
@@ -417,7 +408,7 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
417
408
  description: `Add local Module Federation manifest URL for ${vertical.id}`,
418
409
  value: manifestUrl
419
410
  },
420
- ...effectApiMutation,
411
+ ...apiMutation,
421
412
  {
422
413
  path: 'package.json',
423
414
  pointer: "/scripts",
@@ -444,9 +435,9 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
444
435
  description: 'Keep shell Module Federation DTS compilation scoped'
445
436
  },
446
437
  {
447
- path: GENERATED_CONTRACT_PATH,
448
- pointer: '/apps',
449
- description: `Regenerate contract with ${vertical.id}`
438
+ path: ULTRAMODERN_CONFIG_PATH,
439
+ pointer: '/topology/apps',
440
+ description: `Regenerate compact config with ${vertical.id}`
450
441
  }
451
442
  ];
452
443
  }
@@ -458,7 +449,7 @@ function createShellDependencyChanges(scope, vertical) {
458
449
  packageName: remoteDependencyAlias(vertical),
459
450
  version: zephyrRemoteDependency(scope, vertical)
460
451
  },
461
- ...appHasEffectApi(vertical) ? [
452
+ ...appHasApi(vertical) ? [
462
453
  {
463
454
  path: `${shellApp.directory}/package.json`,
464
455
  section: 'dependencies',
@@ -470,8 +461,8 @@ function createShellDependencyChanges(scope, vertical) {
470
461
  }
471
462
  function addUltramodernVertical(options) {
472
463
  const beforeFiles = createFileSnapshot(options.workspaceRoot);
473
- const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
474
- writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind);
464
+ const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, bridge, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
465
+ writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind, updatedVerticals, bridge);
475
466
  topology.shell ??= {};
476
467
  topology.shell.verticalRefs ??= [];
477
468
  topology.shell.verticalRefs.push(vertical.id);
@@ -490,22 +481,22 @@ function addUltramodernVertical(options) {
490
481
  overlay.manifests ??= {};
491
482
  overlay.manifests[vertical.id] = `http://localhost:${vertical.port}/mf-manifest.json`;
492
483
  overlay.apis ??= {};
493
- overlay.apis[vertical.id] = `http://localhost:${vertical.port}${effectApiPrefix(vertical)}`;
484
+ overlay.apis[vertical.id] = `http://localhost:${vertical.port}${resolveApiPrefix(vertical)}`;
494
485
  writeJsonFile(topologyPath, topology);
495
486
  writeJsonFile(ownershipPath, ownership);
496
487
  writeJsonFile(overlayPath, overlay);
497
- writeJsonFile(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH), createGeneratedContract(scope, [
488
+ writeJsonFile(node_path.join(options.workspaceRoot, ULTRAMODERN_CONFIG_PATH), createCompactUltramodernConfig(scope, options.modernVersion, packageSource, [
498
489
  {
499
490
  ...shellApp,
500
491
  verticalRefs: updatedVerticals.map((vertical)=>vertical.id)
501
492
  },
502
493
  ...updatedVerticals
503
- ], enableTailwind));
504
- rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals);
494
+ ], enableTailwind, bridge));
495
+ rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals, bridge);
505
496
  writeGeneratedWorkspaceScripts(options.workspaceRoot, scope, enableTailwind, updatedVerticals);
506
497
  addShellZephyrDependency(options.workspaceRoot, scope, vertical);
507
498
  addShellWorkspaceDependency(options.workspaceRoot, scope, vertical);
508
- updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals);
499
+ updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals, bridge);
509
500
  writeJsonFile(node_path.join(options.workspaceRoot, 'tsconfig.json'), createRootTsConfig([
510
501
  {
511
502
  ...shellApp,
@@ -513,9 +504,9 @@ function addUltramodernVertical(options) {
513
504
  },
514
505
  ...updatedVerticals
515
506
  ]));
516
- const afterFiles = createFileSnapshot(options.workspaceRoot);
517
- const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
518
- const result = createGenerationResult({
507
+ const preliminaryAfterFiles = createFileSnapshot(options.workspaceRoot);
508
+ const preliminaryDiff = diffFileSnapshots(beforeFiles, preliminaryAfterFiles);
509
+ const preliminaryResult = createGenerationResult({
519
510
  operation: 'vertical',
520
511
  workspaceRoot: options.workspaceRoot,
521
512
  packageScope: scope,
@@ -523,14 +514,32 @@ function addUltramodernVertical(options) {
523
514
  createdApps: [
524
515
  vertical
525
516
  ],
526
- createdPaths,
527
- rewrittenPaths
517
+ createdPaths: preliminaryDiff.createdPaths,
518
+ rewrittenPaths: preliminaryDiff.rewrittenPaths
528
519
  });
529
520
  runCodeSmithOverlays({
530
521
  workspaceRoot: options.workspaceRoot,
531
522
  overlays: options.overlays,
532
- result
523
+ result: preliminaryResult
524
+ });
525
+ const afterOverlaysFiles = createFileSnapshot(options.workspaceRoot);
526
+ const changedPaths = diffFileSnapshots(beforeFiles, afterOverlaysFiles);
527
+ formatGeneratedWorkspaceFiles(options.workspaceRoot, [
528
+ ...changedPaths.createdPaths,
529
+ ...changedPaths.rewrittenPaths
530
+ ]);
531
+ const afterFiles = createFileSnapshot(options.workspaceRoot);
532
+ const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
533
+ return createGenerationResult({
534
+ operation: 'vertical',
535
+ workspaceRoot: options.workspaceRoot,
536
+ packageScope: scope,
537
+ packageSource,
538
+ createdApps: [
539
+ vertical
540
+ ],
541
+ createdPaths,
542
+ rewrittenPaths
533
543
  });
534
- return result;
535
544
  }
536
- export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };
545
+ export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingBridgeConfig, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };