@bleedingdev/modern-js-create 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121

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 (118) hide show
  1. package/README.md +35 -12
  2. package/dist/cjs/create-package-root.cjs +7 -9
  3. package/dist/cjs/index.cjs +74 -44
  4. package/dist/cjs/locale/en.cjs +6 -7
  5. package/dist/cjs/locale/zh.cjs +6 -7
  6. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +337 -0
  7. package/dist/cjs/ultramodern-workspace/app-files.cjs +223 -0
  8. package/dist/cjs/ultramodern-workspace/contracts.cjs +836 -0
  9. package/dist/cjs/ultramodern-workspace/demo-components.cjs +422 -0
  10. package/dist/cjs/ultramodern-workspace/descriptors.cjs +222 -0
  11. package/dist/cjs/ultramodern-workspace/effect-api.cjs +952 -0
  12. package/dist/cjs/ultramodern-workspace/fs-io.cjs +191 -0
  13. package/dist/cjs/ultramodern-workspace/index.cjs +48 -0
  14. package/dist/cjs/ultramodern-workspace/locales.cjs +173 -0
  15. package/dist/cjs/ultramodern-workspace/module-federation.cjs +487 -0
  16. package/dist/cjs/ultramodern-workspace/naming.cjs +161 -0
  17. package/dist/cjs/ultramodern-workspace/package-json.cjs +406 -0
  18. package/dist/cjs/ultramodern-workspace/package-source.cjs +59 -0
  19. package/dist/cjs/ultramodern-workspace/policy.cjs +248 -0
  20. package/dist/cjs/ultramodern-workspace/public-surface.cjs +268 -0
  21. package/dist/cjs/ultramodern-workspace/routes.cjs +375 -0
  22. package/dist/cjs/ultramodern-workspace/types.cjs +61 -0
  23. package/dist/cjs/ultramodern-workspace/versions.cjs +153 -0
  24. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +153 -0
  25. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +175 -0
  26. package/dist/esm/create-package-root.js +7 -9
  27. package/dist/esm/index.js +72 -42
  28. package/dist/esm/locale/en.js +6 -7
  29. package/dist/esm/locale/zh.js +6 -7
  30. package/dist/esm/ultramodern-workspace/add-vertical.js +252 -0
  31. package/dist/esm/ultramodern-workspace/app-files.js +149 -0
  32. package/dist/esm/ultramodern-workspace/contracts.js +741 -0
  33. package/dist/esm/ultramodern-workspace/demo-components.js +363 -0
  34. package/dist/esm/ultramodern-workspace/descriptors.js +133 -0
  35. package/dist/esm/ultramodern-workspace/effect-api.js +854 -0
  36. package/dist/esm/ultramodern-workspace/fs-io.js +90 -0
  37. package/dist/esm/ultramodern-workspace/index.js +3 -0
  38. package/dist/esm/ultramodern-workspace/locales.js +122 -0
  39. package/dist/esm/ultramodern-workspace/module-federation.js +415 -0
  40. package/dist/esm/ultramodern-workspace/naming.js +71 -0
  41. package/dist/esm/ultramodern-workspace/package-json.js +338 -0
  42. package/dist/esm/ultramodern-workspace/package-source.js +21 -0
  43. package/dist/esm/ultramodern-workspace/policy.js +183 -0
  44. package/dist/esm/ultramodern-workspace/public-surface.js +183 -0
  45. package/dist/esm/ultramodern-workspace/routes.js +280 -0
  46. package/dist/esm/ultramodern-workspace/types.js +16 -0
  47. package/dist/esm/ultramodern-workspace/versions.js +34 -0
  48. package/dist/esm/ultramodern-workspace/workspace-scripts.js +91 -0
  49. package/dist/esm/ultramodern-workspace/write-workspace.js +121 -0
  50. package/dist/esm-node/create-package-root.js +7 -9
  51. package/dist/esm-node/index.js +72 -42
  52. package/dist/esm-node/locale/en.js +6 -7
  53. package/dist/esm-node/locale/zh.js +6 -7
  54. package/dist/esm-node/ultramodern-workspace/add-vertical.js +253 -0
  55. package/dist/esm-node/ultramodern-workspace/app-files.js +150 -0
  56. package/dist/esm-node/ultramodern-workspace/contracts.js +742 -0
  57. package/dist/esm-node/ultramodern-workspace/demo-components.js +364 -0
  58. package/dist/esm-node/ultramodern-workspace/descriptors.js +134 -0
  59. package/dist/esm-node/ultramodern-workspace/effect-api.js +855 -0
  60. package/dist/esm-node/ultramodern-workspace/fs-io.js +91 -0
  61. package/dist/esm-node/ultramodern-workspace/index.js +4 -0
  62. package/dist/esm-node/ultramodern-workspace/locales.js +123 -0
  63. package/dist/esm-node/ultramodern-workspace/module-federation.js +416 -0
  64. package/dist/esm-node/ultramodern-workspace/naming.js +72 -0
  65. package/dist/esm-node/ultramodern-workspace/package-json.js +339 -0
  66. package/dist/esm-node/ultramodern-workspace/package-source.js +22 -0
  67. package/dist/esm-node/ultramodern-workspace/policy.js +184 -0
  68. package/dist/esm-node/ultramodern-workspace/public-surface.js +184 -0
  69. package/dist/esm-node/ultramodern-workspace/routes.js +281 -0
  70. package/dist/esm-node/ultramodern-workspace/types.js +17 -0
  71. package/dist/esm-node/ultramodern-workspace/versions.js +35 -0
  72. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +92 -0
  73. package/dist/esm-node/ultramodern-workspace/write-workspace.js +122 -0
  74. package/dist/types/locale/en.d.ts +4 -5
  75. package/dist/types/locale/index.d.ts +8 -10
  76. package/dist/types/locale/zh.d.ts +4 -5
  77. package/dist/types/ultramodern-workspace/add-vertical.d.ts +19 -0
  78. package/dist/types/ultramodern-workspace/app-files.d.ts +14 -0
  79. package/dist/types/ultramodern-workspace/contracts.d.ts +21 -0
  80. package/dist/types/ultramodern-workspace/demo-components.d.ts +9 -0
  81. package/dist/types/ultramodern-workspace/descriptors.d.ts +39 -0
  82. package/dist/types/ultramodern-workspace/effect-api.d.ts +73 -0
  83. package/dist/types/ultramodern-workspace/fs-io.d.ts +18 -0
  84. package/dist/types/ultramodern-workspace/index.d.ts +4 -0
  85. package/dist/types/ultramodern-workspace/locales.d.ts +183 -0
  86. package/dist/types/ultramodern-workspace/module-federation.d.ts +16 -0
  87. package/dist/types/ultramodern-workspace/naming.d.ts +16 -0
  88. package/dist/types/ultramodern-workspace/package-json.d.ts +12 -0
  89. package/dist/types/ultramodern-workspace/package-source.d.ts +2 -0
  90. package/dist/types/ultramodern-workspace/policy.d.ts +60 -0
  91. package/dist/types/ultramodern-workspace/public-surface.d.ts +37 -0
  92. package/dist/types/ultramodern-workspace/routes.d.ts +25 -0
  93. package/dist/types/ultramodern-workspace/types.d.ts +95 -0
  94. package/dist/types/ultramodern-workspace/versions.d.ts +38 -0
  95. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +10 -0
  96. package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -0
  97. package/package.json +4 -3
  98. package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +1 -4
  99. package/template-workspace/.mise.toml.handlebars +1 -0
  100. package/template-workspace/{AGENTS.md → AGENTS.md.handlebars} +12 -7
  101. package/template-workspace/README.md.handlebars +40 -24
  102. package/template-workspace/{pnpm-workspace.yaml → pnpm-workspace.yaml.handlebars} +2 -2
  103. package/template-workspace/scripts/bootstrap-agent-skills.mjs +31 -51
  104. package/templates/app/shell-frame.tsx +49 -0
  105. package/templates/app/ultramodern-route-head.tsx.handlebars +142 -0
  106. package/templates/packages/shared-contracts-index.ts +466 -0
  107. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +69 -0
  108. package/templates/workspace-scripts/check-ultramodern-i18n-boundaries.mjs +9 -0
  109. package/templates/workspace-scripts/generate-public-surface-assets.mjs +529 -0
  110. package/templates/workspace-scripts/proof-cloudflare-version.mjs +125 -0
  111. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +851 -0
  112. package/templates/workspace-scripts/ultramodern-performance-readiness.config.mjs +7 -0
  113. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +223 -0
  114. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +593 -0
  115. package/dist/cjs/ultramodern-workspace.cjs +0 -6797
  116. package/dist/esm/ultramodern-workspace.js +0 -6738
  117. package/dist/esm-node/ultramodern-workspace.js +0 -6739
  118. package/dist/types/ultramodern-workspace.d.ts +0 -29
@@ -0,0 +1,121 @@
1
+ import node_fs from "node:fs";
2
+ import { createAppEnvDts, createAppRuntimeConfig, createAppStyles, createPostcssConfig, createSharedDesignTokensCss, createShellFrameComponent, createTailwindConfig } from "./app-files.js";
3
+ import { createDevelopmentOverlay, createGeneratedContract, createOwnership, createPackageSourceMetadata, createTemplateManifest, createTopology } from "./contracts.js";
4
+ import { createLayout, createRemoteEntry, createRemoteExposeComponent, createRemotePage, createShellPage, createShellRemoteComponents, remoteComponentOutputPath } from "./demo-components.js";
5
+ import { GENERATED_CONTRACT_PATH, appHasEffectApi, appI18nNamespace, createShellHost, sharedPackages, shellApp } from "./descriptors.js";
6
+ import { createEffectClient, createEffectServiceEntry, createEffectSharedApi, createShellEffectClient } from "./effect-api.js";
7
+ import { copyRootTemplate, writeFile, writeJson } from "./fs-io.js";
8
+ import { createAppPublicLocaleMessages } from "./locales.js";
9
+ import { createAppModernConfig, createRemoteModuleFederationConfig, createShellModuleFederationConfig, createUltramodernBuildModule } from "./module-federation.js";
10
+ import { assertUniqueTailwindPrefixes, relativeRootFor, toPackageScope } from "./naming.js";
11
+ import { createAppPackage, createPackageTsConfig, createRootPackageJson, createSharedContractsIndex, createSharedPackage, createTsConfigBase } from "./package-json.js";
12
+ import { resolvePackageSource } from "./package-source.js";
13
+ import { createPublicWebAppArtifacts } from "./public-surface.js";
14
+ import { NODE_FETCH_VERSION, NODE_VERSION, PNPM_VERSION, TANSTACK_ROUTER_VERSION } from "./versions.js";
15
+ import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
16
+ function writeApp(targetDir, scope, app, packageSource, enableTailwind, remotes = []) {
17
+ const resolvedApp = 'shell' === app.kind ? createShellHost(remotes) : app;
18
+ const publicWeb = createPublicWebAppArtifacts(resolvedApp);
19
+ const writeAppFile = (relativePath, content)=>{
20
+ writeFile(targetDir, `${resolvedApp.directory}/${relativePath}`, content);
21
+ };
22
+ writeJson(targetDir, `${resolvedApp.directory}/package.json`, createAppPackage(scope, resolvedApp, packageSource, enableTailwind, remotes));
23
+ writeJson(targetDir, `${resolvedApp.directory}/tsconfig.json`, createPackageTsConfig(resolvedApp.directory, appHasEffectApi(resolvedApp)));
24
+ writeFile(targetDir, `${resolvedApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(resolvedApp, remotes));
25
+ writeFile(targetDir, `${resolvedApp.directory}/src/ultramodern-build.ts`, createUltramodernBuildModule(scope, resolvedApp));
26
+ writeFile(targetDir, publicWeb.jsonLdHelperFile.path, publicWeb.jsonLdHelperFile.content);
27
+ writeFile(targetDir, publicWeb.routeMetadataFile.path, publicWeb.routeMetadataFile.content);
28
+ writeFile(targetDir, publicWeb.routeHeadFile.path, publicWeb.routeHeadFile.content);
29
+ writeFile(targetDir, `${resolvedApp.directory}/modern.config.ts`, createAppModernConfig(scope, resolvedApp));
30
+ writeFile(targetDir, `${resolvedApp.directory}/src/modern.runtime.ts`, createAppRuntimeConfig(resolvedApp, scope, remotes));
31
+ writeJson(targetDir, `${resolvedApp.directory}/locales/en/translation.json`, createAppPublicLocaleMessages(resolvedApp, 'en', remotes));
32
+ writeJson(targetDir, `${resolvedApp.directory}/locales/en/${appI18nNamespace(resolvedApp)}.json`, createAppPublicLocaleMessages(resolvedApp, 'en', remotes));
33
+ writeJson(targetDir, `${resolvedApp.directory}/locales/cs/translation.json`, createAppPublicLocaleMessages(resolvedApp, 'cs', remotes));
34
+ writeJson(targetDir, `${resolvedApp.directory}/locales/cs/${appI18nNamespace(resolvedApp)}.json`, createAppPublicLocaleMessages(resolvedApp, 'cs', remotes));
35
+ writeFile(targetDir, `${resolvedApp.directory}/src/routes/index.css`, createAppStyles(enableTailwind, scope, resolvedApp));
36
+ if (enableTailwind) {
37
+ writeFile(targetDir, `${resolvedApp.directory}/postcss.config.mjs`, createPostcssConfig());
38
+ writeFile(targetDir, `${resolvedApp.directory}/tailwind.config.ts`, createTailwindConfig());
39
+ }
40
+ writeFile(targetDir, `${resolvedApp.directory}/module-federation.config.ts`, 'shell' === resolvedApp.kind ? createShellModuleFederationConfig(scope, remotes) : createRemoteModuleFederationConfig(scope, resolvedApp, remotes));
41
+ writeAppFile('src/routes/layout.tsx', createLayout(resolvedApp.id));
42
+ writeAppFile('src/routes/[lang]/page.tsx', 'shell' === resolvedApp.kind ? createShellPage(remotes) : createRemotePage(resolvedApp));
43
+ for (const generatedFile of publicWeb.routeMetaFiles)writeFile(targetDir, generatedFile.path, generatedFile.content);
44
+ for (const generatedFile of publicWeb.routeAliasFiles)writeFile(targetDir, generatedFile.path, generatedFile.content);
45
+ if ('shell' === resolvedApp.kind) {
46
+ writeAppFile('src/routes/vertical-components.tsx', createShellRemoteComponents(scope, remotes));
47
+ writeAppFile('src/routes/shell-frame.tsx', createShellFrameComponent());
48
+ writeFile(targetDir, `${resolvedApp.directory}/src/effect/vertical-clients.ts`, createShellEffectClient(scope, remotes));
49
+ }
50
+ if (appHasEffectApi(resolvedApp)) {
51
+ writeFile(targetDir, `${resolvedApp.directory}/shared/effect/api.ts`, createEffectSharedApi(resolvedApp));
52
+ writeFile(targetDir, `${resolvedApp.directory}/api/effect/index.ts`, createEffectServiceEntry(resolvedApp, '../../shared/effect/api.ts'));
53
+ writeFile(targetDir, `${resolvedApp.directory}/src/effect/${resolvedApp.effectApi.stem}-client.ts`, createEffectClient(resolvedApp, '../../shared/effect/api'));
54
+ }
55
+ if ('vertical' === resolvedApp.kind) {
56
+ writeAppFile('src/federation-entry.tsx', createRemoteEntry(resolvedApp));
57
+ for (const expose of Object.keys(resolvedApp.exposes ?? {})){
58
+ const outputPath = remoteComponentOutputPath(resolvedApp, expose);
59
+ if (outputPath) writeAppFile(outputPath.slice(resolvedApp.directory.length + 1), createRemoteExposeComponent(resolvedApp, expose));
60
+ }
61
+ }
62
+ }
63
+ function writeSharedPackages(targetDir, scope) {
64
+ for (const sharedPackage of sharedPackages){
65
+ writeJson(targetDir, `${sharedPackage.directory}/package.json`, createSharedPackage(scope, sharedPackage.id, sharedPackage.description));
66
+ writeJson(targetDir, `${sharedPackage.directory}/tsconfig.json`, {
67
+ extends: `${relativeRootFor(sharedPackage.directory)}/tsconfig.base.json`,
68
+ include: [
69
+ 'src'
70
+ ]
71
+ });
72
+ }
73
+ writeFile(targetDir, 'packages/shared-contracts/src/index.ts', createSharedContractsIndex());
74
+ writeFile(targetDir, 'packages/shared-design-tokens/src/index.ts', `export const sharedDesignTokens = {
75
+ color: {
76
+ accent: '#2f8f68',
77
+ foreground: '#133225',
78
+ surface: '#f6fbf7',
79
+ },
80
+ } as const;
81
+ `);
82
+ writeFile(targetDir, 'packages/shared-design-tokens/src/tokens.css', createSharedDesignTokensCss());
83
+ }
84
+ function generateUltramodernWorkspace(options) {
85
+ const scope = toPackageScope(options.packageName);
86
+ const packageSource = resolvePackageSource(options);
87
+ const enableTailwind = false !== options.enableTailwind;
88
+ const initialVerticals = [];
89
+ assertUniqueTailwindPrefixes([
90
+ shellApp,
91
+ ...initialVerticals
92
+ ]);
93
+ node_fs.mkdirSync(options.targetDir, {
94
+ recursive: true
95
+ });
96
+ copyRootTemplate(options.targetDir, {
97
+ packageName: options.packageName,
98
+ packageScope: scope,
99
+ nodeVersion: NODE_VERSION,
100
+ pnpmVersion: PNPM_VERSION,
101
+ nodeFetchVersion: NODE_FETCH_VERSION,
102
+ tanstackRouterVersion: TANSTACK_ROUTER_VERSION,
103
+ tailwindEnabled: String(enableTailwind)
104
+ });
105
+ writeJson(options.targetDir, 'package.json', createRootPackageJson(scope, packageSource, initialVerticals));
106
+ writeJson(options.targetDir, 'tsconfig.base.json', createTsConfigBase());
107
+ writeJson(options.targetDir, 'topology/reference-topology.json', createTopology(scope, initialVerticals));
108
+ writeJson(options.targetDir, 'topology/ownership.json', createOwnership(scope, initialVerticals));
109
+ writeJson(options.targetDir, 'topology/local-overlays/development.json', createDevelopmentOverlay(initialVerticals));
110
+ writeJson(options.targetDir, '.modernjs/ultramodern-workspace-template-manifest.json', createTemplateManifest(options.modernVersion, packageSource));
111
+ writeJson(options.targetDir, '.modernjs/ultramodern-package-source.json', createPackageSourceMetadata(scope, packageSource));
112
+ writeJson(options.targetDir, GENERATED_CONTRACT_PATH, createGeneratedContract(scope, [
113
+ createShellHost(initialVerticals),
114
+ ...initialVerticals
115
+ ], enableTailwind));
116
+ writeApp(options.targetDir, scope, shellApp, packageSource, enableTailwind, initialVerticals);
117
+ for (const remote of initialVerticals)writeApp(options.targetDir, scope, remote, packageSource, enableTailwind, initialVerticals);
118
+ writeSharedPackages(options.targetDir, scope);
119
+ writeGeneratedWorkspaceScripts(options.targetDir, scope, enableTailwind, initialVerticals);
120
+ }
121
+ export { generateUltramodernWorkspace, writeApp, writeSharedPackages };
@@ -1,17 +1,15 @@
1
1
  import "node:module";
2
2
  import node_fs from "node:fs";
3
3
  import node_path from "node:path";
4
+ const MAX_WALK_UP_LEVELS = 5;
4
5
  function resolveCreatePackageRoot(fromDir) {
5
- const candidates = [
6
- fromDir,
7
- node_path.resolve(fromDir, '..'),
8
- node_path.resolve(fromDir, '..', '..')
9
- ];
10
- const seen = new Set();
11
- for (const candidate of candidates)if (!seen.has(candidate)) {
12
- seen.add(candidate);
6
+ let candidate = fromDir;
7
+ for(let level = 0; level <= MAX_WALK_UP_LEVELS; level++){
13
8
  if (node_fs.existsSync(node_path.join(candidate, 'package.json')) && node_fs.existsSync(node_path.join(candidate, 'template-workspace'))) return candidate;
9
+ const parent = node_path.dirname(candidate);
10
+ if (parent === candidate) break;
11
+ candidate = parent;
14
12
  }
15
- throw new Error('Unable to resolve create package root');
13
+ throw new Error(`Unable to resolve the @modern-js/create package root (a directory containing both package.json and template-workspace/) within ${MAX_WALK_UP_LEVELS} levels above ${fromDir}`);
16
14
  }
17
15
  export { resolveCreatePackageRoot };
@@ -7,12 +7,19 @@ import { fileURLToPath } from "node:url";
7
7
  import { resolveCreatePackageRoot } from "./create-package-root.js";
8
8
  import { i18n, localeKeys } from "./locale/index.js";
9
9
  import { BLEEDINGDEV_CREATE_PACKAGE, BLEEDINGDEV_FRAMEWORK_VERSION_ENV, BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, WORKSPACE_PACKAGE_VERSION } from "./ultramodern-package-source.js";
10
- import { addUltramodernVertical, generateUltramodernWorkspace } from "./ultramodern-workspace.js";
10
+ import { addUltramodernVertical, generateUltramodernWorkspace } from "./ultramodern-workspace/index.js";
11
11
  const src_dirname = node_path.dirname(fileURLToPath(import.meta.url));
12
12
  const createPackageRoot = resolveCreatePackageRoot(src_dirname);
13
13
  const semverPattern = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
14
14
  const LEGACY_MODERN_JS_FLAG = '--legacy-modern-js';
15
15
  const LEGACY_MODERN_JS_CONFIRMATION = 'USE LEGACY MODERN.JS';
16
+ const WORKSPACE_PROTOCOL_FLAG = '--workspace';
17
+ const BFF_FLAG = '--bff';
18
+ const BFF_RUNTIME_OPTION = '--bff-runtime';
19
+ const SUPPORTED_BFF_RUNTIMES = [
20
+ 'effect'
21
+ ];
22
+ const REGISTRY_LOOKUP_TIMEOUT_MS = 15000;
16
23
  function getOptionValue(args, names) {
17
24
  for (const name of names){
18
25
  const prefix = `${name}=`;
@@ -46,8 +53,10 @@ function getBleedingDevFrameworkVersion(createPackage, fallbackVersion) {
46
53
  }
47
54
  function showVersion() {
48
55
  const createPackage = readCreatePackageJson();
56
+ const name = createPackage.name || '@modern-js/create';
49
57
  const version = createPackage.version || 'unknown';
50
58
  console.log(i18n.t(localeKeys.version.message, {
59
+ name,
51
60
  version
52
61
  }));
53
62
  process.exit(0);
@@ -63,20 +72,26 @@ function showHelp() {
63
72
  console.log(i18n.t(localeKeys.help.optionHelp));
64
73
  console.log(i18n.t(localeKeys.help.optionVersion));
65
74
  console.log(i18n.t(localeKeys.help.optionLang));
66
- if (localeKeys.help.optionTailwind) console.log(i18n.t(localeKeys.help.optionTailwind));
67
- if (localeKeys.help.optionUltramodernPackageSource) console.log(i18n.t(localeKeys.help.optionUltramodernPackageSource));
68
- if (localeKeys.help.optionUltramodernPackageScope) console.log(i18n.t(localeKeys.help.optionUltramodernPackageScope));
69
- if (localeKeys.help.optionUltramodernPackageNamePrefix) console.log(i18n.t(localeKeys.help.optionUltramodernPackageNamePrefix));
70
- if (localeKeys.help.optionVertical) console.log(i18n.t(localeKeys.help.optionVertical));
71
- if (localeKeys.help.optionLegacyModernJs) console.log(i18n.t(localeKeys.help.optionLegacyModernJs));
75
+ console.log(i18n.t(localeKeys.help.optionTailwind));
76
+ console.log(i18n.t(localeKeys.help.optionBff));
77
+ console.log(i18n.t(localeKeys.help.optionBffRuntime));
78
+ console.log(i18n.t(localeKeys.help.optionWorkspace));
79
+ console.log(i18n.t(localeKeys.help.optionUltramodernPackageSource));
80
+ console.log(i18n.t(localeKeys.help.optionUltramodernPackageVersion));
81
+ console.log(i18n.t(localeKeys.help.optionUltramodernPackageRegistry));
82
+ console.log(i18n.t(localeKeys.help.optionUltramodernPackageScope));
83
+ console.log(i18n.t(localeKeys.help.optionUltramodernPackageNamePrefix));
84
+ console.log(i18n.t(localeKeys.help.optionVertical));
85
+ console.log(i18n.t(localeKeys.help.optionLegacyModernJs));
72
86
  console.log('');
73
87
  console.log(i18n.t(localeKeys.help.examples));
74
88
  console.log(i18n.t(localeKeys.help.example1));
75
89
  console.log(i18n.t(localeKeys.help.example2));
76
- if (localeKeys.help.example4) console.log(i18n.t(localeKeys.help.example4));
77
- if (localeKeys.help.example5) console.log(i18n.t(localeKeys.help.example5));
78
- if (localeKeys.help.example6) console.log(i18n.t(localeKeys.help.example6));
79
- if (localeKeys.help.example12) console.log(i18n.t(localeKeys.help.example12));
90
+ console.log(i18n.t(localeKeys.help.example3));
91
+ console.log(i18n.t(localeKeys.help.example4));
92
+ console.log(i18n.t(localeKeys.help.example5));
93
+ console.log(i18n.t(localeKeys.help.example6));
94
+ console.log(i18n.t(localeKeys.help.example7));
80
95
  console.log('');
81
96
  console.log(i18n.t(localeKeys.help.moreInfo));
82
97
  console.log('');
@@ -133,6 +148,26 @@ function delegateLegacyModernJsSetup(args) {
133
148
  });
134
149
  throw new Error('Legacy Modern.js setup requires pnpm or npx to run @modern-js/create.');
135
150
  }
151
+ function detectBffRuntime(args) {
152
+ if (args.some((arg)=>arg.startsWith(`${BFF_FLAG}=`))) {
153
+ console.error(`${BFF_FLAG} does not accept a value. Use: ${BFF_RUNTIME_OPTION} <runtime>`);
154
+ process.exit(1);
155
+ }
156
+ const runtimeRequested = args.some((arg)=>arg === BFF_RUNTIME_OPTION || arg.startsWith(`${BFF_RUNTIME_OPTION}=`));
157
+ if (!runtimeRequested) return 'effect';
158
+ const runtime = getOptionValue(args, [
159
+ BFF_RUNTIME_OPTION
160
+ ]);
161
+ if (!runtime) {
162
+ console.error(`${BFF_RUNTIME_OPTION} requires a value (supported: ${SUPPORTED_BFF_RUNTIMES.join(', ')})`);
163
+ process.exit(1);
164
+ }
165
+ if (!SUPPORTED_BFF_RUNTIMES.includes(runtime)) {
166
+ console.error(`Unsupported BFF runtime "${runtime}". UltraModern workspaces scaffold an Effect BFF for every MicroVertical (supported: ${SUPPORTED_BFF_RUNTIMES.join(', ')}).`);
167
+ process.exit(1);
168
+ }
169
+ return runtime;
170
+ }
136
171
  function detectTailwindFlag() {
137
172
  const args = process.argv.slice(2);
138
173
  return !args.includes('--no-tailwind');
@@ -184,7 +219,7 @@ function hasExplicitUltramodernPackageSource(args, value) {
184
219
  ]);
185
220
  return value ? configuredValue === value : void 0 !== configuredValue;
186
221
  }
187
- function readBleedingDevFrameworkVersionFromRegistry() {
222
+ function readBleedingDevFrameworkVersionFromRegistry(fallbackVersion) {
188
223
  const envVersion = process.env[BLEEDINGDEV_FRAMEWORK_VERSION_ENV]?.trim();
189
224
  if (envVersion) {
190
225
  if (!semverPattern.test(envVersion)) {
@@ -199,16 +234,19 @@ function readBleedingDevFrameworkVersionFromRegistry() {
199
234
  `${BLEEDINGDEV_CREATE_PACKAGE}@latest`,
200
235
  'ultramodern.frameworkVersion',
201
236
  '--json'
202
- ]).trim();
237
+ ], {
238
+ timeoutMs: REGISTRY_LOOKUP_TIMEOUT_MS
239
+ }).trim();
203
240
  const version = JSON.parse(rawVersion);
204
241
  if ('string' == typeof version && semverPattern.test(version)) return version;
205
242
  } catch {}
206
- console.error([
207
- `Could not resolve ${BLEEDINGDEV_CREATE_PACKAGE}@latest ultramodern.frameworkVersion.`,
208
- 'Pass --workspace to use local workspace protocol dependencies,',
243
+ console.warn([
244
+ `Could not resolve ${BLEEDINGDEV_CREATE_PACKAGE}@latest ultramodern.frameworkVersion from the npm registry.`,
245
+ `Falling back to the packaged framework version ${fallbackVersion}.`,
246
+ `Pass ${WORKSPACE_PROTOCOL_FLAG} to use local workspace protocol dependencies,`,
209
247
  'or pass --ultramodern-package-version with the exact BleedingDev framework cohort.'
210
248
  ].join(' '));
211
- process.exit(1);
249
+ return fallbackVersion;
212
250
  }
213
251
  function resolveInstallBackedPackageSource(args, createPackage, packageSource) {
214
252
  const explicitVersion = getOptionValue(args, [
@@ -223,7 +261,7 @@ function resolveInstallBackedPackageSource(args, createPackage, packageSource) {
223
261
  return {
224
262
  ...packageSource,
225
263
  strategy: 'install',
226
- modernPackageVersion: explicitVersion ?? (isBleedingDevCreatePackage(createPackage) ? packageSource.modernPackageVersion : readBleedingDevFrameworkVersionFromRegistry()),
264
+ modernPackageVersion: explicitVersion ?? (isBleedingDevCreatePackage(createPackage) ? packageSource.modernPackageVersion : readBleedingDevFrameworkVersionFromRegistry(packageSource.modernPackageVersion)),
227
265
  aliasScope,
228
266
  aliasPackageNamePrefix: getOptionValue(args, [
229
267
  '--ultramodern-package-name-prefix'
@@ -231,7 +269,12 @@ function resolveInstallBackedPackageSource(args, createPackage, packageSource) {
231
269
  };
232
270
  }
233
271
  function resolveWorkspacePackageSource(args, createPackage, packageSource) {
234
- if (hasExplicitUltramodernPackageSource(args, 'workspace')) return {
272
+ const workspaceProtocolRequested = args.includes(WORKSPACE_PROTOCOL_FLAG);
273
+ if (workspaceProtocolRequested && hasExplicitUltramodernPackageSource(args, 'install')) {
274
+ console.error(`${WORKSPACE_PROTOCOL_FLAG} conflicts with --ultramodern-package-source=install`);
275
+ process.exit(1);
276
+ }
277
+ if (workspaceProtocolRequested || hasExplicitUltramodernPackageSource(args, 'workspace')) return {
235
278
  ...packageSource,
236
279
  strategy: 'workspace',
237
280
  modernPackageVersion: WORKSPACE_PACKAGE_VERSION
@@ -246,7 +289,8 @@ function runSetupCommand(command, args, options = {}) {
246
289
  'ignore',
247
290
  'pipe',
248
291
  'pipe'
249
- ]
292
+ ],
293
+ timeout: options.timeoutMs
250
294
  });
251
295
  }
252
296
  function commandExists(command) {
@@ -261,26 +305,9 @@ function commandExists(command) {
261
305
  return false;
262
306
  }
263
307
  }
264
- function installGitForGeneratedProject() {
308
+ function assertGitAvailableForGeneratedProject() {
265
309
  if (commandExists('git')) return;
266
- const runShell = (script)=>runSetupCommand('sh', [
267
- '-lc',
268
- script
269
- ], {
270
- stdio: 'inherit'
271
- });
272
- const sudo = 'function' == typeof process.getuid && 0 === process.getuid() ? '' : 'sudo ';
273
- if (commandExists('brew')) runSetupCommand('brew', [
274
- 'install',
275
- 'git'
276
- ], {
277
- stdio: 'inherit'
278
- });
279
- else if ('linux' === process.platform && commandExists('apt-get')) runShell(`${sudo}apt-get update && ${sudo}apt-get install -y git`);
280
- else if ('linux' === process.platform && commandExists('dnf')) runShell(`${sudo}dnf install -y git`);
281
- else if ('linux' === process.platform && commandExists('yum')) runShell(`${sudo}yum install -y git`);
282
- else if ('linux' === process.platform && commandExists('apk')) runShell('apk add --no-cache git');
283
- if (!commandExists('git')) throw new Error('Git is required for UltraModern setup. Install git and rerun create, or run pnpm skills:install after installing git.');
310
+ throw new Error('Git is required for UltraModern setup. Install git yourself (for example "brew install git" or "sudo apt-get install git") and rerun create. This tool never installs system packages on your behalf.');
284
311
  }
285
312
  function isInsideGitWorkTree(targetDir) {
286
313
  try {
@@ -295,7 +322,7 @@ function isInsideGitWorkTree(targetDir) {
295
322
  }
296
323
  }
297
324
  function initializeGeneratedGitRepository(targetDir) {
298
- installGitForGeneratedProject();
325
+ assertGitAvailableForGeneratedProject();
299
326
  if (isInsideGitWorkTree(targetDir)) return;
300
327
  try {
301
328
  runSetupCommand('git', [
@@ -337,6 +364,7 @@ async function getProjectName() {
337
364
  const optionWithValue = new Set([
338
365
  '--lang',
339
366
  '-l',
367
+ BFF_RUNTIME_OPTION,
340
368
  '--ultramodern-package-source',
341
369
  '--ultramodern-package-version',
342
370
  '--ultramodern-package-registry',
@@ -350,7 +378,8 @@ async function getProjectName() {
350
378
  '-v',
351
379
  '--tailwind',
352
380
  '--no-tailwind',
353
- '--workspace',
381
+ BFF_FLAG,
382
+ WORKSPACE_PROTOCOL_FLAG,
354
383
  '--vertical',
355
384
  LEGACY_MODERN_JS_FLAG
356
385
  ]);
@@ -362,7 +391,7 @@ async function getProjectName() {
362
391
  i += 1;
363
392
  continue;
364
393
  }
365
- if (!(arg.startsWith('--lang=') || arg.startsWith('--ultramodern-package-source=') || arg.startsWith('--ultramodern-package-version=') || arg.startsWith('--ultramodern-package-registry=') || arg.startsWith('--ultramodern-package-scope=') || arg.startsWith('--ultramodern-package-name-prefix='))) positionalArgs.push(arg);
394
+ if (!(arg.startsWith('--lang=') || arg.startsWith(`${BFF_RUNTIME_OPTION}=`) || arg.startsWith('--ultramodern-package-source=') || arg.startsWith('--ultramodern-package-version=') || arg.startsWith('--ultramodern-package-registry=') || arg.startsWith('--ultramodern-package-scope=') || arg.startsWith('--ultramodern-package-name-prefix='))) positionalArgs.push(arg);
366
395
  }
367
396
  }
368
397
  if (positionalArgs.length > 1) {
@@ -404,6 +433,7 @@ async function main() {
404
433
  delegateLegacyModernJsSetup(args);
405
434
  return;
406
435
  }
436
+ detectBffRuntime(args);
407
437
  console.log(`\n${i18n.t(localeKeys.message.welcome)}\n`);
408
438
  const { name: projectName, useCurrentDir } = await getProjectName();
409
439
  const targetDir = useCurrentDir ? process.cwd() : node_path.isAbsolute(projectName) ? projectName : node_path.resolve(process.cwd(), projectName);
@@ -29,8 +29,12 @@ const EN_LOCALE = {
29
29
  optionVersion: ' -v, --version Display version information',
30
30
  optionLang: ' -l, --lang Set the language (en default; zh opt-in)',
31
31
  optionTailwind: ' --no-tailwind Disable default Tailwind CSS v4 workspace styling',
32
+ optionBff: ' --bff Keep the default Effect BFF scaffolding (every MicroVertical ships an Effect BFF)',
33
+ optionBffRuntime: ' --bff-runtime Select the BFF runtime for scaffolded MicroVerticals (supported: effect; default: effect)',
32
34
  optionWorkspace: ' --workspace Use workspace protocol for @modern-js dependencies (for local monorepo testing)',
33
35
  optionUltramodernPackageSource: ' --ultramodern-package-source Select UltraModern package source (workspace or install; BleedingDev defaults to install aliases)',
36
+ optionUltramodernPackageVersion: ' --ultramodern-package-version Pin the exact BleedingDev framework cohort for install package sources',
37
+ optionUltramodernPackageRegistry: ' --ultramodern-package-registry npm registry URL used for install package sources',
34
38
  optionUltramodernPackageScope: ' --ultramodern-package-scope Publish scope for npm alias installs (for example bleedingdev)',
35
39
  optionUltramodernPackageNamePrefix: ' --ultramodern-package-name-prefix Prefix for npm alias package names (default: modern-js-)',
36
40
  optionVertical: ' --vertical Mutate the current existing UltraModern workspace and wire a MicroVertical named <project-name>',
@@ -42,16 +46,11 @@ const EN_LOCALE = {
42
46
  example4: ' pnpm dlx @bleedingdev/modern-js-create --help',
43
47
  example5: ' pnpm dlx @bleedingdev/modern-js-create .',
44
48
  example6: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --workspace',
45
- example7: '',
46
- example8: '',
47
- example9: '',
48
- example10: '',
49
- example11: '',
50
- example12: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
49
+ example7: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
51
50
  moreInfo: '📚 Learn more: https://modernjs.dev'
52
51
  },
53
52
  version: {
54
- message: '@bleedingdev/modern-js-create version: {version}'
53
+ message: '{name} version: {version}'
55
54
  }
56
55
  };
57
56
  export { EN_LOCALE };
@@ -29,8 +29,12 @@ const ZH_LOCALE = {
29
29
  optionVersion: ' -v, --version 显示版本信息',
30
30
  optionLang: ' -l, --lang 设置语言 (默认 en;zh 需显式选择)',
31
31
  optionTailwind: ' --no-tailwind 禁用默认 Tailwind CSS v4 工作区样式',
32
+ optionBff: ' --bff 保留默认的 Effect BFF 脚手架(每个 MicroVertical 自带 Effect BFF)',
33
+ optionBffRuntime: ' --bff-runtime 选择 MicroVertical 脚手架的 BFF 运行时(支持: effect;默认: effect)',
32
34
  optionWorkspace: ' --workspace 对 @modern-js 依赖使用 workspace 协议(用于本地 monorepo 联调)',
33
35
  optionUltramodernPackageSource: ' --ultramodern-package-source 选择 UltraModern 依赖来源(workspace 或 install;BleedingDev 默认使用 install alias)',
36
+ optionUltramodernPackageVersion: ' --ultramodern-package-version 为 install 依赖来源固定精确的 BleedingDev 框架版本',
37
+ optionUltramodernPackageRegistry: ' --ultramodern-package-registry install 依赖来源使用的 npm registry 地址',
34
38
  optionUltramodernPackageScope: ' --ultramodern-package-scope npm alias 安装使用的发布 scope(例如 bleedingdev)',
35
39
  optionUltramodernPackageNamePrefix: ' --ultramodern-package-name-prefix npm alias 包名前缀(默认:modern-js-)',
36
40
  optionVertical: ' --vertical 修改当前已有的 UltraModern 工作区,并接入名为 <项目名称> 的 MicroVertical',
@@ -42,16 +46,11 @@ const ZH_LOCALE = {
42
46
  example4: ' pnpm dlx @bleedingdev/modern-js-create --help',
43
47
  example5: ' pnpm dlx @bleedingdev/modern-js-create .',
44
48
  example6: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --workspace',
45
- example7: '',
46
- example8: '',
47
- example9: '',
48
- example10: '',
49
- example11: '',
50
- example12: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
49
+ example7: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
51
50
  moreInfo: '📚 更多信息: https://modernjs.dev'
52
51
  },
53
52
  version: {
54
- message: '@bleedingdev/modern-js-create 版本: {version}'
53
+ message: '{name} 版本: {version}'
55
54
  }
56
55
  };
57
56
  export { ZH_LOCALE };