@bleedingdev/modern-js-create 3.4.0-ultramodern.12 → 3.4.0-ultramodern.14

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 (108) hide show
  1. package/README.md +13 -11
  2. package/dist/cjs/index.cjs +36 -3
  3. package/dist/cjs/locale/en.cjs +10 -0
  4. package/dist/cjs/locale/zh.cjs +10 -0
  5. package/dist/cjs/ultramodern-tooling/commands.cjs +185 -0
  6. package/dist/cjs/ultramodern-tooling/config.cjs +248 -0
  7. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +64 -25
  8. package/dist/cjs/ultramodern-workspace/bridge-config.cjs +327 -0
  9. package/dist/cjs/ultramodern-workspace/codesmith.cjs +1 -0
  10. package/dist/cjs/ultramodern-workspace/contracts.cjs +119 -653
  11. package/dist/cjs/ultramodern-workspace/descriptors.cjs +4 -0
  12. package/dist/cjs/ultramodern-workspace/fs-io.cjs +117 -0
  13. package/dist/cjs/ultramodern-workspace/generation-result.cjs +1 -1
  14. package/dist/cjs/ultramodern-workspace/index.cjs +4 -0
  15. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +572 -0
  16. package/dist/cjs/ultramodern-workspace/module-federation.cjs +14 -0
  17. package/dist/cjs/ultramodern-workspace/package-json.cjs +26 -12
  18. package/dist/cjs/ultramodern-workspace/public-api.cjs +4 -0
  19. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +74 -44
  20. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +55 -15
  21. package/dist/esm/index.js +36 -3
  22. package/dist/esm/locale/en.js +10 -0
  23. package/dist/esm/locale/zh.js +10 -0
  24. package/dist/esm/ultramodern-tooling/commands.js +132 -0
  25. package/dist/esm/ultramodern-tooling/config.js +196 -0
  26. package/dist/esm/ultramodern-workspace/add-vertical.js +65 -29
  27. package/dist/esm/ultramodern-workspace/bridge-config.js +270 -0
  28. package/dist/esm/ultramodern-workspace/codesmith.js +1 -0
  29. package/dist/esm/ultramodern-workspace/contracts.js +122 -608
  30. package/dist/esm/ultramodern-workspace/descriptors.js +2 -1
  31. package/dist/esm/ultramodern-workspace/fs-io.js +116 -2
  32. package/dist/esm/ultramodern-workspace/generation-result.js +2 -2
  33. package/dist/esm/ultramodern-workspace/index.js +1 -0
  34. package/dist/esm/ultramodern-workspace/mf-validation.js +517 -0
  35. package/dist/esm/ultramodern-workspace/module-federation.js +14 -0
  36. package/dist/esm/ultramodern-workspace/package-json.js +26 -12
  37. package/dist/esm/ultramodern-workspace/public-api.js +1 -0
  38. package/dist/esm/ultramodern-workspace/workspace-scripts.js +75 -27
  39. package/dist/esm/ultramodern-workspace/write-workspace.js +56 -19
  40. package/dist/esm-node/index.js +36 -3
  41. package/dist/esm-node/locale/en.js +10 -0
  42. package/dist/esm-node/locale/zh.js +10 -0
  43. package/dist/esm-node/ultramodern-tooling/commands.js +133 -0
  44. package/dist/esm-node/ultramodern-tooling/config.js +197 -0
  45. package/dist/esm-node/ultramodern-workspace/add-vertical.js +65 -29
  46. package/dist/esm-node/ultramodern-workspace/bridge-config.js +271 -0
  47. package/dist/esm-node/ultramodern-workspace/codesmith.js +1 -0
  48. package/dist/esm-node/ultramodern-workspace/contracts.js +122 -608
  49. package/dist/esm-node/ultramodern-workspace/descriptors.js +2 -1
  50. package/dist/esm-node/ultramodern-workspace/fs-io.js +116 -2
  51. package/dist/esm-node/ultramodern-workspace/generation-result.js +2 -2
  52. package/dist/esm-node/ultramodern-workspace/index.js +1 -0
  53. package/dist/esm-node/ultramodern-workspace/mf-validation.js +518 -0
  54. package/dist/esm-node/ultramodern-workspace/module-federation.js +14 -0
  55. package/dist/esm-node/ultramodern-workspace/package-json.js +26 -12
  56. package/dist/esm-node/ultramodern-workspace/public-api.js +1 -0
  57. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +75 -27
  58. package/dist/esm-node/ultramodern-workspace/write-workspace.js +56 -19
  59. package/dist/types/locale/en.d.ts +10 -0
  60. package/dist/types/locale/index.d.ts +20 -0
  61. package/dist/types/locale/zh.d.ts +10 -0
  62. package/dist/types/ultramodern-tooling/commands.d.ts +1 -0
  63. package/dist/types/ultramodern-tooling/config.d.ts +43 -0
  64. package/dist/types/ultramodern-workspace/add-vertical.d.ts +5 -2
  65. package/dist/types/ultramodern-workspace/bridge-config.d.ts +64 -0
  66. package/dist/types/ultramodern-workspace/codesmith.d.ts +1 -0
  67. package/dist/types/ultramodern-workspace/contracts.d.ts +2 -17
  68. package/dist/types/ultramodern-workspace/descriptors.d.ts +1 -0
  69. package/dist/types/ultramodern-workspace/fs-io.d.ts +1 -0
  70. package/dist/types/ultramodern-workspace/index.d.ts +2 -0
  71. package/dist/types/ultramodern-workspace/mf-validation.d.ts +27 -0
  72. package/dist/types/ultramodern-workspace/package-json.d.ts +4 -3
  73. package/dist/types/ultramodern-workspace/public-api.d.ts +2 -0
  74. package/dist/types/ultramodern-workspace/types.d.ts +2 -0
  75. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +1 -7
  76. package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -2
  77. package/package.json +5 -3
  78. package/template-workspace/{.agents → .codex}/skills-lock.json +12 -12
  79. package/template-workspace/.gitignore.handlebars +3 -0
  80. package/template-workspace/AGENTS.md.handlebars +11 -5
  81. package/template-workspace/README.md.handlebars +15 -12
  82. package/template-workspace/oxfmt.config.ts +1 -0
  83. package/template-workspace/oxlint.config.ts +1 -0
  84. package/template-workspace/scripts/bootstrap-agent-skills.mjs +77 -67
  85. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +56 -3
  86. package/templates/workspace-scripts/generate-public-surface-assets.mjs +239 -4
  87. package/templates/workspace-scripts/proof-cloudflare-version.mjs +282 -4
  88. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +172 -1
  89. package/templates/workspace-scripts/ultramodern-typecheck.mjs +4 -2
  90. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +783 -26
  91. /package/template-workspace/{.agents → .codex}/rstackjs-agent-skills-LICENSE +0 -0
  92. /package/template-workspace/{.agents → .codex}/skills/rsbuild-best-practices/SKILL.md +0 -0
  93. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/SKILL.md +0 -0
  94. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/command-map.md +0 -0
  95. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/common-analysis-patterns.md +0 -0
  96. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-common.md +0 -0
  97. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-rspack.md +0 -0
  98. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor-webpack.md +0 -0
  99. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/install-rsdoctor.md +0 -0
  100. /package/template-workspace/{.agents → .codex}/skills/rsdoctor-analysis/references/rsdoctor-data-types.md +0 -0
  101. /package/template-workspace/{.agents → .codex}/skills/rslib-best-practices/SKILL.md +0 -0
  102. /package/template-workspace/{.agents → .codex}/skills/rslib-modern-package/SKILL.md +0 -0
  103. /package/template-workspace/{.agents → .codex}/skills/rspack-best-practices/SKILL.md +0 -0
  104. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/SKILL.md +0 -0
  105. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/bottlenecks.md +0 -0
  106. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/references/tracing-guide.md +0 -0
  107. /package/template-workspace/{.agents → .codex}/skills/rspack-tracing/scripts/analyze_trace.js +0 -0
  108. /package/template-workspace/{.agents → .codex}/skills/rstest-best-practices/SKILL.md +0 -0
@@ -0,0 +1,132 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import node_fs from "node:fs";
3
+ import node_os from "node:os";
4
+ import node_path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { resolveCreatePackageRoot } from "../create-package-root.js";
7
+ import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
8
+ import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
9
+ import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
10
+ const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
11
+ const createPackageRoot = resolveCreatePackageRoot(commands_dirname);
12
+ function printHelp() {
13
+ process.stdout.write(`Usage:
14
+ modern-js-create ultramodern <command> [args]
15
+
16
+ Commands:
17
+ validate
18
+ typecheck
19
+ mf-types
20
+ public-surface
21
+ cloudflare-proof
22
+ performance-readiness
23
+ skills install
24
+ skills check
25
+ `);
26
+ }
27
+ function spawnNodeScript(relativeScriptPath, args, context, options = {}) {
28
+ const scriptPath = node_path.join(createPackageRoot, relativeScriptPath);
29
+ const result = spawnSync(process.execPath, [
30
+ scriptPath,
31
+ ...args
32
+ ], {
33
+ cwd: options.cwd ?? context.workspaceRoot,
34
+ env: {
35
+ ...process.env,
36
+ ULTRAMODERN_WORKSPACE_ROOT: context.workspaceRoot
37
+ },
38
+ stdio: 'inherit'
39
+ });
40
+ if (result.error) throw result.error;
41
+ return result.status ?? 1;
42
+ }
43
+ function runRenderedModule(source, context) {
44
+ const tempDir = node_fs.mkdtempSync(node_path.join(node_os.tmpdir(), 'ultramodern-tool-'));
45
+ const tempFile = node_path.join(tempDir, 'command.mjs');
46
+ try {
47
+ node_fs.writeFileSync(tempFile, source, 'utf-8');
48
+ const result = spawnSync(process.execPath, [
49
+ tempFile
50
+ ], {
51
+ cwd: context.workspaceRoot,
52
+ stdio: 'inherit'
53
+ });
54
+ if (result.error) throw result.error;
55
+ return result.status ?? 1;
56
+ } finally{
57
+ node_fs.rmSync(tempDir, {
58
+ force: true,
59
+ recursive: true
60
+ });
61
+ }
62
+ }
63
+ function runValidate(context) {
64
+ const config = readUltramodernConfig(context.workspaceRoot);
65
+ const apps = workspaceAppsFromToolingConfig(config);
66
+ const remotes = apps.filter((app)=>'shell' !== app.kind);
67
+ const source = createWorkspaceValidationScript(config.workspace.packageScope, config.features.tailwind, remotes);
68
+ return runRenderedModule(source, context);
69
+ }
70
+ function runMfTypes(args, context) {
71
+ if (args.includes('--help') || args.includes('-h')) {
72
+ process.stdout.write(`Usage:
73
+ modern-js-create ultramodern mf-types [app-dir...]
74
+
75
+ Checks real Module Federation config files and DTS archives for exposed apps.
76
+ `);
77
+ return 0;
78
+ }
79
+ validateModuleFederationTypes({
80
+ workspaceRoot: context.workspaceRoot,
81
+ appDirs: args.length > 0 ? args : void 0
82
+ });
83
+ return 0;
84
+ }
85
+ function runSkills(args, context) {
86
+ const [subcommand, ...rest] = args;
87
+ if ('install' === subcommand) return spawnNodeScript("template-workspace/scripts/bootstrap-agent-skills.mjs", rest, context);
88
+ if ('check' === subcommand) return spawnNodeScript("template-workspace/scripts/bootstrap-agent-skills.mjs", [
89
+ '--check',
90
+ ...rest
91
+ ], context);
92
+ throw new Error('Usage: modern-js-create ultramodern skills <install|check>');
93
+ }
94
+ async function runUltramodernToolingCli(args, workspaceRoot = process.env.ULTRAMODERN_WORKSPACE_ROOT ?? process.cwd()) {
95
+ try {
96
+ const [command, ...rest] = args;
97
+ const context = {
98
+ workspaceRoot: node_path.resolve(workspaceRoot),
99
+ invocationCwd: process.cwd()
100
+ };
101
+ switch(command){
102
+ case void 0:
103
+ case '--help':
104
+ case '-h':
105
+ printHelp();
106
+ return 0;
107
+ case 'validate':
108
+ return runValidate(context);
109
+ case 'typecheck':
110
+ return spawnNodeScript("templates/workspace-scripts/ultramodern-typecheck.mjs", rest, context, {
111
+ cwd: context.invocationCwd
112
+ });
113
+ case 'mf-types':
114
+ return runMfTypes(rest, context);
115
+ case 'public-surface':
116
+ return spawnNodeScript("templates/workspace-scripts/generate-public-surface-assets.mjs", rest, context);
117
+ case 'cloudflare-proof':
118
+ return spawnNodeScript("templates/workspace-scripts/proof-cloudflare-version.mjs", rest, context);
119
+ case 'performance-readiness':
120
+ return spawnNodeScript("templates/workspace-scripts/ultramodern-performance-readiness.mjs", rest, context);
121
+ case 'skills':
122
+ return runSkills(rest, context);
123
+ default:
124
+ throw new Error(`Unknown UltraModern command: ${command}`);
125
+ }
126
+ } catch (error) {
127
+ const message = error instanceof Error ? error.message : String(error);
128
+ process.stderr.write(`[ultramodern] ${message}\n`);
129
+ return 1;
130
+ }
131
+ }
132
+ export { runUltramodernToolingCli };
@@ -0,0 +1,196 @@
1
+ import node_fs from "node:fs";
2
+ import node_path from "node:path";
3
+ import { normalizeUltramodernBridgeConfig } from "../ultramodern-workspace/bridge-config.js";
4
+ import { GENERATED_CONTRACT_PATH, ULTRAMODERN_CONFIG_PATH, createNeutralOwnership, shellApp } from "../ultramodern-workspace/descriptors.js";
5
+ import { toKebabCase } from "../ultramodern-workspace/naming.js";
6
+ const PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
7
+ const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
8
+ function readJsonObject(filePath) {
9
+ const value = JSON.parse(node_fs.readFileSync(filePath, 'utf-8'));
10
+ if (null === value || 'object' != typeof value || Array.isArray(value)) throw new Error(`UltraModern config must contain a JSON object: ${filePath}`);
11
+ return value;
12
+ }
13
+ function readOptionalJsonObject(filePath) {
14
+ return node_fs.existsSync(filePath) ? readJsonObject(filePath) : {};
15
+ }
16
+ function packageScopeFromRoot(workspaceRoot) {
17
+ const rootPackage = readOptionalJsonObject(node_path.join(workspaceRoot, 'package.json'));
18
+ return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : node_path.basename(workspaceRoot);
19
+ }
20
+ function packageSourceFromMetadata(workspaceRoot) {
21
+ const metadataPath = node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
22
+ if (!node_fs.existsSync(metadataPath)) return;
23
+ const metadata = readJsonObject(metadataPath);
24
+ const aliases = metadata.modernPackages?.aliases ?? {};
25
+ const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
26
+ const firstPackage = Object.keys(aliases)[0];
27
+ const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
28
+ const unscopedName = firstPackage?.split('/').at(-1) ?? '';
29
+ const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
30
+ const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
31
+ return {
32
+ strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
33
+ modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : 'workspace:*',
34
+ registry: 'string' == typeof metadata.modernPackages?.registry ? metadata.modernPackages.registry : void 0,
35
+ aliasScope,
36
+ aliasPackageNamePrefix
37
+ };
38
+ }
39
+ function readOverlayPorts(workspaceRoot) {
40
+ const overlayPath = node_path.join(workspaceRoot, DEVELOPMENT_OVERLAY_PATH);
41
+ if (!node_fs.existsSync(overlayPath)) return {};
42
+ const overlay = readJsonObject(overlayPath);
43
+ const ports = overlay.ports;
44
+ if (null === ports || 'object' != typeof ports || Array.isArray(ports)) return {};
45
+ return Object.fromEntries(Object.entries(ports).filter((entry)=>'number' == typeof entry[1]));
46
+ }
47
+ function normalizeCompactConfig(workspaceRoot, sourcePath, config) {
48
+ const packageSource = config.packageSource && 'object' == typeof config.packageSource ? {
49
+ strategy: 'install' === config.packageSource.strategy ? 'install' : 'workspace',
50
+ modernPackageVersion: 'string' == typeof config.packageSource.modernPackageVersion ? config.packageSource.modernPackageVersion : 'workspace:*',
51
+ registry: 'string' == typeof config.packageSource.registry ? config.packageSource.registry : void 0,
52
+ aliasScope: 'string' == typeof config.packageSource.aliasScope ? config.packageSource.aliasScope : void 0,
53
+ aliasPackageNamePrefix: 'string' == typeof config.packageSource.aliasPackageNamePrefix ? config.packageSource.aliasPackageNamePrefix : void 0
54
+ } : packageSourceFromMetadata(workspaceRoot);
55
+ return {
56
+ schemaVersion: 'number' == typeof config.schemaVersion ? config.schemaVersion : 1,
57
+ profile: 'string' == typeof config.profile ? config.profile : void 0,
58
+ source: 'compact',
59
+ sourcePath,
60
+ workspace: {
61
+ packageScope: 'string' == typeof config.workspace?.packageScope ? config.workspace.packageScope : packageScopeFromRoot(workspaceRoot)
62
+ },
63
+ packageSource,
64
+ features: {
65
+ tailwind: config.features?.tailwind !== false
66
+ },
67
+ bridge: normalizeUltramodernBridgeConfig(config.bridge),
68
+ topology: {
69
+ apps: Array.isArray(config.topology?.apps) ? config.topology.apps.map((app)=>({
70
+ id: String(app.id),
71
+ kind: 'vertical' === app.kind ? 'vertical' : 'shell',
72
+ path: 'string' == typeof app.path ? app.path : '.',
73
+ package: 'string' == typeof app.package ? app.package : void 0,
74
+ packageSuffix: 'string' == typeof app.packageSuffix ? app.packageSuffix : void 0,
75
+ displayName: 'string' == typeof app.displayName ? app.displayName : void 0,
76
+ domain: 'string' == typeof app.domain ? app.domain : void 0,
77
+ port: 'number' == typeof app.port ? app.port : void 0,
78
+ portEnv: 'string' == typeof app.portEnv ? app.portEnv : void 0,
79
+ moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
80
+ role: 'remote' === app.moduleFederation.role ? 'remote' : 'host',
81
+ name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
82
+ exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
83
+ verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
84
+ hostOnly: true === app.moduleFederation.hostOnly,
85
+ noExposes: true === app.moduleFederation.noExposes
86
+ } : void 0,
87
+ effectApi: app.effectApi && 'object' == typeof app.effectApi ? {
88
+ stem: 'string' == typeof app.effectApi.stem ? app.effectApi.stem : String(app.id),
89
+ prefix: 'string' == typeof app.effectApi.prefix ? app.effectApi.prefix : `/${String(app.id)}-api`,
90
+ consumedBy: Array.isArray(app.effectApi.consumedBy) ? app.effectApi.consumedBy.filter((consumer)=>'string' == typeof consumer) : [
91
+ shellApp.id,
92
+ String(app.id)
93
+ ]
94
+ } : void 0
95
+ })) : []
96
+ }
97
+ };
98
+ }
99
+ function adaptLegacyContract(workspaceRoot, sourcePath, contract) {
100
+ const ports = readOverlayPorts(workspaceRoot);
101
+ const apps = Array.isArray(contract.apps) ? contract.apps : [];
102
+ const shell = apps.find((app)=>app?.id === shellApp.id);
103
+ return {
104
+ schemaVersion: 'number' == typeof contract.schemaVersion ? contract.schemaVersion : 1,
105
+ profile: 'string' == typeof contract.profile ? contract.profile : void 0,
106
+ source: 'legacy',
107
+ sourcePath,
108
+ workspace: {
109
+ packageScope: packageScopeFromRoot(workspaceRoot)
110
+ },
111
+ packageSource: packageSourceFromMetadata(workspaceRoot),
112
+ features: {
113
+ tailwind: shell?.styling?.tailwind !== false
114
+ },
115
+ topology: {
116
+ apps: apps.map((app)=>{
117
+ const id = String(app.id);
118
+ const appPath = 'string' == typeof app.path ? app.path : id === shellApp.id ? shellApp.directory : `verticals/${toKebabCase(id)}`;
119
+ const domain = 'string' == typeof app.i18n?.namespace && 'shell' !== app.i18n.namespace ? app.i18n.namespace : appPath.split('/').at(-1);
120
+ return {
121
+ id,
122
+ kind: 'vertical' === app.kind ? 'vertical' : 'shell',
123
+ path: appPath,
124
+ package: 'string' == typeof app.package ? app.package : void 0,
125
+ packageSuffix: 'string' == typeof app.package ? app.package.split('/').at(-1) : appPath.split('/').at(-1),
126
+ displayName: id === shellApp.id ? shellApp.displayName : void 0,
127
+ domain,
128
+ port: ports[id],
129
+ moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
130
+ role: 'vertical' === app.kind ? 'remote' : 'host',
131
+ name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
132
+ exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
133
+ verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
134
+ hostOnly: 'vertical' !== app.kind
135
+ } : void 0,
136
+ effectApi: app.effect && 'object' == typeof app.effect ? {
137
+ stem: 'string' == typeof app.effect.prefix ? app.effect.prefix.split('/').filter(Boolean).at(-1) ?? domain ?? id : domain ?? id,
138
+ prefix: 'string' == typeof app.effect.prefix ? app.effect.prefix : `/${domain ?? id}-api`,
139
+ consumedBy: [
140
+ shellApp.id,
141
+ id
142
+ ]
143
+ } : void 0
144
+ };
145
+ })
146
+ },
147
+ legacyContract: contract
148
+ };
149
+ }
150
+ function readUltramodernConfig(workspaceRoot = process.cwd()) {
151
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
152
+ if (node_fs.existsSync(compactPath)) return normalizeCompactConfig(workspaceRoot, compactPath, readJsonObject(compactPath));
153
+ const legacyPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
154
+ if (node_fs.existsSync(legacyPath)) return adaptLegacyContract(workspaceRoot, legacyPath, readJsonObject(legacyPath));
155
+ throw new Error(`Missing UltraModern config. Expected ${ULTRAMODERN_CONFIG_PATH} or ${GENERATED_CONTRACT_PATH}.`);
156
+ }
157
+ function workspaceAppsFromToolingConfig(config) {
158
+ return config.topology.apps.map((app)=>{
159
+ if ('shell' === app.kind) return {
160
+ ...shellApp,
161
+ directory: app.path,
162
+ packageSuffix: app.packageSuffix ?? shellApp.packageSuffix,
163
+ displayName: app.displayName ?? shellApp.displayName,
164
+ port: app.port ?? shellApp.port,
165
+ portEnv: app.portEnv ?? shellApp.portEnv,
166
+ mfName: app.moduleFederation?.name ?? shellApp.mfName,
167
+ verticalRefs: app.moduleFederation?.verticalRefs ?? []
168
+ };
169
+ const domain = app.domain ?? app.id;
170
+ const packageSuffix = app.packageSuffix ?? domain;
171
+ const exposes = Object.fromEntries((app.moduleFederation?.exposes ?? []).map((expose)=>[
172
+ expose,
173
+ './Route' === expose ? './src/federation-entry.tsx' : './Widget' === expose ? `./src/components/${domain}-widget.tsx` : ''
174
+ ]));
175
+ return {
176
+ id: app.id,
177
+ directory: app.path,
178
+ packageSuffix,
179
+ displayName: app.displayName ?? `${domain} Vertical`,
180
+ kind: 'vertical',
181
+ domain,
182
+ portEnv: app.portEnv ?? `VERTICAL_${domain.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}_PORT`,
183
+ port: app.port ?? 0,
184
+ mfName: app.moduleFederation?.name ?? app.id,
185
+ exposes,
186
+ ...app.moduleFederation?.verticalRefs ? {
187
+ verticalRefs: app.moduleFederation.verticalRefs
188
+ } : {},
189
+ ...app.effectApi ? {
190
+ effectApi: app.effectApi
191
+ } : {},
192
+ ownership: createNeutralOwnership(app.id)
193
+ };
194
+ });
195
+ }
196
+ export { readUltramodernConfig, workspaceAppsFromToolingConfig };
@@ -2,12 +2,12 @@ import node_fs from "node:fs";
2
2
  import node_os from "node:os";
3
3
  import node_path from "node:path";
4
4
  import { WORKSPACE_PACKAGE_VERSION } from "../ultramodern-package-source.js";
5
+ import { readUltramodernConfig } from "../ultramodern-tooling/config.js";
5
6
  import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "./app-files.js";
6
- import { createGeneratedContract } from "./contracts.js";
7
7
  import { createShellPage, createShellRemoteComponents } from "./demo-components.js";
8
- import { GENERATED_CONTRACT_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
8
+ import { GENERATED_CONTRACT_PATH, ULTRAMODERN_CONFIG_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
9
9
  import { createShellEffectClient, effectApiTopologyMetadata } from "./effect-api.js";
10
- import { readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
10
+ import { formatGeneratedWorkspaceFiles, readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
11
11
  import { createFileSnapshot, createGenerationResult, diffFileSnapshots } from "./generation-result.js";
12
12
  import { createAppPublicLocaleMessages } from "./locales.js";
13
13
  import { createShellModuleFederationConfig } from "./module-federation.js";
@@ -19,7 +19,7 @@ import { createCloudflareDeployContract } from "./policy.js";
19
19
  import { createPublicWebAppArtifacts, rewriteWorkspaceAssetsForApp } from "./public-surface.js";
20
20
  import { isRecord } from "./types.js";
21
21
  import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
22
- import { writeApp } from "./write-workspace.js";
22
+ import { createCompactUltramodernConfig, writeApp } from "./write-workspace.js";
23
23
  const FIRST_VERTICAL_PORT = 4101;
24
24
  const TOPOLOGY_PATH = 'topology/reference-topology.json';
25
25
  const OWNERSHIP_PATH = 'topology/ownership.json';
@@ -32,7 +32,12 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
32
32
  modernVersion,
33
33
  packageSource
34
34
  });
35
- const metadataPath = node_path.join(workspaceRoot, '.modernjs/ultramodern-package-source.json');
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
+ const metadataPath = node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
36
41
  if (!node_fs.existsSync(metadataPath)) return resolvePackageSource({
37
42
  targetDir: workspaceRoot,
38
43
  packageName: node_path.basename(workspaceRoot),
@@ -55,6 +60,8 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
55
60
  };
56
61
  }
57
62
  function existingTailwindEnabled(workspaceRoot) {
63
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
64
+ if (node_fs.existsSync(compactPath)) return readUltramodernConfig(workspaceRoot).features.tailwind;
58
65
  const contractPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
59
66
  if (!node_fs.existsSync(contractPath)) return true;
60
67
  const contract = readJsonFile(contractPath);
@@ -62,6 +69,10 @@ function existingTailwindEnabled(workspaceRoot) {
62
69
  const shell = apps.find((app)=>isRecord(app) && app.id === shellApp.id);
63
70
  return shell?.styling && isRecord(shell.styling) ? false !== shell.styling.tailwind : true;
64
71
  }
72
+ function existingBridgeConfig(workspaceRoot) {
73
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
74
+ return node_fs.existsSync(compactPath) ? readUltramodernConfig(workspaceRoot).bridge : void 0;
75
+ }
65
76
  function assertValidVerticalName(name) {
66
77
  const normalized = toKebabCase(name);
67
78
  if (!normalized || normalized !== name) throw new Error(`Invalid Vertical name "${name}". Use lowercase kebab-case.`);
@@ -74,17 +85,17 @@ function nextAvailablePort(ports) {
74
85
  function assertCanCreate(workspaceRoot, relativePath) {
75
86
  if (node_fs.existsSync(node_path.join(workspaceRoot, relativePath))) throw new Error(`Refusing to overwrite existing path: ${relativePath}`);
76
87
  }
77
- function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes) {
88
+ function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes, bridge) {
78
89
  const packagePath = node_path.join(workspaceRoot, 'package.json');
79
90
  const rootPackage = readJsonFile(packagePath);
80
- const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes);
91
+ const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes, bridge);
81
92
  rootPackage.scripts = generatedRootPackage.scripts;
82
93
  writeJsonFile(packagePath, rootPackage);
83
94
  }
84
- function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes) {
95
+ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes, bridge) {
85
96
  const shellHost = createShellHost(remotes);
86
97
  const publicWeb = createPublicWebAppArtifacts(shellHost);
87
- writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes));
98
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes, bridge));
88
99
  writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.json`), createAppTsConfig(shellHost, remotes));
89
100
  writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.mf-types.json`), createAppMfTypesTsConfig(shellHost));
90
101
  writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(shellHost, remotes));
@@ -203,8 +214,7 @@ function prepareAddUltramodernVertical(options) {
203
214
  const topology = readRequiredJsonObject(topologyPath);
204
215
  const ownership = readRequiredJsonObject(ownershipPath);
205
216
  const overlay = readRequiredJsonObject(overlayPath);
206
- readRequiredJsonObject(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH));
207
- readRequiredJsonObject(node_path.join(options.workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
217
+ readRequiredWorkspaceConfig(options.workspaceRoot);
208
218
  assertOptionalJsonObject(topology.shell, 'topology.shell', topologyPath);
209
219
  assertOptionalJsonArray(topology.verticals, 'topology.verticals', topologyPath);
210
220
  assertOptionalJsonArray(ownership.owners, 'ownership.owners', ownershipPath);
@@ -215,6 +225,7 @@ function prepareAddUltramodernVertical(options) {
215
225
  const scope = toPackageScope(String(rootPackage.name ?? node_path.basename(options.workspaceRoot)));
216
226
  const packageSource = existingPackageSource(options.workspaceRoot, options.modernVersion, options.packageSource);
217
227
  const enableTailwind = options.enableTailwind ?? existingTailwindEnabled(options.workspaceRoot);
228
+ const bridge = existingBridgeConfig(options.workspaceRoot);
218
229
  const existingVerticals = verticalsFromTopology(topology, overlay.ports);
219
230
  const port = nextAvailablePort(overlay.ports);
220
231
  const vertical = createVerticalDescriptor(name, port);
@@ -242,6 +253,7 @@ function prepareAddUltramodernVertical(options) {
242
253
  overlay,
243
254
  packageSource,
244
255
  enableTailwind,
256
+ bridge,
245
257
  vertical,
246
258
  updatedVerticals
247
259
  };
@@ -252,6 +264,12 @@ function readRequiredJsonObject(filePath) {
252
264
  if (!isRecord(value)) throw new Error(`UltraModern workspace file must contain a JSON object: ${filePath}`);
253
265
  return value;
254
266
  }
267
+ function readRequiredWorkspaceConfig(workspaceRoot) {
268
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
269
+ if (node_fs.existsSync(compactPath)) return void readRequiredJsonObject(compactPath);
270
+ readRequiredJsonObject(node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH));
271
+ readRequiredJsonObject(node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
272
+ }
255
273
  function assertOptionalJsonObject(value, label, filePath) {
256
274
  if (void 0 !== value && !isRecord(value)) throw new Error(`${label} in ${filePath} must be a JSON object`);
257
275
  }
@@ -356,7 +374,7 @@ function createVerticalPlan(preflight, result) {
356
374
  shellDependencyChanges: createShellDependencyChanges(scope, vertical),
357
375
  generatedContractChanges: [
358
376
  {
359
- path: GENERATED_CONTRACT_PATH,
377
+ path: ULTRAMODERN_CONFIG_PATH,
360
378
  addedAppIds: [
361
379
  vertical.id
362
380
  ],
@@ -443,9 +461,9 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
443
461
  description: 'Keep shell Module Federation DTS compilation scoped'
444
462
  },
445
463
  {
446
- path: GENERATED_CONTRACT_PATH,
447
- pointer: '/apps',
448
- description: `Regenerate contract with ${vertical.id}`
464
+ path: ULTRAMODERN_CONFIG_PATH,
465
+ pointer: '/topology/apps',
466
+ description: `Regenerate compact config with ${vertical.id}`
449
467
  }
450
468
  ];
451
469
  }
@@ -469,8 +487,8 @@ function createShellDependencyChanges(scope, vertical) {
469
487
  }
470
488
  function addUltramodernVertical(options) {
471
489
  const beforeFiles = createFileSnapshot(options.workspaceRoot);
472
- const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
473
- writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind);
490
+ const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, bridge, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
491
+ writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind, updatedVerticals, bridge);
474
492
  topology.shell ??= {};
475
493
  topology.shell.verticalRefs ??= [];
476
494
  topology.shell.verticalRefs.push(vertical.id);
@@ -493,18 +511,18 @@ function addUltramodernVertical(options) {
493
511
  writeJsonFile(topologyPath, topology);
494
512
  writeJsonFile(ownershipPath, ownership);
495
513
  writeJsonFile(overlayPath, overlay);
496
- writeJsonFile(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH), createGeneratedContract(scope, [
514
+ writeJsonFile(node_path.join(options.workspaceRoot, ULTRAMODERN_CONFIG_PATH), createCompactUltramodernConfig(scope, options.modernVersion, packageSource, [
497
515
  {
498
516
  ...shellApp,
499
517
  verticalRefs: updatedVerticals.map((vertical)=>vertical.id)
500
518
  },
501
519
  ...updatedVerticals
502
- ], enableTailwind));
503
- rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals);
520
+ ], enableTailwind, bridge));
521
+ rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals, bridge);
504
522
  writeGeneratedWorkspaceScripts(options.workspaceRoot, scope, enableTailwind, updatedVerticals);
505
523
  addShellZephyrDependency(options.workspaceRoot, scope, vertical);
506
524
  addShellWorkspaceDependency(options.workspaceRoot, scope, vertical);
507
- updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals);
525
+ updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals, bridge);
508
526
  writeJsonFile(node_path.join(options.workspaceRoot, 'tsconfig.json'), createRootTsConfig([
509
527
  {
510
528
  ...shellApp,
@@ -512,9 +530,9 @@ function addUltramodernVertical(options) {
512
530
  },
513
531
  ...updatedVerticals
514
532
  ]));
515
- const afterFiles = createFileSnapshot(options.workspaceRoot);
516
- const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
517
- const result = createGenerationResult({
533
+ const preliminaryAfterFiles = createFileSnapshot(options.workspaceRoot);
534
+ const preliminaryDiff = diffFileSnapshots(beforeFiles, preliminaryAfterFiles);
535
+ const preliminaryResult = createGenerationResult({
518
536
  operation: 'vertical',
519
537
  workspaceRoot: options.workspaceRoot,
520
538
  packageScope: scope,
@@ -522,14 +540,32 @@ function addUltramodernVertical(options) {
522
540
  createdApps: [
523
541
  vertical
524
542
  ],
525
- createdPaths,
526
- rewrittenPaths
543
+ createdPaths: preliminaryDiff.createdPaths,
544
+ rewrittenPaths: preliminaryDiff.rewrittenPaths
527
545
  });
528
546
  runCodeSmithOverlays({
529
547
  workspaceRoot: options.workspaceRoot,
530
548
  overlays: options.overlays,
531
- result
549
+ result: preliminaryResult
550
+ });
551
+ const afterOverlaysFiles = createFileSnapshot(options.workspaceRoot);
552
+ const changedPaths = diffFileSnapshots(beforeFiles, afterOverlaysFiles);
553
+ formatGeneratedWorkspaceFiles(options.workspaceRoot, [
554
+ ...changedPaths.createdPaths,
555
+ ...changedPaths.rewrittenPaths
556
+ ]);
557
+ const afterFiles = createFileSnapshot(options.workspaceRoot);
558
+ const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
559
+ return createGenerationResult({
560
+ operation: 'vertical',
561
+ workspaceRoot: options.workspaceRoot,
562
+ packageScope: scope,
563
+ packageSource,
564
+ createdApps: [
565
+ vertical
566
+ ],
567
+ createdPaths,
568
+ rewrittenPaths
532
569
  });
533
- return result;
534
570
  }
535
- export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };
571
+ export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingBridgeConfig, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };