@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,197 @@
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 { GENERATED_CONTRACT_PATH, ULTRAMODERN_CONFIG_PATH, createNeutralOwnership, shellApp } from "../ultramodern-workspace/descriptors.js";
6
+ import { toKebabCase } from "../ultramodern-workspace/naming.js";
7
+ const PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
8
+ const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
9
+ function readJsonObject(filePath) {
10
+ const value = JSON.parse(node_fs.readFileSync(filePath, 'utf-8'));
11
+ if (null === value || 'object' != typeof value || Array.isArray(value)) throw new Error(`UltraModern config must contain a JSON object: ${filePath}`);
12
+ return value;
13
+ }
14
+ function readOptionalJsonObject(filePath) {
15
+ return node_fs.existsSync(filePath) ? readJsonObject(filePath) : {};
16
+ }
17
+ function packageScopeFromRoot(workspaceRoot) {
18
+ const rootPackage = readOptionalJsonObject(node_path.join(workspaceRoot, 'package.json'));
19
+ return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : node_path.basename(workspaceRoot);
20
+ }
21
+ function packageSourceFromMetadata(workspaceRoot) {
22
+ const metadataPath = node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
23
+ if (!node_fs.existsSync(metadataPath)) return;
24
+ const metadata = readJsonObject(metadataPath);
25
+ const aliases = metadata.modernPackages?.aliases ?? {};
26
+ const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
27
+ const firstPackage = Object.keys(aliases)[0];
28
+ const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
29
+ const unscopedName = firstPackage?.split('/').at(-1) ?? '';
30
+ const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
31
+ const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
32
+ return {
33
+ strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
34
+ modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : 'workspace:*',
35
+ registry: 'string' == typeof metadata.modernPackages?.registry ? metadata.modernPackages.registry : void 0,
36
+ aliasScope,
37
+ aliasPackageNamePrefix
38
+ };
39
+ }
40
+ function readOverlayPorts(workspaceRoot) {
41
+ const overlayPath = node_path.join(workspaceRoot, DEVELOPMENT_OVERLAY_PATH);
42
+ if (!node_fs.existsSync(overlayPath)) return {};
43
+ const overlay = readJsonObject(overlayPath);
44
+ const ports = overlay.ports;
45
+ if (null === ports || 'object' != typeof ports || Array.isArray(ports)) return {};
46
+ return Object.fromEntries(Object.entries(ports).filter((entry)=>'number' == typeof entry[1]));
47
+ }
48
+ function normalizeCompactConfig(workspaceRoot, sourcePath, config) {
49
+ const packageSource = config.packageSource && 'object' == typeof config.packageSource ? {
50
+ strategy: 'install' === config.packageSource.strategy ? 'install' : 'workspace',
51
+ modernPackageVersion: 'string' == typeof config.packageSource.modernPackageVersion ? config.packageSource.modernPackageVersion : 'workspace:*',
52
+ registry: 'string' == typeof config.packageSource.registry ? config.packageSource.registry : void 0,
53
+ aliasScope: 'string' == typeof config.packageSource.aliasScope ? config.packageSource.aliasScope : void 0,
54
+ aliasPackageNamePrefix: 'string' == typeof config.packageSource.aliasPackageNamePrefix ? config.packageSource.aliasPackageNamePrefix : void 0
55
+ } : packageSourceFromMetadata(workspaceRoot);
56
+ return {
57
+ schemaVersion: 'number' == typeof config.schemaVersion ? config.schemaVersion : 1,
58
+ profile: 'string' == typeof config.profile ? config.profile : void 0,
59
+ source: 'compact',
60
+ sourcePath,
61
+ workspace: {
62
+ packageScope: 'string' == typeof config.workspace?.packageScope ? config.workspace.packageScope : packageScopeFromRoot(workspaceRoot)
63
+ },
64
+ packageSource,
65
+ features: {
66
+ tailwind: config.features?.tailwind !== false
67
+ },
68
+ bridge: normalizeUltramodernBridgeConfig(config.bridge),
69
+ topology: {
70
+ apps: Array.isArray(config.topology?.apps) ? config.topology.apps.map((app)=>({
71
+ id: String(app.id),
72
+ kind: 'vertical' === app.kind ? 'vertical' : 'shell',
73
+ path: 'string' == typeof app.path ? app.path : '.',
74
+ package: 'string' == typeof app.package ? app.package : void 0,
75
+ packageSuffix: 'string' == typeof app.packageSuffix ? app.packageSuffix : void 0,
76
+ displayName: 'string' == typeof app.displayName ? app.displayName : void 0,
77
+ domain: 'string' == typeof app.domain ? app.domain : void 0,
78
+ port: 'number' == typeof app.port ? app.port : void 0,
79
+ portEnv: 'string' == typeof app.portEnv ? app.portEnv : void 0,
80
+ moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
81
+ role: 'remote' === app.moduleFederation.role ? 'remote' : 'host',
82
+ name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
83
+ exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
84
+ verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
85
+ hostOnly: true === app.moduleFederation.hostOnly,
86
+ noExposes: true === app.moduleFederation.noExposes
87
+ } : void 0,
88
+ effectApi: app.effectApi && 'object' == typeof app.effectApi ? {
89
+ stem: 'string' == typeof app.effectApi.stem ? app.effectApi.stem : String(app.id),
90
+ prefix: 'string' == typeof app.effectApi.prefix ? app.effectApi.prefix : `/${String(app.id)}-api`,
91
+ consumedBy: Array.isArray(app.effectApi.consumedBy) ? app.effectApi.consumedBy.filter((consumer)=>'string' == typeof consumer) : [
92
+ shellApp.id,
93
+ String(app.id)
94
+ ]
95
+ } : void 0
96
+ })) : []
97
+ }
98
+ };
99
+ }
100
+ function adaptLegacyContract(workspaceRoot, sourcePath, contract) {
101
+ const ports = readOverlayPorts(workspaceRoot);
102
+ const apps = Array.isArray(contract.apps) ? contract.apps : [];
103
+ const shell = apps.find((app)=>app?.id === shellApp.id);
104
+ return {
105
+ schemaVersion: 'number' == typeof contract.schemaVersion ? contract.schemaVersion : 1,
106
+ profile: 'string' == typeof contract.profile ? contract.profile : void 0,
107
+ source: 'legacy',
108
+ sourcePath,
109
+ workspace: {
110
+ packageScope: packageScopeFromRoot(workspaceRoot)
111
+ },
112
+ packageSource: packageSourceFromMetadata(workspaceRoot),
113
+ features: {
114
+ tailwind: shell?.styling?.tailwind !== false
115
+ },
116
+ topology: {
117
+ apps: apps.map((app)=>{
118
+ const id = String(app.id);
119
+ const appPath = 'string' == typeof app.path ? app.path : id === shellApp.id ? shellApp.directory : `verticals/${toKebabCase(id)}`;
120
+ const domain = 'string' == typeof app.i18n?.namespace && 'shell' !== app.i18n.namespace ? app.i18n.namespace : appPath.split('/').at(-1);
121
+ return {
122
+ id,
123
+ kind: 'vertical' === app.kind ? 'vertical' : 'shell',
124
+ path: appPath,
125
+ package: 'string' == typeof app.package ? app.package : void 0,
126
+ packageSuffix: 'string' == typeof app.package ? app.package.split('/').at(-1) : appPath.split('/').at(-1),
127
+ displayName: id === shellApp.id ? shellApp.displayName : void 0,
128
+ domain,
129
+ port: ports[id],
130
+ moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
131
+ role: 'vertical' === app.kind ? 'remote' : 'host',
132
+ name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
133
+ exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
134
+ verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
135
+ hostOnly: 'vertical' !== app.kind
136
+ } : void 0,
137
+ effectApi: app.effect && 'object' == typeof app.effect ? {
138
+ stem: 'string' == typeof app.effect.prefix ? app.effect.prefix.split('/').filter(Boolean).at(-1) ?? domain ?? id : domain ?? id,
139
+ prefix: 'string' == typeof app.effect.prefix ? app.effect.prefix : `/${domain ?? id}-api`,
140
+ consumedBy: [
141
+ shellApp.id,
142
+ id
143
+ ]
144
+ } : void 0
145
+ };
146
+ })
147
+ },
148
+ legacyContract: contract
149
+ };
150
+ }
151
+ function readUltramodernConfig(workspaceRoot = process.cwd()) {
152
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
153
+ if (node_fs.existsSync(compactPath)) return normalizeCompactConfig(workspaceRoot, compactPath, readJsonObject(compactPath));
154
+ const legacyPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
155
+ if (node_fs.existsSync(legacyPath)) return adaptLegacyContract(workspaceRoot, legacyPath, readJsonObject(legacyPath));
156
+ throw new Error(`Missing UltraModern config. Expected ${ULTRAMODERN_CONFIG_PATH} or ${GENERATED_CONTRACT_PATH}.`);
157
+ }
158
+ function workspaceAppsFromToolingConfig(config) {
159
+ return config.topology.apps.map((app)=>{
160
+ if ('shell' === app.kind) return {
161
+ ...shellApp,
162
+ directory: app.path,
163
+ packageSuffix: app.packageSuffix ?? shellApp.packageSuffix,
164
+ displayName: app.displayName ?? shellApp.displayName,
165
+ port: app.port ?? shellApp.port,
166
+ portEnv: app.portEnv ?? shellApp.portEnv,
167
+ mfName: app.moduleFederation?.name ?? shellApp.mfName,
168
+ verticalRefs: app.moduleFederation?.verticalRefs ?? []
169
+ };
170
+ const domain = app.domain ?? app.id;
171
+ const packageSuffix = app.packageSuffix ?? domain;
172
+ const exposes = Object.fromEntries((app.moduleFederation?.exposes ?? []).map((expose)=>[
173
+ expose,
174
+ './Route' === expose ? './src/federation-entry.tsx' : './Widget' === expose ? `./src/components/${domain}-widget.tsx` : ''
175
+ ]));
176
+ return {
177
+ id: app.id,
178
+ directory: app.path,
179
+ packageSuffix,
180
+ displayName: app.displayName ?? `${domain} Vertical`,
181
+ kind: 'vertical',
182
+ domain,
183
+ portEnv: app.portEnv ?? `VERTICAL_${domain.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}_PORT`,
184
+ port: app.port ?? 0,
185
+ mfName: app.moduleFederation?.name ?? app.id,
186
+ exposes,
187
+ ...app.moduleFederation?.verticalRefs ? {
188
+ verticalRefs: app.moduleFederation.verticalRefs
189
+ } : {},
190
+ ...app.effectApi ? {
191
+ effectApi: app.effectApi
192
+ } : {},
193
+ ownership: createNeutralOwnership(app.id)
194
+ };
195
+ });
196
+ }
197
+ 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";
6
7
  import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "./app-files.js";
7
- import { createGeneratedContract } from "./contracts.js";
8
8
  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";
9
+ import { GENERATED_CONTRACT_PATH, ULTRAMODERN_CONFIG_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createRemoteManifestEnv, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
10
10
  import { createShellEffectClient, effectApiTopologyMetadata } from "./effect-api.js";
11
- import { readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.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,7 +20,7 @@ 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';
@@ -33,7 +33,12 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
33
33
  modernVersion,
34
34
  packageSource
35
35
  });
36
- const metadataPath = node_path.join(workspaceRoot, '.modernjs/ultramodern-package-source.json');
36
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
37
+ if (node_fs.existsSync(compactPath)) {
38
+ const compactConfig = readUltramodernConfig(workspaceRoot);
39
+ if (compactConfig.packageSource) return compactConfig.packageSource;
40
+ }
41
+ const metadataPath = node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
37
42
  if (!node_fs.existsSync(metadataPath)) return resolvePackageSource({
38
43
  targetDir: workspaceRoot,
39
44
  packageName: node_path.basename(workspaceRoot),
@@ -56,6 +61,8 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
56
61
  };
57
62
  }
58
63
  function existingTailwindEnabled(workspaceRoot) {
64
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
65
+ if (node_fs.existsSync(compactPath)) return readUltramodernConfig(workspaceRoot).features.tailwind;
59
66
  const contractPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
60
67
  if (!node_fs.existsSync(contractPath)) return true;
61
68
  const contract = readJsonFile(contractPath);
@@ -63,6 +70,10 @@ function existingTailwindEnabled(workspaceRoot) {
63
70
  const shell = apps.find((app)=>isRecord(app) && app.id === shellApp.id);
64
71
  return shell?.styling && isRecord(shell.styling) ? false !== shell.styling.tailwind : true;
65
72
  }
73
+ function existingBridgeConfig(workspaceRoot) {
74
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
75
+ return node_fs.existsSync(compactPath) ? readUltramodernConfig(workspaceRoot).bridge : void 0;
76
+ }
66
77
  function assertValidVerticalName(name) {
67
78
  const normalized = toKebabCase(name);
68
79
  if (!normalized || normalized !== name) throw new Error(`Invalid Vertical name "${name}". Use lowercase kebab-case.`);
@@ -75,17 +86,17 @@ function nextAvailablePort(ports) {
75
86
  function assertCanCreate(workspaceRoot, relativePath) {
76
87
  if (node_fs.existsSync(node_path.join(workspaceRoot, relativePath))) throw new Error(`Refusing to overwrite existing path: ${relativePath}`);
77
88
  }
78
- function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes) {
89
+ function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes, bridge) {
79
90
  const packagePath = node_path.join(workspaceRoot, 'package.json');
80
91
  const rootPackage = readJsonFile(packagePath);
81
- const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes);
92
+ const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes, bridge);
82
93
  rootPackage.scripts = generatedRootPackage.scripts;
83
94
  writeJsonFile(packagePath, rootPackage);
84
95
  }
85
- function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes) {
96
+ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes, bridge) {
86
97
  const shellHost = createShellHost(remotes);
87
98
  const publicWeb = createPublicWebAppArtifacts(shellHost);
88
- writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes));
99
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes, bridge));
89
100
  writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.json`), createAppTsConfig(shellHost, remotes));
90
101
  writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/tsconfig.mf-types.json`), createAppMfTypesTsConfig(shellHost));
91
102
  writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(shellHost, remotes));
@@ -204,8 +215,7 @@ function prepareAddUltramodernVertical(options) {
204
215
  const topology = readRequiredJsonObject(topologyPath);
205
216
  const ownership = readRequiredJsonObject(ownershipPath);
206
217
  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));
218
+ readRequiredWorkspaceConfig(options.workspaceRoot);
209
219
  assertOptionalJsonObject(topology.shell, 'topology.shell', topologyPath);
210
220
  assertOptionalJsonArray(topology.verticals, 'topology.verticals', topologyPath);
211
221
  assertOptionalJsonArray(ownership.owners, 'ownership.owners', ownershipPath);
@@ -216,6 +226,7 @@ function prepareAddUltramodernVertical(options) {
216
226
  const scope = toPackageScope(String(rootPackage.name ?? node_path.basename(options.workspaceRoot)));
217
227
  const packageSource = existingPackageSource(options.workspaceRoot, options.modernVersion, options.packageSource);
218
228
  const enableTailwind = options.enableTailwind ?? existingTailwindEnabled(options.workspaceRoot);
229
+ const bridge = existingBridgeConfig(options.workspaceRoot);
219
230
  const existingVerticals = verticalsFromTopology(topology, overlay.ports);
220
231
  const port = nextAvailablePort(overlay.ports);
221
232
  const vertical = createVerticalDescriptor(name, port);
@@ -243,6 +254,7 @@ function prepareAddUltramodernVertical(options) {
243
254
  overlay,
244
255
  packageSource,
245
256
  enableTailwind,
257
+ bridge,
246
258
  vertical,
247
259
  updatedVerticals
248
260
  };
@@ -253,6 +265,12 @@ function readRequiredJsonObject(filePath) {
253
265
  if (!isRecord(value)) throw new Error(`UltraModern workspace file must contain a JSON object: ${filePath}`);
254
266
  return value;
255
267
  }
268
+ function readRequiredWorkspaceConfig(workspaceRoot) {
269
+ const compactPath = node_path.join(workspaceRoot, ULTRAMODERN_CONFIG_PATH);
270
+ if (node_fs.existsSync(compactPath)) return void readRequiredJsonObject(compactPath);
271
+ readRequiredJsonObject(node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH));
272
+ readRequiredJsonObject(node_path.join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
273
+ }
256
274
  function assertOptionalJsonObject(value, label, filePath) {
257
275
  if (void 0 !== value && !isRecord(value)) throw new Error(`${label} in ${filePath} must be a JSON object`);
258
276
  }
@@ -357,7 +375,7 @@ function createVerticalPlan(preflight, result) {
357
375
  shellDependencyChanges: createShellDependencyChanges(scope, vertical),
358
376
  generatedContractChanges: [
359
377
  {
360
- path: GENERATED_CONTRACT_PATH,
378
+ path: ULTRAMODERN_CONFIG_PATH,
361
379
  addedAppIds: [
362
380
  vertical.id
363
381
  ],
@@ -444,9 +462,9 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
444
462
  description: 'Keep shell Module Federation DTS compilation scoped'
445
463
  },
446
464
  {
447
- path: GENERATED_CONTRACT_PATH,
448
- pointer: '/apps',
449
- description: `Regenerate contract with ${vertical.id}`
465
+ path: ULTRAMODERN_CONFIG_PATH,
466
+ pointer: '/topology/apps',
467
+ description: `Regenerate compact config with ${vertical.id}`
450
468
  }
451
469
  ];
452
470
  }
@@ -470,8 +488,8 @@ function createShellDependencyChanges(scope, vertical) {
470
488
  }
471
489
  function addUltramodernVertical(options) {
472
490
  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);
491
+ const { scope, topologyPath, ownershipPath, overlayPath, topology, ownership, overlay, packageSource, enableTailwind, bridge, vertical, updatedVerticals } = prepareAddUltramodernVertical(options);
492
+ writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind, updatedVerticals, bridge);
475
493
  topology.shell ??= {};
476
494
  topology.shell.verticalRefs ??= [];
477
495
  topology.shell.verticalRefs.push(vertical.id);
@@ -494,18 +512,18 @@ function addUltramodernVertical(options) {
494
512
  writeJsonFile(topologyPath, topology);
495
513
  writeJsonFile(ownershipPath, ownership);
496
514
  writeJsonFile(overlayPath, overlay);
497
- writeJsonFile(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH), createGeneratedContract(scope, [
515
+ writeJsonFile(node_path.join(options.workspaceRoot, ULTRAMODERN_CONFIG_PATH), createCompactUltramodernConfig(scope, options.modernVersion, packageSource, [
498
516
  {
499
517
  ...shellApp,
500
518
  verticalRefs: updatedVerticals.map((vertical)=>vertical.id)
501
519
  },
502
520
  ...updatedVerticals
503
- ], enableTailwind));
504
- rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals);
521
+ ], enableTailwind, bridge));
522
+ rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals, bridge);
505
523
  writeGeneratedWorkspaceScripts(options.workspaceRoot, scope, enableTailwind, updatedVerticals);
506
524
  addShellZephyrDependency(options.workspaceRoot, scope, vertical);
507
525
  addShellWorkspaceDependency(options.workspaceRoot, scope, vertical);
508
- updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals);
526
+ updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals, bridge);
509
527
  writeJsonFile(node_path.join(options.workspaceRoot, 'tsconfig.json'), createRootTsConfig([
510
528
  {
511
529
  ...shellApp,
@@ -513,9 +531,9 @@ function addUltramodernVertical(options) {
513
531
  },
514
532
  ...updatedVerticals
515
533
  ]));
516
- const afterFiles = createFileSnapshot(options.workspaceRoot);
517
- const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
518
- const result = createGenerationResult({
534
+ const preliminaryAfterFiles = createFileSnapshot(options.workspaceRoot);
535
+ const preliminaryDiff = diffFileSnapshots(beforeFiles, preliminaryAfterFiles);
536
+ const preliminaryResult = createGenerationResult({
519
537
  operation: 'vertical',
520
538
  workspaceRoot: options.workspaceRoot,
521
539
  packageScope: scope,
@@ -523,14 +541,32 @@ function addUltramodernVertical(options) {
523
541
  createdApps: [
524
542
  vertical
525
543
  ],
526
- createdPaths,
527
- rewrittenPaths
544
+ createdPaths: preliminaryDiff.createdPaths,
545
+ rewrittenPaths: preliminaryDiff.rewrittenPaths
528
546
  });
529
547
  runCodeSmithOverlays({
530
548
  workspaceRoot: options.workspaceRoot,
531
549
  overlays: options.overlays,
532
- result
550
+ result: preliminaryResult
551
+ });
552
+ const afterOverlaysFiles = createFileSnapshot(options.workspaceRoot);
553
+ const changedPaths = diffFileSnapshots(beforeFiles, afterOverlaysFiles);
554
+ formatGeneratedWorkspaceFiles(options.workspaceRoot, [
555
+ ...changedPaths.createdPaths,
556
+ ...changedPaths.rewrittenPaths
557
+ ]);
558
+ const afterFiles = createFileSnapshot(options.workspaceRoot);
559
+ const { createdPaths, rewrittenPaths } = diffFileSnapshots(beforeFiles, afterFiles);
560
+ return createGenerationResult({
561
+ operation: 'vertical',
562
+ workspaceRoot: options.workspaceRoot,
563
+ packageScope: scope,
564
+ packageSource,
565
+ createdApps: [
566
+ vertical
567
+ ],
568
+ createdPaths,
569
+ rewrittenPaths
533
570
  });
534
- return result;
535
571
  }
536
- export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };
572
+ export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingBridgeConfig, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, planUltramodernVertical, prepareAddUltramodernVertical, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };