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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/cjs/index.cjs +1 -1
  2. package/dist/cjs/locale/en.cjs +2 -2
  3. package/dist/cjs/locale/zh.cjs +2 -2
  4. package/dist/cjs/ultramodern-tooling/config.cjs +9 -91
  5. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +13 -40
  6. package/dist/cjs/ultramodern-workspace/contracts.cjs +2 -0
  7. package/dist/cjs/ultramodern-workspace/demo-components.cjs +12 -12
  8. package/dist/cjs/ultramodern-workspace/descriptors.cjs +0 -4
  9. package/dist/cjs/ultramodern-workspace/effect-api.cjs +74 -75
  10. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +1 -2
  11. package/dist/cjs/ultramodern-workspace/module-federation.cjs +3 -2
  12. package/dist/cjs/ultramodern-workspace/package-json.cjs +6 -5
  13. package/dist/cjs/ultramodern-workspace/policy.cjs +1 -1
  14. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +7 -0
  15. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +4 -4
  16. package/dist/esm/index.js +1 -1
  17. package/dist/esm/locale/en.js +2 -2
  18. package/dist/esm/locale/zh.js +2 -2
  19. package/dist/esm/ultramodern-tooling/config.js +10 -92
  20. package/dist/esm/ultramodern-workspace/add-vertical.js +14 -41
  21. package/dist/esm/ultramodern-workspace/contracts.js +2 -0
  22. package/dist/esm/ultramodern-workspace/demo-components.js +12 -12
  23. package/dist/esm/ultramodern-workspace/descriptors.js +1 -2
  24. package/dist/esm/ultramodern-workspace/effect-api.js +74 -75
  25. package/dist/esm/ultramodern-workspace/mf-validation.js +1 -2
  26. package/dist/esm/ultramodern-workspace/module-federation.js +3 -2
  27. package/dist/esm/ultramodern-workspace/package-json.js +6 -5
  28. package/dist/esm/ultramodern-workspace/policy.js +1 -1
  29. package/dist/esm/ultramodern-workspace/workspace-scripts.js +5 -1
  30. package/dist/esm/ultramodern-workspace/write-workspace.js +4 -4
  31. package/dist/esm-node/index.js +1 -1
  32. package/dist/esm-node/locale/en.js +2 -2
  33. package/dist/esm-node/locale/zh.js +2 -2
  34. package/dist/esm-node/ultramodern-tooling/config.js +10 -92
  35. package/dist/esm-node/ultramodern-workspace/add-vertical.js +14 -41
  36. package/dist/esm-node/ultramodern-workspace/contracts.js +2 -0
  37. package/dist/esm-node/ultramodern-workspace/demo-components.js +12 -12
  38. package/dist/esm-node/ultramodern-workspace/descriptors.js +1 -2
  39. package/dist/esm-node/ultramodern-workspace/effect-api.js +74 -75
  40. package/dist/esm-node/ultramodern-workspace/mf-validation.js +1 -2
  41. package/dist/esm-node/ultramodern-workspace/module-federation.js +3 -2
  42. package/dist/esm-node/ultramodern-workspace/package-json.js +6 -5
  43. package/dist/esm-node/ultramodern-workspace/policy.js +1 -1
  44. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +5 -1
  45. package/dist/esm-node/ultramodern-workspace/write-workspace.js +4 -4
  46. package/dist/types/ultramodern-tooling/config.d.ts +1 -2
  47. package/dist/types/ultramodern-workspace/descriptors.d.ts +0 -1
  48. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +1 -0
  49. package/package.json +3 -3
  50. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +1 -11
  51. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mjs +339 -0
  52. package/templates/workspace-scripts/generate-public-surface-assets.mjs +14 -12
  53. package/templates/workspace-scripts/proof-cloudflare-version.mjs +3 -13
  54. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +3 -3
  55. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +1 -9
  56. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +82 -86
@@ -217,7 +217,7 @@ function detectBffRuntime(args) {
217
217
  process.exit(1);
218
218
  }
219
219
  if (!SUPPORTED_BFF_RUNTIMES.includes(runtime)) {
220
- console.error(`Unsupported BFF runtime "${runtime}". UltraModern workspaces scaffold an Effect BFF for every MicroVertical (supported: ${SUPPORTED_BFF_RUNTIMES.join(', ')}).`);
220
+ console.error(`Unsupported BFF runtime "${runtime}". UltraModern workspaces scaffold a strict Effect API runtime for every MicroVertical (supported: ${SUPPORTED_BFF_RUNTIMES.join(', ')}).`);
221
221
  process.exit(1);
222
222
  }
223
223
  return runtime;
@@ -47,7 +47,7 @@ const EN_LOCALE = {
47
47
  step1: 'cd {projectName}',
48
48
  step2: 'pnpm install',
49
49
  step3: 'pnpm dev',
50
- legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nBRUTAL WARNING: YOU ARE OPTING OUT OF ULTRAMODERN.JS DEFAULTS.\nThe unattended default is the best UltraModern.js configuration:\na structured SuperApp workspace, presetUltramodern, TanStack Router,\nEffect BFF, Tailwind CSS v4, and the BleedingDev package cohort.\nThe original Modern.js setup is a dangerous opt-in path.\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
50
+ legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nBRUTAL WARNING: YOU ARE OPTING OUT OF ULTRAMODERN.JS DEFAULTS.\nThe unattended default is the best UltraModern.js configuration:\na structured SuperApp workspace, presetUltramodern, TanStack Router,\na strict Effect API runtime, Tailwind CSS v4, and the BleedingDev package cohort.\nThe original Modern.js setup is a dangerous opt-in path.\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
51
51
  },
52
52
  help: {
53
53
  title: '🚀 UltraModern.js Project Creator',
@@ -59,7 +59,7 @@ const EN_LOCALE = {
59
59
  optionVersion: ' -v, --version Display version information',
60
60
  optionLang: ' -l, --lang Set the language (en default; zh opt-in)',
61
61
  optionTailwind: ' --no-tailwind Disable default Tailwind CSS v4 workspace styling',
62
- optionBff: ' --bff Keep the default Effect BFF scaffolding (every MicroVertical ships an Effect BFF)',
62
+ optionBff: ' --bff Keep the default strict Effect API runtime (every MicroVertical ships one)',
63
63
  optionBffRuntime: ' --bff-runtime Select the BFF runtime for scaffolded MicroVerticals (supported: effect; default: effect)',
64
64
  optionWorkspace: ' --workspace Use workspace protocol for @modern-js dependencies (for local monorepo testing)',
65
65
  optionUltramodernPackageSource: ' --ultramodern-package-source Select UltraModern package source (workspace or install; BleedingDev defaults to install aliases)',
@@ -47,7 +47,7 @@ const ZH_LOCALE = {
47
47
  step1: 'cd {projectName}',
48
48
  step2: 'pnpm install',
49
49
  step3: 'pnpm dev',
50
- legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n严重警告:你正在退出 ULTRAMODERN.JS 默认配置。\n免交互默认值是最佳 UltraModern.js 配置:\n结构化 SuperApp 工作区、presetUltramodern、TanStack Router、\nEffect BFF、Tailwind CSS v4,以及 BleedingDev 包版本队列。\n原始 Modern.js 初始化是危险的显式选择路径。\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
50
+ legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n严重警告:你正在退出 ULTRAMODERN.JS 默认配置。\n免交互默认值是最佳 UltraModern.js 配置:\n结构化 SuperApp 工作区、presetUltramodern、TanStack Router、\n严格 Effect API 运行时、Tailwind CSS v4,以及 BleedingDev 包版本队列。\n原始 Modern.js 初始化是危险的显式选择路径。\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
51
51
  },
52
52
  help: {
53
53
  title: '🚀 UltraModern.js 项目创建工具',
@@ -59,7 +59,7 @@ const ZH_LOCALE = {
59
59
  optionVersion: ' -v, --version 显示版本信息',
60
60
  optionLang: ' -l, --lang 设置语言 (默认 en;zh 需显式选择)',
61
61
  optionTailwind: ' --no-tailwind 禁用默认 Tailwind CSS v4 工作区样式',
62
- optionBff: ' --bff 保留默认的 Effect BFF 脚手架(每个 MicroVertical 自带 Effect BFF)',
62
+ optionBff: ' --bff 保留默认的严格 Effect API 运行时(每个 MicroVertical 自带一个)',
63
63
  optionBffRuntime: ' --bff-runtime 选择 MicroVertical 脚手架的 BFF 运行时(支持: effect;默认: effect)',
64
64
  optionWorkspace: ' --workspace 对 @modern-js 依赖使用 workspace 协议(用于本地 monorepo 联调)',
65
65
  optionUltramodernPackageSource: ' --ultramodern-package-source 选择 UltraModern 依赖来源(workspace 或 install;BleedingDev 默认使用 install alias)',
@@ -47,8 +47,6 @@ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_no
47
47
  const bridge_config_cjs_namespaceObject = require("../ultramodern-workspace/bridge-config.cjs");
48
48
  const descriptors_cjs_namespaceObject = require("../ultramodern-workspace/descriptors.cjs");
49
49
  const naming_cjs_namespaceObject = require("../ultramodern-workspace/naming.cjs");
50
- const PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
51
- const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
52
50
  function readJsonObject(filePath) {
53
51
  const value = JSON.parse(external_node_fs_default().readFileSync(filePath, 'utf-8'));
54
52
  if (null === value || 'object' != typeof value || Array.isArray(value)) throw new Error(`UltraModern config must contain a JSON object: ${filePath}`);
@@ -57,45 +55,18 @@ function readJsonObject(filePath) {
57
55
  function readOptionalJsonObject(filePath) {
58
56
  return external_node_fs_default().existsSync(filePath) ? readJsonObject(filePath) : {};
59
57
  }
60
- function packageScopeFromRoot(workspaceRoot) {
61
- const rootPackage = readOptionalJsonObject(external_node_path_default().join(workspaceRoot, 'package.json'));
62
- return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : external_node_path_default().basename(workspaceRoot);
58
+ function packageScopeFromRoot(workspaceRoot1) {
59
+ const rootPackage = readOptionalJsonObject(external_node_path_default().join(workspaceRoot1, 'package.json'));
60
+ return 'string' == typeof rootPackage.name && rootPackage.name.length > 0 ? rootPackage.name : external_node_path_default().basename(workspaceRoot1);
63
61
  }
64
- function packageSourceFromMetadata(workspaceRoot) {
65
- const metadataPath = external_node_path_default().join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
66
- if (!external_node_fs_default().existsSync(metadataPath)) return;
67
- const metadata = readJsonObject(metadataPath);
68
- const aliases = metadata.modernPackages?.aliases ?? {};
69
- const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
70
- const firstPackage = Object.keys(aliases)[0];
71
- const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
72
- const unscopedName = firstPackage?.split('/').at(-1) ?? '';
73
- const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
74
- const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
75
- return {
76
- strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
77
- modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : 'workspace:*',
78
- registry: 'string' == typeof metadata.modernPackages?.registry ? metadata.modernPackages.registry : void 0,
79
- aliasScope,
80
- aliasPackageNamePrefix
81
- };
82
- }
83
- function readOverlayPorts(workspaceRoot) {
84
- const overlayPath = external_node_path_default().join(workspaceRoot, DEVELOPMENT_OVERLAY_PATH);
85
- if (!external_node_fs_default().existsSync(overlayPath)) return {};
86
- const overlay = readJsonObject(overlayPath);
87
- const ports = overlay.ports;
88
- if (null === ports || 'object' != typeof ports || Array.isArray(ports)) return {};
89
- return Object.fromEntries(Object.entries(ports).filter((entry)=>'number' == typeof entry[1]));
90
- }
91
- function normalizeCompactConfig(workspaceRoot, sourcePath, config) {
62
+ function normalizeCompactConfig(sourcePath, config) {
92
63
  const packageSource = config.packageSource && 'object' == typeof config.packageSource ? {
93
64
  strategy: 'install' === config.packageSource.strategy ? 'install' : 'workspace',
94
65
  modernPackageVersion: 'string' == typeof config.packageSource.modernPackageVersion ? config.packageSource.modernPackageVersion : 'workspace:*',
95
66
  registry: 'string' == typeof config.packageSource.registry ? config.packageSource.registry : void 0,
96
67
  aliasScope: 'string' == typeof config.packageSource.aliasScope ? config.packageSource.aliasScope : void 0,
97
68
  aliasPackageNamePrefix: 'string' == typeof config.packageSource.aliasPackageNamePrefix ? config.packageSource.aliasPackageNamePrefix : void 0
98
- } : packageSourceFromMetadata(workspaceRoot);
69
+ } : void 0;
99
70
  return {
100
71
  schemaVersion: 'number' == typeof config.schemaVersion ? config.schemaVersion : 1,
101
72
  profile: 'string' == typeof config.profile ? config.profile : void 0,
@@ -141,63 +112,10 @@ function normalizeCompactConfig(workspaceRoot, sourcePath, config) {
141
112
  }
142
113
  };
143
114
  }
144
- function adaptLegacyContract(workspaceRoot, sourcePath, contract) {
145
- const ports = readOverlayPorts(workspaceRoot);
146
- const apps = Array.isArray(contract.apps) ? contract.apps : [];
147
- const shell = apps.find((app)=>app?.id === descriptors_cjs_namespaceObject.shellApp.id);
148
- return {
149
- schemaVersion: 'number' == typeof contract.schemaVersion ? contract.schemaVersion : 1,
150
- profile: 'string' == typeof contract.profile ? contract.profile : void 0,
151
- source: 'legacy',
152
- sourcePath,
153
- workspace: {
154
- packageScope: packageScopeFromRoot(workspaceRoot)
155
- },
156
- packageSource: packageSourceFromMetadata(workspaceRoot),
157
- features: {
158
- tailwind: shell?.styling?.tailwind !== false
159
- },
160
- topology: {
161
- apps: apps.map((app)=>{
162
- const id = String(app.id);
163
- const appPath = 'string' == typeof app.path ? app.path : id === descriptors_cjs_namespaceObject.shellApp.id ? descriptors_cjs_namespaceObject.shellApp.directory : `verticals/${(0, naming_cjs_namespaceObject.toKebabCase)(id)}`;
164
- const domain = 'string' == typeof app.i18n?.namespace && 'shell' !== app.i18n.namespace ? app.i18n.namespace : appPath.split('/').at(-1);
165
- return {
166
- id,
167
- kind: 'vertical' === app.kind ? 'vertical' : 'shell',
168
- path: appPath,
169
- package: 'string' == typeof app.package ? app.package : void 0,
170
- packageSuffix: 'string' == typeof app.package ? app.package.split('/').at(-1) : appPath.split('/').at(-1),
171
- displayName: id === descriptors_cjs_namespaceObject.shellApp.id ? descriptors_cjs_namespaceObject.shellApp.displayName : void 0,
172
- domain,
173
- port: ports[id],
174
- moduleFederation: app.moduleFederation && 'object' == typeof app.moduleFederation ? {
175
- role: 'vertical' === app.kind ? 'remote' : 'host',
176
- name: 'string' == typeof app.moduleFederation.name ? app.moduleFederation.name : void 0,
177
- exposes: Array.isArray(app.moduleFederation.exposes) ? app.moduleFederation.exposes.filter((expose)=>'string' == typeof expose) : void 0,
178
- verticalRefs: Array.isArray(app.moduleFederation.verticalRefs) ? app.moduleFederation.verticalRefs.filter((ref)=>'string' == typeof ref) : void 0,
179
- hostOnly: 'vertical' !== app.kind
180
- } : void 0,
181
- effectApi: app.effect && 'object' == typeof app.effect ? {
182
- stem: 'string' == typeof app.effect.prefix ? app.effect.prefix.split('/').filter(Boolean).at(-1) ?? domain ?? id : domain ?? id,
183
- prefix: 'string' == typeof app.effect.prefix ? app.effect.prefix : `/${domain ?? id}-api`,
184
- consumedBy: [
185
- descriptors_cjs_namespaceObject.shellApp.id,
186
- id
187
- ]
188
- } : void 0
189
- };
190
- })
191
- },
192
- legacyContract: contract
193
- };
194
- }
195
- function readUltramodernConfig(workspaceRoot = process.cwd()) {
196
- const compactPath = external_node_path_default().join(workspaceRoot, descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH);
197
- if (external_node_fs_default().existsSync(compactPath)) return normalizeCompactConfig(workspaceRoot, compactPath, readJsonObject(compactPath));
198
- const legacyPath = external_node_path_default().join(workspaceRoot, descriptors_cjs_namespaceObject.GENERATED_CONTRACT_PATH);
199
- if (external_node_fs_default().existsSync(legacyPath)) return adaptLegacyContract(workspaceRoot, legacyPath, readJsonObject(legacyPath));
200
- throw new Error(`Missing UltraModern config. Expected ${descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH} or ${descriptors_cjs_namespaceObject.GENERATED_CONTRACT_PATH}.`);
115
+ function readUltramodernConfig(workspaceRoot1 = process.cwd()) {
116
+ const compactPath = external_node_path_default().join(workspaceRoot1, descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH);
117
+ if (external_node_fs_default().existsSync(compactPath)) return normalizeCompactConfig(compactPath, readJsonObject(compactPath));
118
+ throw new Error(`Missing UltraModern config. Expected ${descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH}.`);
201
119
  }
202
120
  function workspaceAppsFromToolingConfig(config) {
203
121
  return config.topology.apps.map((app)=>{
@@ -83,7 +83,6 @@ const FIRST_VERTICAL_PORT = 4101;
83
83
  const TOPOLOGY_PATH = 'topology/reference-topology.json';
84
84
  const OWNERSHIP_PATH = 'topology/ownership.json';
85
85
  const DEVELOPMENT_OVERLAY_PATH = 'topology/local-overlays/development.json';
86
- const PACKAGE_SOURCE_METADATA_PATH = '.modernjs/ultramodern-package-source.json';
87
86
  function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
88
87
  if (packageSource) return (0, external_package_source_cjs_namespaceObject.resolvePackageSource)({
89
88
  targetDir: workspaceRoot,
@@ -96,37 +95,12 @@ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
96
95
  const compactConfig = (0, config_cjs_namespaceObject.readUltramodernConfig)(workspaceRoot);
97
96
  if (compactConfig.packageSource) return compactConfig.packageSource;
98
97
  }
99
- const metadataPath = external_node_path_default().join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH);
100
- if (!external_node_fs_default().existsSync(metadataPath)) return (0, external_package_source_cjs_namespaceObject.resolvePackageSource)({
101
- targetDir: workspaceRoot,
102
- packageName: external_node_path_default().basename(workspaceRoot),
103
- modernVersion
104
- });
105
- const metadata = (0, external_fs_io_cjs_namespaceObject.readJsonFile)(metadataPath);
106
- const aliases = metadata.modernPackages?.aliases ?? {};
107
- const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
108
- const firstPackage = Object.keys(aliases)[0];
109
- const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
110
- const unscopedName = firstPackage?.split('/').at(-1) ?? '';
111
- const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
112
- const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
113
- return {
114
- strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
115
- modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : modernVersion,
116
- registry: metadata.modernPackages?.registry,
117
- aliasScope,
118
- aliasPackageNamePrefix
119
- };
98
+ throw new Error(`Missing UltraModern workspace file: ${compactPath}`);
120
99
  }
121
100
  function existingTailwindEnabled(workspaceRoot) {
122
101
  const compactPath = external_node_path_default().join(workspaceRoot, external_descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH);
123
102
  if (external_node_fs_default().existsSync(compactPath)) return (0, config_cjs_namespaceObject.readUltramodernConfig)(workspaceRoot).features.tailwind;
124
- const contractPath = external_node_path_default().join(workspaceRoot, external_descriptors_cjs_namespaceObject.GENERATED_CONTRACT_PATH);
125
- if (!external_node_fs_default().existsSync(contractPath)) return true;
126
- const contract = (0, external_fs_io_cjs_namespaceObject.readJsonFile)(contractPath);
127
- const apps = (0, external_types_cjs_namespaceObject.isRecord)(contract) && Array.isArray(contract.apps) ? contract.apps : [];
128
- const shell = apps.find((app)=>(0, external_types_cjs_namespaceObject.isRecord)(app) && app.id === external_descriptors_cjs_namespaceObject.shellApp.id);
129
- return shell?.styling && (0, external_types_cjs_namespaceObject.isRecord)(shell.styling) ? false !== shell.styling.tailwind : true;
103
+ throw new Error(`Missing UltraModern workspace file: ${compactPath}`);
130
104
  }
131
105
  function existingBridgeConfig(workspaceRoot) {
132
106
  const compactPath = external_node_path_default().join(workspaceRoot, external_descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH);
@@ -172,7 +146,7 @@ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwin
172
146
  (0, external_fs_io_cjs_namespaceObject.writeFileReplacing)(workspaceRoot, `${external_descriptors_cjs_namespaceObject.shellApp.directory}/src/routes/[lang]/page.tsx`, (0, external_demo_components_cjs_namespaceObject.createShellPage)(remotes));
173
147
  (0, external_fs_io_cjs_namespaceObject.writeFileReplacing)(workspaceRoot, `${external_descriptors_cjs_namespaceObject.shellApp.directory}/src/routes/vertical-components.tsx`, (0, external_demo_components_cjs_namespaceObject.createShellRemoteComponents)(scope, remotes));
174
148
  (0, external_fs_io_cjs_namespaceObject.writeFileReplacing)(workspaceRoot, `${external_descriptors_cjs_namespaceObject.shellApp.directory}/src/routes/shell-frame.tsx`, (0, external_app_files_cjs_namespaceObject.createShellFrameComponent)());
175
- (0, external_fs_io_cjs_namespaceObject.writeFileReplacing)(workspaceRoot, `${external_descriptors_cjs_namespaceObject.shellApp.directory}/src/effect/vertical-clients.ts`, (0, external_effect_api_cjs_namespaceObject.createShellEffectClient)(scope, remotes));
149
+ (0, external_fs_io_cjs_namespaceObject.writeFileReplacing)(workspaceRoot, `${external_descriptors_cjs_namespaceObject.shellApp.directory}/src/api/vertical-clients.ts`, (0, external_effect_api_cjs_namespaceObject.createShellEffectClient)(scope, remotes));
176
150
  }
177
151
  function addShellZephyrDependency(workspaceRoot, scope, remote) {
178
152
  const packagePath = external_node_path_default().join(workspaceRoot, external_descriptors_cjs_namespaceObject.shellApp.directory, 'package.json');
@@ -228,10 +202,11 @@ function verticalsFromTopology(topology, ports) {
228
202
  return (topology.verticals ?? []).map((vertical)=>{
229
203
  const domain = vertical.domain ?? String(vertical.id);
230
204
  const packageSuffix = vertical.package?.split('/').at(-1) ?? domain;
231
- const effectApi = vertical.api?.effect ? {
232
- stem: 'string' == typeof vertical.api.effect.basePath ? vertical.api.effect.basePath.split('/').filter(Boolean).at(-1) ?? domain : domain,
233
- prefix: vertical.api.effect.bff?.prefix ?? `/${domain}-api`,
234
- consumedBy: Array.isArray(vertical.api.effect.consumedBy) ? vertical.api.effect.consumedBy : [
205
+ const apiTopology = vertical.api;
206
+ const effectApi = apiTopology?.runtime === 'effect' ? {
207
+ stem: 'string' == typeof apiTopology.basePath ? apiTopology.basePath.split('/').filter(Boolean).at(-1) ?? domain : domain,
208
+ prefix: apiTopology.bff?.prefix ?? `/${domain}-api`,
209
+ consumedBy: Array.isArray(apiTopology.consumedBy) ? apiTopology.consumedBy : [
235
210
  external_descriptors_cjs_namespaceObject.shellApp.id,
236
211
  vertical.id
237
212
  ]
@@ -325,9 +300,7 @@ function readRequiredJsonObject(filePath) {
325
300
  }
326
301
  function readRequiredWorkspaceConfig(workspaceRoot) {
327
302
  const compactPath = external_node_path_default().join(workspaceRoot, external_descriptors_cjs_namespaceObject.ULTRAMODERN_CONFIG_PATH);
328
- if (external_node_fs_default().existsSync(compactPath)) return void readRequiredJsonObject(compactPath);
329
- readRequiredJsonObject(external_node_path_default().join(workspaceRoot, external_descriptors_cjs_namespaceObject.GENERATED_CONTRACT_PATH));
330
- readRequiredJsonObject(external_node_path_default().join(workspaceRoot, PACKAGE_SOURCE_METADATA_PATH));
303
+ readRequiredJsonObject(compactPath);
331
304
  }
332
305
  function assertOptionalJsonObject(value, label, filePath) {
333
306
  if (void 0 !== value && !(0, external_types_cjs_namespaceObject.isRecord)(value)) throw new Error(`${label} in ${filePath} must be a JSON object`);
@@ -348,8 +321,8 @@ function validateWorkspaceAppDescriptors(apps) {
348
321
  if ('number' != typeof app.port || !Number.isFinite(app.port) || app.port <= 0) throw new Error(`Invalid development port for ${appLabel}`);
349
322
  assertNonEmptyString(app.mfName, `Module Federation name for ${appLabel}`);
350
323
  if (app.effectApi) {
351
- assertNonEmptyString(app.effectApi.prefix, `Effect API prefix for ${appLabel}`);
352
- if (!app.effectApi.prefix.startsWith('/')) throw new Error(`Effect API prefix for ${appLabel} must start with "/"`);
324
+ assertNonEmptyString(app.effectApi.prefix, `API prefix for ${appLabel}`);
325
+ if (!app.effectApi.prefix.startsWith('/')) throw new Error(`API prefix for ${appLabel} must start with "/"`);
353
326
  }
354
327
  }
355
328
  }
@@ -359,7 +332,7 @@ function validateUniqueWorkspaceAppDescriptors(apps) {
359
332
  assertUniqueAppField(apps, 'output path', (app)=>(0, external_naming_cjs_namespaceObject.normalizePath)(app.directory));
360
333
  assertUniqueAppField(apps, 'Module Federation name', (app)=>app.mfName);
361
334
  assertUniqueAppField(apps, 'development port', (app)=>String(app.port));
362
- assertUniqueAppField(apps, 'Effect API prefix', (app)=>app.effectApi?.prefix);
335
+ assertUniqueAppField(apps, 'API prefix', (app)=>app.effectApi?.prefix);
363
336
  assertUniqueAppField(apps, 'manifest environment name', (app)=>'vertical' === app.kind ? (0, external_descriptors_cjs_namespaceObject.createRemoteManifestEnv)(app) : void 0);
364
337
  }
365
338
  function assertUniqueAppField(apps, label, readValue) {
@@ -448,7 +421,7 @@ function createDryRunJsonMutations(preflight, manifestUrl) {
448
421
  {
449
422
  path: DEVELOPMENT_OVERLAY_PATH,
450
423
  pointer: `/apis/${vertical.id}`,
451
- description: `Add local Effect API URL for ${vertical.id}`,
424
+ description: `Add local API URL for ${vertical.id}`,
452
425
  value: `http://localhost:${vertical.port}${(0, external_descriptors_cjs_namespaceObject.effectApiPrefix)(vertical)}`
453
426
  }
454
427
  ] : [];
@@ -95,6 +95,7 @@ function createTopology(scope, remotes = []) {
95
95
  script: "scripts/validate-ultramodern-workspace.mjs",
96
96
  commands: [
97
97
  'pnpm i18n:boundaries',
98
+ 'pnpm api:check',
98
99
  'pnpm contract:check'
99
100
  ]
100
101
  }
@@ -288,6 +289,7 @@ function createUltramodernConfig(scope, modernVersion, packageSource, apps = [
288
289
  publicSurface: "scripts/generate-public-surface-assets.mjs",
289
290
  cloudflareProof: "scripts/proof-cloudflare-version.mjs",
290
291
  performanceReadiness: "scripts/ultramodern-performance-readiness.mjs",
292
+ apiBoundaries: "scripts/check-ultramodern-api-boundaries.mjs",
291
293
  skills: "scripts/bootstrap-agent-skills.mjs"
292
294
  }
293
295
  }
@@ -248,36 +248,36 @@ ${showcaseItems}
248
248
  }
249
249
  function createRemotePage(app) {
250
250
  const tw = (0, external_naming_cjs_namespaceObject.createTw)((0, external_naming_cjs_namespaceObject.tailwindPrefixForApp)(app));
251
- const listEffectItems = `list${(0, external_naming_cjs_namespaceObject.toPascalCase)((0, external_descriptors_cjs_namespaceObject.effectApiStem)(app))}`;
252
- const effectBffImport = (0, external_descriptors_cjs_namespaceObject.appHasEffectApi)(app) ? `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
251
+ const listApiItems = `list${(0, external_naming_cjs_namespaceObject.toPascalCase)((0, external_descriptors_cjs_namespaceObject.effectApiStem)(app))}`;
252
+ const apiImport = (0, external_descriptors_cjs_namespaceObject.appHasEffectApi)(app) ? `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
253
253
  import { Link } from '@modern-js/plugin-tanstack/runtime';
254
254
  import { useEffect, useState } from 'react';
255
255
  import {
256
256
  Effect,
257
- ${listEffectItems},
257
+ ${listApiItems},
258
258
  runEffectRequest,
259
- } from '../../effect/${(0, external_descriptors_cjs_namespaceObject.effectApiStem)(app)}-client';
259
+ } from '../../api/${(0, external_descriptors_cjs_namespaceObject.effectApiStem)(app)}-client';
260
260
  import { UltramodernRouteHead } from '../ultramodern-route-head';
261
261
  import { ultramodernUiMarker } from '../../ultramodern-build';
262
262
  ` : "import { useModernI18n } from '@modern-js/plugin-i18n/runtime';\nimport { Link } from '@modern-js/plugin-tanstack/runtime';\nimport { UltramodernRouteHead } from '../ultramodern-route-head';\nimport { ultramodernUiMarker } from '../../ultramodern-build';\n";
263
- const effectBffState = (0, external_descriptors_cjs_namespaceObject.appHasEffectApi)(app) ? ` const [effectApiStatus, setEffectApiStatus] = useState('pending');
263
+ const apiState = (0, external_descriptors_cjs_namespaceObject.appHasEffectApi)(app) ? ` const [apiStatus, setApiStatus] = useState('pending');
264
264
 
265
265
  useEffect(() => {
266
266
  let cancelled = false;
267
267
  void runEffectRequest(
268
- ${listEffectItems}({ limit: 1 }).pipe(
268
+ ${listApiItems}({ limit: 1 }).pipe(
269
269
  Effect.match({
270
270
  onFailure: () => {
271
271
  if (cancelled) {
272
272
  return;
273
273
  }
274
- setEffectApiStatus('unavailable');
274
+ setApiStatus('unavailable');
275
275
  },
276
276
  onSuccess: data => {
277
277
  if (cancelled) {
278
278
  return;
279
279
  }
280
- setEffectApiStatus(data.items.at(0)?.title ?? 'empty');
280
+ setApiStatus(data.items.at(0)?.title ?? 'empty');
281
281
  },
282
282
  }),
283
283
  ),
@@ -289,12 +289,12 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
289
289
  }, []);
290
290
 
291
291
  ` : '';
292
- const effectBffMarkup = (0, external_descriptors_cjs_namespaceObject.appHasEffectApi)(app) ? ` <p data-testid="effect-bff-status">{effectApiStatus}</p>
292
+ const apiMarkup = (0, external_descriptors_cjs_namespaceObject.appHasEffectApi)(app) ? ` <p data-testid="api-status">{apiStatus}</p>
293
293
  ` : '';
294
- return `${effectBffImport}
294
+ return `${apiImport}
295
295
  export default function ${(0, external_naming_cjs_namespaceObject.toPascalCase)(app.id)}Home() {
296
296
  const { language, supportedLanguages, t } = useModernI18n();
297
- ${effectBffState} return (
297
+ ${apiState} return (
298
298
  <main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
299
299
  <UltramodernRouteHead />
300
300
  <nav aria-label={t('${app.domain}.language.switcher')} className="${tw('flex gap-3')}">
@@ -315,7 +315,7 @@ ${effectBffState} return (
315
315
  <p className="${tw('sr-only')}" data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
316
316
  {ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
317
317
  </p>
318
- ${effectBffMarkup} </main>
318
+ ${apiMarkup} </main>
319
319
  );
320
320
  }
321
321
  `;
@@ -28,7 +28,6 @@ var __webpack_require__ = {};
28
28
  var __webpack_exports__ = {};
29
29
  __webpack_require__.r(__webpack_exports__);
30
30
  __webpack_require__.d(__webpack_exports__, {
31
- GENERATED_CONTRACT_PATH: ()=>GENERATED_CONTRACT_PATH,
32
31
  ULTRAMODERN_CONFIG_PATH: ()=>ULTRAMODERN_CONFIG_PATH,
33
32
  appHasEffectApi: ()=>appHasEffectApi,
34
33
  appI18nNamespace: ()=>appI18nNamespace,
@@ -49,7 +48,6 @@ __webpack_require__.d(__webpack_exports__, {
49
48
  zephyrRemoteDependency: ()=>zephyrRemoteDependency
50
49
  });
51
50
  const external_naming_cjs_namespaceObject = require("./naming.cjs");
52
- const GENERATED_CONTRACT_PATH = '.modernjs/ultramodern-generated-contract.json';
53
51
  const ULTRAMODERN_CONFIG_PATH = '.modernjs/ultramodern.json';
54
52
  const shellApp = {
55
53
  id: 'shell-super-app',
@@ -181,7 +179,6 @@ function createCloudflarePublicUrlEnv(app) {
181
179
  function appI18nNamespace(app) {
182
180
  return 'shell' === app.kind ? 'shell' : app.domain ?? app.id;
183
181
  }
184
- exports.GENERATED_CONTRACT_PATH = __webpack_exports__.GENERATED_CONTRACT_PATH;
185
182
  exports.ULTRAMODERN_CONFIG_PATH = __webpack_exports__.ULTRAMODERN_CONFIG_PATH;
186
183
  exports.appHasEffectApi = __webpack_exports__.appHasEffectApi;
187
184
  exports.appI18nNamespace = __webpack_exports__.appI18nNamespace;
@@ -201,7 +198,6 @@ exports.shellApp = __webpack_exports__.shellApp;
201
198
  exports.verticalEffectApps = __webpack_exports__.verticalEffectApps;
202
199
  exports.zephyrRemoteDependency = __webpack_exports__.zephyrRemoteDependency;
203
200
  for(var __rspack_i in __webpack_exports__)if (-1 === [
204
- "GENERATED_CONTRACT_PATH",
205
201
  "ULTRAMODERN_CONFIG_PATH",
206
202
  "appHasEffectApi",
207
203
  "appI18nNamespace",