@bleedingdev/modern-js-create 3.2.0-ultramodern.12 → 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 (165) hide show
  1. package/README.md +167 -72
  2. package/bin/run.js +0 -0
  3. package/dist/cjs/create-package-root.cjs +63 -0
  4. package/dist/cjs/index.cjs +528 -0
  5. package/dist/cjs/locale/en.cjs +93 -0
  6. package/dist/cjs/locale/index.cjs +50 -0
  7. package/dist/cjs/locale/zh.cjs +93 -0
  8. package/dist/cjs/ultramodern-package-source.cjs +135 -0
  9. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +337 -0
  10. package/dist/cjs/ultramodern-workspace/app-files.cjs +223 -0
  11. package/dist/cjs/ultramodern-workspace/contracts.cjs +836 -0
  12. package/dist/cjs/ultramodern-workspace/demo-components.cjs +422 -0
  13. package/dist/cjs/ultramodern-workspace/descriptors.cjs +222 -0
  14. package/dist/cjs/ultramodern-workspace/effect-api.cjs +952 -0
  15. package/dist/cjs/ultramodern-workspace/fs-io.cjs +191 -0
  16. package/dist/cjs/ultramodern-workspace/index.cjs +48 -0
  17. package/dist/cjs/ultramodern-workspace/locales.cjs +173 -0
  18. package/dist/cjs/ultramodern-workspace/module-federation.cjs +487 -0
  19. package/dist/cjs/ultramodern-workspace/naming.cjs +161 -0
  20. package/dist/cjs/ultramodern-workspace/package-json.cjs +406 -0
  21. package/dist/cjs/ultramodern-workspace/package-source.cjs +59 -0
  22. package/dist/cjs/ultramodern-workspace/policy.cjs +248 -0
  23. package/dist/cjs/ultramodern-workspace/public-surface.cjs +268 -0
  24. package/dist/cjs/ultramodern-workspace/routes.cjs +375 -0
  25. package/dist/cjs/ultramodern-workspace/types.cjs +61 -0
  26. package/dist/cjs/ultramodern-workspace/versions.cjs +153 -0
  27. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +153 -0
  28. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +175 -0
  29. package/dist/esm/create-package-root.js +14 -0
  30. package/dist/esm/index.js +491 -0
  31. package/dist/esm/locale/en.js +55 -0
  32. package/dist/esm/locale/index.js +9 -0
  33. package/dist/esm/locale/zh.js +55 -0
  34. package/dist/esm/ultramodern-package-source.js +63 -0
  35. package/dist/esm/ultramodern-workspace/add-vertical.js +252 -0
  36. package/dist/esm/ultramodern-workspace/app-files.js +149 -0
  37. package/dist/esm/ultramodern-workspace/contracts.js +741 -0
  38. package/dist/esm/ultramodern-workspace/demo-components.js +363 -0
  39. package/dist/esm/ultramodern-workspace/descriptors.js +133 -0
  40. package/dist/esm/ultramodern-workspace/effect-api.js +854 -0
  41. package/dist/esm/ultramodern-workspace/fs-io.js +90 -0
  42. package/dist/esm/ultramodern-workspace/index.js +3 -0
  43. package/dist/esm/ultramodern-workspace/locales.js +122 -0
  44. package/dist/esm/ultramodern-workspace/module-federation.js +415 -0
  45. package/dist/esm/ultramodern-workspace/naming.js +71 -0
  46. package/dist/esm/ultramodern-workspace/package-json.js +338 -0
  47. package/dist/esm/ultramodern-workspace/package-source.js +21 -0
  48. package/dist/esm/ultramodern-workspace/policy.js +183 -0
  49. package/dist/esm/ultramodern-workspace/public-surface.js +183 -0
  50. package/dist/esm/ultramodern-workspace/routes.js +280 -0
  51. package/dist/esm/ultramodern-workspace/types.js +16 -0
  52. package/dist/esm/ultramodern-workspace/versions.js +34 -0
  53. package/dist/esm/ultramodern-workspace/workspace-scripts.js +91 -0
  54. package/dist/esm/ultramodern-workspace/write-workspace.js +121 -0
  55. package/dist/esm-node/create-package-root.js +15 -0
  56. package/dist/esm-node/index.js +492 -0
  57. package/dist/esm-node/locale/en.js +56 -0
  58. package/dist/esm-node/locale/index.js +10 -0
  59. package/dist/esm-node/locale/zh.js +56 -0
  60. package/dist/esm-node/ultramodern-package-source.js +64 -0
  61. package/dist/esm-node/ultramodern-workspace/add-vertical.js +253 -0
  62. package/dist/esm-node/ultramodern-workspace/app-files.js +150 -0
  63. package/dist/esm-node/ultramodern-workspace/contracts.js +742 -0
  64. package/dist/esm-node/ultramodern-workspace/demo-components.js +364 -0
  65. package/dist/esm-node/ultramodern-workspace/descriptors.js +134 -0
  66. package/dist/esm-node/ultramodern-workspace/effect-api.js +855 -0
  67. package/dist/esm-node/ultramodern-workspace/fs-io.js +91 -0
  68. package/dist/esm-node/ultramodern-workspace/index.js +4 -0
  69. package/dist/esm-node/ultramodern-workspace/locales.js +123 -0
  70. package/dist/esm-node/ultramodern-workspace/module-federation.js +416 -0
  71. package/dist/esm-node/ultramodern-workspace/naming.js +72 -0
  72. package/dist/esm-node/ultramodern-workspace/package-json.js +339 -0
  73. package/dist/esm-node/ultramodern-workspace/package-source.js +22 -0
  74. package/dist/esm-node/ultramodern-workspace/policy.js +184 -0
  75. package/dist/esm-node/ultramodern-workspace/public-surface.js +184 -0
  76. package/dist/esm-node/ultramodern-workspace/routes.js +281 -0
  77. package/dist/esm-node/ultramodern-workspace/types.js +17 -0
  78. package/dist/esm-node/ultramodern-workspace/versions.js +35 -0
  79. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +92 -0
  80. package/dist/esm-node/ultramodern-workspace/write-workspace.js +122 -0
  81. package/dist/types/create-package-root.d.ts +1 -0
  82. package/dist/types/locale/en.d.ts +8 -9
  83. package/dist/types/locale/index.d.ts +109 -2
  84. package/dist/types/locale/zh.d.ts +8 -9
  85. package/dist/types/ultramodern-package-source.d.ts +28 -0
  86. package/dist/types/ultramodern-workspace/add-vertical.d.ts +19 -0
  87. package/dist/types/ultramodern-workspace/app-files.d.ts +14 -0
  88. package/dist/types/ultramodern-workspace/contracts.d.ts +21 -0
  89. package/dist/types/ultramodern-workspace/demo-components.d.ts +9 -0
  90. package/dist/types/ultramodern-workspace/descriptors.d.ts +39 -0
  91. package/dist/types/ultramodern-workspace/effect-api.d.ts +73 -0
  92. package/dist/types/ultramodern-workspace/fs-io.d.ts +18 -0
  93. package/dist/types/ultramodern-workspace/index.d.ts +4 -0
  94. package/dist/types/ultramodern-workspace/locales.d.ts +183 -0
  95. package/dist/types/ultramodern-workspace/module-federation.d.ts +16 -0
  96. package/dist/types/ultramodern-workspace/naming.d.ts +16 -0
  97. package/dist/types/ultramodern-workspace/package-json.d.ts +12 -0
  98. package/dist/types/ultramodern-workspace/package-source.d.ts +2 -0
  99. package/dist/types/ultramodern-workspace/policy.d.ts +60 -0
  100. package/dist/types/ultramodern-workspace/public-surface.d.ts +37 -0
  101. package/dist/types/ultramodern-workspace/routes.d.ts +25 -0
  102. package/dist/types/ultramodern-workspace/types.d.ts +95 -0
  103. package/dist/types/ultramodern-workspace/versions.d.ts +38 -0
  104. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +10 -0
  105. package/dist/types/ultramodern-workspace/write-workspace.d.ts +4 -0
  106. package/package.json +34 -15
  107. package/template-workspace/.agents/agent-reference-repos.json +24 -0
  108. package/template-workspace/.agents/skills-lock.json +19 -0
  109. package/template-workspace/.codex/hooks.json +16 -0
  110. package/template-workspace/.github/renovate.json +29 -0
  111. package/template-workspace/.github/workflows/ultramodern-workspace-gates.yml.handlebars +67 -0
  112. package/template-workspace/.gitignore.handlebars +5 -0
  113. package/template-workspace/.mise.toml.handlebars +3 -0
  114. package/template-workspace/AGENTS.md.handlebars +87 -0
  115. package/template-workspace/README.md.handlebars +132 -11
  116. package/template-workspace/lefthook.yml +24 -0
  117. package/template-workspace/oxfmt.config.ts +1 -0
  118. package/template-workspace/oxlint.config.ts +1 -0
  119. package/template-workspace/pnpm-workspace.yaml.handlebars +40 -0
  120. package/template-workspace/scripts/bootstrap-agent-skills.mjs +184 -21
  121. package/template-workspace/scripts/setup-agent-reference-repos.mjs +370 -0
  122. package/templates/app/shell-frame.tsx +49 -0
  123. package/templates/app/ultramodern-route-head.tsx.handlebars +142 -0
  124. package/templates/packages/shared-contracts-index.ts +466 -0
  125. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +69 -0
  126. package/templates/workspace-scripts/check-ultramodern-i18n-boundaries.mjs +9 -0
  127. package/templates/workspace-scripts/generate-public-surface-assets.mjs +529 -0
  128. package/templates/workspace-scripts/proof-cloudflare-version.mjs +125 -0
  129. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +851 -0
  130. package/templates/workspace-scripts/ultramodern-performance-readiness.config.mjs +7 -0
  131. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +223 -0
  132. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +593 -0
  133. package/dist/index.js +0 -2626
  134. package/dist/types/ultramodern-workspace.d.ts +0 -20
  135. package/template/.agents/skills-lock.json +0 -34
  136. package/template/.browserslistrc +0 -4
  137. package/template/.github/workflows/ultramodern-gates.yml.handlebars +0 -30
  138. package/template/.gitignore.handlebars +0 -30
  139. package/template/.nvmrc +0 -2
  140. package/template/AGENTS.md +0 -25
  141. package/template/README.md +0 -79
  142. package/template/api/effect/index.ts.handlebars +0 -23
  143. package/template/api/lambda/hello.ts.handlebars +0 -6
  144. package/template/config/public/locales/cs/translation.json +0 -39
  145. package/template/config/public/locales/en/translation.json +0 -39
  146. package/template/modern.config.ts.handlebars +0 -53
  147. package/template/oxfmt.config.ts +0 -8
  148. package/template/oxlint.config.ts +0 -12
  149. package/template/package.json.handlebars +0 -67
  150. package/template/postcss.config.mjs.handlebars +0 -6
  151. package/template/scripts/bootstrap-agent-skills.mjs +0 -95
  152. package/template/scripts/check-i18n-strings.mjs +0 -83
  153. package/template/scripts/validate-ultramodern.mjs.handlebars +0 -178
  154. package/template/shared/effect/api.ts.handlebars +0 -17
  155. package/template/src/modern-app-env.d.ts +0 -1
  156. package/template/src/modern.runtime.ts.handlebars +0 -23
  157. package/template/src/routes/index.css.handlebars +0 -129
  158. package/template/src/routes/layout.tsx.handlebars +0 -9
  159. package/template/src/routes/page.tsx.handlebars +0 -155
  160. package/template/tailwind.config.ts.handlebars +0 -10
  161. package/template/tsconfig.json +0 -120
  162. package/template-workspace/AGENTS.md +0 -50
  163. package/template-workspace/pnpm-workspace.yaml +0 -17
  164. package/template-workspace/scripts/check-i18n-strings.mjs +0 -83
  165. package/template-workspace/scripts/validate-ultramodern-workspace.mjs.handlebars +0 -433
@@ -0,0 +1,56 @@
1
+ import "node:module";
2
+ const EN_LOCALE = {
3
+ prompt: {
4
+ projectName: 'Please enter project name: ',
5
+ legacyModernJsConfirmation: 'Type "{confirmation}" to continue with the original Modern.js setup: '
6
+ },
7
+ error: {
8
+ projectNameEmpty: 'Error: Project name cannot be empty',
9
+ directoryExists: 'Error: Directory "{projectName}" already exists and is not empty',
10
+ legacyModernJsNotConfirmed: 'Aborted. UltraModern.js remains the default unattended setup.',
11
+ createFailed: 'Error creating project:'
12
+ },
13
+ message: {
14
+ welcome: '🚀 Welcome to UltraModern.js',
15
+ success: '✨ Created successfully!',
16
+ nextSteps: '📋 Next steps:',
17
+ step1: 'cd {projectName}',
18
+ step2: 'pnpm install',
19
+ step3: 'pnpm dev',
20
+ 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!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
21
+ },
22
+ help: {
23
+ title: '🚀 UltraModern.js Project Creator',
24
+ description: 'Create a new UltraModern.js SuperApp workspace with the full quality baseline by default',
25
+ usage: '📖 Usage:',
26
+ usageExample: ' pnpm dlx @bleedingdev/modern-js-create [project-name] [options]',
27
+ options: '⚙️ Options:',
28
+ optionHelp: ' -h, --help Display this help message',
29
+ optionVersion: ' -v, --version Display version information',
30
+ optionLang: ' -l, --lang Set the language (en default; zh opt-in)',
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)',
34
+ optionWorkspace: ' --workspace Use workspace protocol for @modern-js dependencies (for local monorepo testing)',
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',
38
+ optionUltramodernPackageScope: ' --ultramodern-package-scope Publish scope for npm alias installs (for example bleedingdev)',
39
+ optionUltramodernPackageNamePrefix: ' --ultramodern-package-name-prefix Prefix for npm alias package names (default: modern-js-)',
40
+ optionVertical: ' --vertical Mutate the current existing UltraModern workspace and wire a MicroVertical named <project-name>',
41
+ optionLegacyModernJs: ' --legacy-modern-js Opt into the original Modern.js setup after a large warning and typed confirmation',
42
+ examples: '💡 Examples:',
43
+ example1: ' pnpm dlx @bleedingdev/modern-js-create my-workspace',
44
+ example2: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --lang zh',
45
+ example3: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --no-tailwind',
46
+ example4: ' pnpm dlx @bleedingdev/modern-js-create --help',
47
+ example5: ' pnpm dlx @bleedingdev/modern-js-create .',
48
+ example6: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --workspace',
49
+ example7: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
50
+ moreInfo: '📚 Learn more: https://modernjs.dev'
51
+ },
52
+ version: {
53
+ message: '{name} version: {version}'
54
+ }
55
+ };
56
+ export { EN_LOCALE };
@@ -0,0 +1,10 @@
1
+ import "node:module";
2
+ import { I18n } from "@modern-js/i18n-utils";
3
+ import { EN_LOCALE } from "./en.js";
4
+ import { ZH_LOCALE } from "./zh.js";
5
+ const i18n = new I18n();
6
+ const localeKeys = i18n.init('en', {
7
+ zh: ZH_LOCALE,
8
+ en: EN_LOCALE
9
+ });
10
+ export { i18n, localeKeys };
@@ -0,0 +1,56 @@
1
+ import "node:module";
2
+ const ZH_LOCALE = {
3
+ prompt: {
4
+ projectName: '请输入项目名称: ',
5
+ legacyModernJsConfirmation: '输入 "{confirmation}" 以继续使用原始 Modern.js 初始化: '
6
+ },
7
+ error: {
8
+ projectNameEmpty: '错误: 项目名称不能为空',
9
+ directoryExists: '错误: 目录 "{projectName}" 已存在且不为空',
10
+ legacyModernJsNotConfirmed: '已中止。UltraModern.js 仍是默认的免交互初始化方案。',
11
+ createFailed: '创建项目时出错:'
12
+ },
13
+ message: {
14
+ welcome: '🚀 欢迎使用 UltraModern.js',
15
+ success: '✨ 创建成功!',
16
+ nextSteps: '📋 下一步:',
17
+ step1: 'cd {projectName}',
18
+ step2: 'pnpm install',
19
+ step3: 'pnpm dev',
20
+ legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n严重警告:你正在退出 ULTRAMODERN.JS 默认配置。\n免交互默认值是最佳 UltraModern.js 配置:\n结构化 SuperApp 工作区、presetUltramodern、TanStack Router、\nEffect BFF、Tailwind CSS v4,以及 BleedingDev 包版本队列。\n原始 Modern.js 初始化是危险的显式选择路径。\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
21
+ },
22
+ help: {
23
+ title: '🚀 UltraModern.js 项目创建工具',
24
+ description: '默认创建带完整质量基线的 UltraModern.js SuperApp 工作区',
25
+ usage: '📖 用法:',
26
+ usageExample: ' pnpm dlx @bleedingdev/modern-js-create [项目名称] [选项]',
27
+ options: '⚙️ 选项:',
28
+ optionHelp: ' -h, --help 显示帮助信息',
29
+ optionVersion: ' -v, --version 显示版本信息',
30
+ optionLang: ' -l, --lang 设置语言 (默认 en;zh 需显式选择)',
31
+ optionTailwind: ' --no-tailwind 禁用默认 Tailwind CSS v4 工作区样式',
32
+ optionBff: ' --bff 保留默认的 Effect BFF 脚手架(每个 MicroVertical 自带 Effect BFF)',
33
+ optionBffRuntime: ' --bff-runtime 选择 MicroVertical 脚手架的 BFF 运行时(支持: effect;默认: effect)',
34
+ optionWorkspace: ' --workspace 对 @modern-js 依赖使用 workspace 协议(用于本地 monorepo 联调)',
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 地址',
38
+ optionUltramodernPackageScope: ' --ultramodern-package-scope npm alias 安装使用的发布 scope(例如 bleedingdev)',
39
+ optionUltramodernPackageNamePrefix: ' --ultramodern-package-name-prefix npm alias 包名前缀(默认:modern-js-)',
40
+ optionVertical: ' --vertical 修改当前已有的 UltraModern 工作区,并接入名为 <项目名称> 的 MicroVertical',
41
+ optionLegacyModernJs: ' --legacy-modern-js 在大型警告和输入确认后,选择原始 Modern.js 初始化',
42
+ examples: '💡 示例:',
43
+ example1: ' pnpm dlx @bleedingdev/modern-js-create my-workspace',
44
+ example2: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --lang zh',
45
+ example3: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --no-tailwind',
46
+ example4: ' pnpm dlx @bleedingdev/modern-js-create --help',
47
+ example5: ' pnpm dlx @bleedingdev/modern-js-create .',
48
+ example6: ' pnpm dlx @bleedingdev/modern-js-create my-workspace --workspace',
49
+ example7: ' pnpm dlx @bleedingdev/modern-js-create catalog --vertical',
50
+ moreInfo: '📚 更多信息: https://modernjs.dev'
51
+ },
52
+ version: {
53
+ message: '{name} 版本: {version}'
54
+ }
55
+ };
56
+ export { ZH_LOCALE };
@@ -0,0 +1,64 @@
1
+ import "node:module";
2
+ const WORKSPACE_PACKAGE_VERSION = 'workspace:*';
3
+ const BLEEDINGDEV_CREATE_PACKAGE = '@bleedingdev/modern-js-create';
4
+ const BLEEDINGDEV_PACKAGE_SCOPE = 'bleedingdev';
5
+ const BLEEDINGDEV_PACKAGE_NAME_PREFIX = 'modern-js-';
6
+ const BLEEDINGDEV_FRAMEWORK_VERSION_ENV = 'MODERN_CREATE_ULTRAMODERN_FRAMEWORK_VERSION';
7
+ const ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES = [
8
+ '@modern-js/create',
9
+ '@modern-js/code-tools',
10
+ '@modern-js/runtime',
11
+ '@modern-js/app-tools',
12
+ '@modern-js/tsconfig',
13
+ '@modern-js/plugin-i18n',
14
+ '@modern-js/plugin-tanstack',
15
+ '@modern-js/plugin-bff',
16
+ '@modern-js/adapter-rstest'
17
+ ];
18
+ const ULTRAMODERN_WORKSPACE_MODERN_PACKAGES = [
19
+ '@modern-js/create',
20
+ '@modern-js/code-tools',
21
+ '@modern-js/app-tools',
22
+ '@modern-js/plugin-bff',
23
+ '@modern-js/plugin-i18n',
24
+ '@modern-js/plugin-tanstack',
25
+ '@modern-js/runtime'
26
+ ];
27
+ function modernPackageVersion(packageSource) {
28
+ return 'install' === packageSource.strategy ? packageSource.modernPackageVersion : WORKSPACE_PACKAGE_VERSION;
29
+ }
30
+ function modernAliasPackageName(packageName, packageSource) {
31
+ if (!packageSource.aliasScope) return packageName;
32
+ const scope = packageSource.aliasScope.replace(/^@/, '');
33
+ const unscopedName = packageName.split('/').at(-1);
34
+ return `@${scope}/${packageSource.aliasPackageNamePrefix ?? ''}${unscopedName}`;
35
+ }
36
+ function modernPackageSpecifier(packageName, packageSource) {
37
+ if ('install' !== packageSource.strategy) return WORKSPACE_PACKAGE_VERSION;
38
+ if (!packageSource.aliasScope) return packageSource.modernPackageVersion;
39
+ return `npm:${modernAliasPackageName(packageName, packageSource)}@${packageSource.modernPackageVersion}`;
40
+ }
41
+ function modernPackageAliases(packageNames, packageSource) {
42
+ if (!packageSource.aliasScope) return;
43
+ return Object.fromEntries(packageNames.map((packageName)=>[
44
+ packageName,
45
+ modernAliasPackageName(packageName, packageSource)
46
+ ]));
47
+ }
48
+ function createModernPackagesMetadata(packageNames, packageSource, options = {}) {
49
+ const includeAliases = options.includeAliases ?? Boolean(packageSource.aliasScope);
50
+ const aliases = includeAliases ? modernPackageAliases(packageNames, packageSource) : void 0;
51
+ return {
52
+ packages: [
53
+ ...packageNames
54
+ ],
55
+ specifier: modernPackageVersion(packageSource),
56
+ ...packageSource.registry ? {
57
+ registry: packageSource.registry
58
+ } : {},
59
+ ...aliases ? {
60
+ aliases
61
+ } : {}
62
+ };
63
+ }
64
+ export { BLEEDINGDEV_CREATE_PACKAGE, BLEEDINGDEV_FRAMEWORK_VERSION_ENV, BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES, ULTRAMODERN_WORKSPACE_MODERN_PACKAGES, WORKSPACE_PACKAGE_VERSION, createModernPackagesMetadata, modernAliasPackageName, modernPackageAliases, modernPackageSpecifier, modernPackageVersion };
@@ -0,0 +1,253 @@
1
+ import "node:module";
2
+ import node_fs from "node:fs";
3
+ import node_path from "node:path";
4
+ import { WORKSPACE_PACKAGE_VERSION } from "../ultramodern-package-source.js";
5
+ import { createAppEnvDts, createAppRuntimeConfig, createShellFrameComponent } from "./app-files.js";
6
+ import { createGeneratedContract } from "./contracts.js";
7
+ import { createShellPage, createShellRemoteComponents } from "./demo-components.js";
8
+ import { GENERATED_CONTRACT_PATH, appHasEffectApi, appI18nNamespace, createModuleFederationRemoteContracts, createNeutralOwnership, createShellHost, createVerticalDescriptor, effectApiPrefix, remoteDependencyAlias, shellApp, zephyrRemoteDependency } from "./descriptors.js";
9
+ import { createShellEffectClient, effectApiTopologyMetadata } from "./effect-api.js";
10
+ import { readJsonFile, writeFileReplacing, writeJsonFile } from "./fs-io.js";
11
+ import { createAppPublicLocaleMessages } from "./locales.js";
12
+ import { createShellModuleFederationConfig } from "./module-federation.js";
13
+ import { assertUniqueTailwindPrefixes, packageName, toEnvSegment, toKebabCase, toPackageScope, toPascalCase } from "./naming.js";
14
+ import { createAppPackage, createRootPackageJson } from "./package-json.js";
15
+ import { resolvePackageSource } from "./package-source.js";
16
+ import { createCloudflareDeployContract } from "./policy.js";
17
+ import { createPublicWebAppArtifacts, rewriteWorkspaceAssetsForApp } from "./public-surface.js";
18
+ import { isRecord } from "./types.js";
19
+ import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
20
+ import { writeApp } from "./write-workspace.js";
21
+ const FIRST_VERTICAL_PORT = 4101;
22
+ function existingPackageSource(workspaceRoot, modernVersion, packageSource) {
23
+ if (packageSource) return resolvePackageSource({
24
+ targetDir: workspaceRoot,
25
+ packageName: node_path.basename(workspaceRoot),
26
+ modernVersion,
27
+ packageSource
28
+ });
29
+ const metadataPath = node_path.join(workspaceRoot, '.modernjs/ultramodern-package-source.json');
30
+ if (!node_fs.existsSync(metadataPath)) return resolvePackageSource({
31
+ targetDir: workspaceRoot,
32
+ packageName: node_path.basename(workspaceRoot),
33
+ modernVersion
34
+ });
35
+ const metadata = readJsonFile(metadataPath);
36
+ const aliases = metadata.modernPackages?.aliases ?? {};
37
+ const firstAlias = Object.values(aliases).find((value)=>'string' == typeof value);
38
+ const firstPackage = Object.keys(aliases)[0];
39
+ const aliasScope = firstAlias?.match(/^@([^/]+)\//)?.[1];
40
+ const unscopedName = firstPackage?.split('/').at(-1) ?? '';
41
+ const aliasUnscopedName = firstAlias?.split('/').at(-1) ?? '';
42
+ const aliasPackageNamePrefix = aliasUnscopedName && unscopedName && aliasUnscopedName.endsWith(unscopedName) ? aliasUnscopedName.slice(0, -unscopedName.length) : void 0;
43
+ return {
44
+ strategy: 'install' === metadata.strategy ? 'install' : 'workspace',
45
+ modernPackageVersion: 'string' == typeof metadata.modernPackages?.specifier ? metadata.modernPackages.specifier : modernVersion,
46
+ registry: metadata.modernPackages?.registry,
47
+ aliasScope,
48
+ aliasPackageNamePrefix
49
+ };
50
+ }
51
+ function existingTailwindEnabled(workspaceRoot) {
52
+ const contractPath = node_path.join(workspaceRoot, GENERATED_CONTRACT_PATH);
53
+ if (!node_fs.existsSync(contractPath)) return true;
54
+ const contract = readJsonFile(contractPath);
55
+ const apps = isRecord(contract) && Array.isArray(contract.apps) ? contract.apps : [];
56
+ const shell = apps.find((app)=>isRecord(app) && app.id === shellApp.id);
57
+ return shell?.styling && isRecord(shell.styling) ? false !== shell.styling.tailwind : true;
58
+ }
59
+ function assertValidVerticalName(name) {
60
+ const normalized = toKebabCase(name);
61
+ if (!normalized || normalized !== name) throw new Error(`Invalid Vertical name "${name}". Use lowercase kebab-case.`);
62
+ return normalized;
63
+ }
64
+ function nextAvailablePort(ports) {
65
+ const numericPorts = Object.values(ports).filter((value)=>'number' == typeof value && Number.isFinite(value));
66
+ return Math.max(FIRST_VERTICAL_PORT - 1, ...numericPorts) + 1;
67
+ }
68
+ function assertCanCreate(workspaceRoot, relativePath) {
69
+ if (node_fs.existsSync(node_path.join(workspaceRoot, relativePath))) throw new Error(`Refusing to overwrite existing path: ${relativePath}`);
70
+ }
71
+ function updateRootWorkspaceScripts(workspaceRoot, scope, packageSource, remotes) {
72
+ const packagePath = node_path.join(workspaceRoot, 'package.json');
73
+ const rootPackage = readJsonFile(packagePath);
74
+ const generatedRootPackage = createRootPackageJson(scope, packageSource, remotes);
75
+ rootPackage.scripts = generatedRootPackage.scripts;
76
+ writeJsonFile(packagePath, rootPackage);
77
+ }
78
+ function rewriteShellAppFiles(workspaceRoot, scope, packageSource, enableTailwind, remotes) {
79
+ const shellHost = createShellHost(remotes);
80
+ const publicWeb = createPublicWebAppArtifacts(shellHost);
81
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/package.json`), createAppPackage(scope, shellHost, packageSource, enableTailwind, remotes));
82
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern-app-env.d.ts`, createAppEnvDts(shellHost, remotes));
83
+ writeFileReplacing(workspaceRoot, publicWeb.jsonLdHelperFile.path, publicWeb.jsonLdHelperFile.content);
84
+ writeFileReplacing(workspaceRoot, publicWeb.routeMetadataFile.path, publicWeb.routeMetadataFile.content);
85
+ writeFileReplacing(workspaceRoot, publicWeb.routeHeadFile.path, publicWeb.routeHeadFile.content);
86
+ for (const generatedFile of publicWeb.routeMetaFiles)writeFileReplacing(workspaceRoot, generatedFile.path, generatedFile.content);
87
+ rewriteWorkspaceAssetsForApp(workspaceRoot, shellHost);
88
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/modern.runtime.ts`, createAppRuntimeConfig(shellHost, scope, remotes));
89
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/locales/en/translation.json`), createAppPublicLocaleMessages(shellHost, 'en', remotes));
90
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/locales/en/${appI18nNamespace(shellHost)}.json`), createAppPublicLocaleMessages(shellHost, 'en', remotes));
91
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/locales/cs/translation.json`), createAppPublicLocaleMessages(shellHost, 'cs', remotes));
92
+ writeJsonFile(node_path.join(workspaceRoot, `${shellApp.directory}/locales/cs/${appI18nNamespace(shellHost)}.json`), createAppPublicLocaleMessages(shellHost, 'cs', remotes));
93
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/module-federation.config.ts`, createShellModuleFederationConfig(scope, remotes));
94
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/routes/[lang]/page.tsx`, createShellPage(remotes));
95
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/routes/vertical-components.tsx`, createShellRemoteComponents(scope, remotes));
96
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/routes/shell-frame.tsx`, createShellFrameComponent());
97
+ writeFileReplacing(workspaceRoot, `${shellApp.directory}/src/effect/vertical-clients.ts`, createShellEffectClient(scope, remotes));
98
+ }
99
+ function addShellZephyrDependency(workspaceRoot, scope, remote) {
100
+ const packagePath = node_path.join(workspaceRoot, shellApp.directory, 'package.json');
101
+ const shellPackage = readJsonFile(packagePath);
102
+ shellPackage['zephyr:dependencies'] ??= {};
103
+ shellPackage['zephyr:dependencies'][remoteDependencyAlias(remote)] = zephyrRemoteDependency(scope, remote);
104
+ writeJsonFile(packagePath, shellPackage);
105
+ }
106
+ function addShellWorkspaceDependency(workspaceRoot, scope, remote) {
107
+ if (!appHasEffectApi(remote)) return;
108
+ const packagePath = node_path.join(workspaceRoot, shellApp.directory, 'package.json');
109
+ const shellPackage = readJsonFile(packagePath);
110
+ shellPackage.dependencies ??= {};
111
+ shellPackage.dependencies[packageName(scope, remote.packageSuffix)] = WORKSPACE_PACKAGE_VERSION;
112
+ writeJsonFile(packagePath, shellPackage);
113
+ }
114
+ function verticalTopologyEntry(scope, vertical, remotes = []) {
115
+ return {
116
+ id: vertical.id,
117
+ kind: vertical.kind,
118
+ domain: vertical.domain,
119
+ package: packageName(scope, vertical.packageSuffix),
120
+ path: vertical.directory,
121
+ moduleFederation: {
122
+ role: 'remote',
123
+ name: vertical.mfName,
124
+ manifestUrl: `http://localhost:${vertical.port}/mf-manifest.json`,
125
+ exposes: Object.keys(vertical.exposes ?? {}),
126
+ ...vertical.verticalRefs?.length ? {
127
+ verticalRefs: vertical.verticalRefs,
128
+ remotes: createModuleFederationRemoteContracts(vertical, remotes)
129
+ } : {},
130
+ ssr: true,
131
+ fallbackTelemetryEvent: 'modernjs:mv-runtime-parity',
132
+ sharedContractVersion: 'mf-ssr-contract-v1'
133
+ },
134
+ ...effectApiTopologyMetadata(vertical) ? {
135
+ api: effectApiTopologyMetadata(vertical)
136
+ } : {},
137
+ cloudflare: createCloudflareDeployContract(scope, vertical),
138
+ ownership: vertical.ownership
139
+ };
140
+ }
141
+ function ownershipEntry(scope, owner) {
142
+ return {
143
+ id: owner.id,
144
+ package: packageName(scope, owner.packageSuffix),
145
+ path: owner.directory,
146
+ ownership: owner.ownership
147
+ };
148
+ }
149
+ function verticalsFromTopology(topology, ports) {
150
+ return (topology.verticals ?? []).map((vertical)=>{
151
+ const domain = vertical.domain ?? String(vertical.id);
152
+ const packageSuffix = vertical.package?.split('/').at(-1) ?? domain;
153
+ const effectApi = vertical.api?.effect ? {
154
+ stem: 'string' == typeof vertical.api.effect.basePath ? vertical.api.effect.basePath.split('/').filter(Boolean).at(-1) ?? domain : domain,
155
+ prefix: vertical.api.effect.bff?.prefix ?? `/${domain}-api`,
156
+ consumedBy: Array.isArray(vertical.api.effect.consumedBy) ? vertical.api.effect.consumedBy : [
157
+ shellApp.id,
158
+ vertical.id
159
+ ]
160
+ } : void 0;
161
+ return {
162
+ id: vertical.id,
163
+ directory: 'string' == typeof vertical.path ? vertical.path : `verticals/${domain}`,
164
+ packageSuffix,
165
+ displayName: vertical.displayName ?? `${toPascalCase(domain)} Vertical`,
166
+ kind: 'vertical',
167
+ domain,
168
+ portEnv: `VERTICAL_${toEnvSegment(domain)}_PORT`,
169
+ port: 'number' == typeof ports[vertical.id] ? ports[vertical.id] : 0,
170
+ mfName: vertical.moduleFederation?.name ?? `vertical${toPascalCase(domain)}`,
171
+ ...Array.isArray(vertical.moduleFederation?.exposes) ? {
172
+ exposes: Object.fromEntries(vertical.moduleFederation.exposes.map((expose)=>[
173
+ expose,
174
+ './Route' === expose ? './src/federation-entry.tsx' : './Widget' === expose ? `./src/components/${domain}-widget.tsx` : ''
175
+ ]))
176
+ } : {},
177
+ ...Array.isArray(vertical.moduleFederation?.verticalRefs) ? {
178
+ verticalRefs: vertical.moduleFederation.verticalRefs
179
+ } : Array.isArray(vertical.moduleFederation?.remotes) ? {
180
+ verticalRefs: vertical.moduleFederation.remotes.map((entry)=>entry.id).filter((id)=>'string' == typeof id)
181
+ } : {},
182
+ ...effectApi ? {
183
+ effectApi
184
+ } : {},
185
+ ownership: vertical.ownership ?? createNeutralOwnership(vertical.id)
186
+ };
187
+ });
188
+ }
189
+ function addUltramodernVertical(options) {
190
+ const name = assertValidVerticalName(options.name);
191
+ const rootPackage = readJsonFile(node_path.join(options.workspaceRoot, 'package.json'));
192
+ const scope = toPackageScope(String(rootPackage.name ?? node_path.basename(options.workspaceRoot)));
193
+ const topologyPath = node_path.join(options.workspaceRoot, 'topology/reference-topology.json');
194
+ const ownershipPath = node_path.join(options.workspaceRoot, 'topology/ownership.json');
195
+ const overlayPath = node_path.join(options.workspaceRoot, 'topology/local-overlays/development.json');
196
+ for (const requiredPath of [
197
+ topologyPath,
198
+ ownershipPath,
199
+ overlayPath
200
+ ])if (!node_fs.existsSync(requiredPath)) throw new Error(`Missing UltraModern workspace file: ${requiredPath}`);
201
+ const topology = readJsonFile(topologyPath);
202
+ const ownership = readJsonFile(ownershipPath);
203
+ const overlay = readJsonFile(overlayPath);
204
+ overlay.ports ??= {};
205
+ const packageSource = existingPackageSource(options.workspaceRoot, options.modernVersion, options.packageSource);
206
+ const enableTailwind = options.enableTailwind ?? existingTailwindEnabled(options.workspaceRoot);
207
+ const port = nextAvailablePort(overlay.ports);
208
+ const vertical = createVerticalDescriptor(name, port);
209
+ assertCanCreate(options.workspaceRoot, vertical.directory);
210
+ if ((topology.verticals ?? []).some((entry)=>entry.id === vertical.id)) throw new Error(`Topology already contains ${vertical.id}`);
211
+ if (Object.values(overlay.ports).includes(vertical.port)) throw new Error(`Development port ${vertical.port} is already in use`);
212
+ writeApp(options.workspaceRoot, scope, vertical, packageSource, enableTailwind);
213
+ topology.shell ??= {};
214
+ topology.shell.verticalRefs ??= [];
215
+ topology.shell.verticalRefs.push(vertical.id);
216
+ topology.shell.moduleFederation ??= {};
217
+ topology.shell.moduleFederation.remotes ??= [];
218
+ topology.shell.moduleFederation.remotes.push({
219
+ id: vertical.id,
220
+ name: vertical.mfName,
221
+ manifestUrl: `http://localhost:${vertical.port}/mf-manifest.json`
222
+ });
223
+ topology.verticals ??= [];
224
+ topology.verticals.push(verticalTopologyEntry(scope, vertical));
225
+ ownership.owners ??= [];
226
+ ownership.owners.push(ownershipEntry(scope, vertical));
227
+ overlay.ports[vertical.id] = vertical.port;
228
+ overlay.manifests ??= {};
229
+ overlay.manifests[vertical.id] = `http://localhost:${vertical.port}/mf-manifest.json`;
230
+ overlay.apis ??= {};
231
+ overlay.apis[vertical.id] = `http://localhost:${vertical.port}${effectApiPrefix(vertical)}`;
232
+ writeJsonFile(topologyPath, topology);
233
+ writeJsonFile(ownershipPath, ownership);
234
+ writeJsonFile(overlayPath, overlay);
235
+ const updatedVerticals = verticalsFromTopology(topology, overlay.ports);
236
+ assertUniqueTailwindPrefixes([
237
+ shellApp,
238
+ ...updatedVerticals
239
+ ]);
240
+ writeJsonFile(node_path.join(options.workspaceRoot, GENERATED_CONTRACT_PATH), createGeneratedContract(scope, [
241
+ {
242
+ ...shellApp,
243
+ verticalRefs: updatedVerticals.map((vertical)=>vertical.id)
244
+ },
245
+ ...updatedVerticals
246
+ ], enableTailwind));
247
+ rewriteShellAppFiles(options.workspaceRoot, scope, packageSource, enableTailwind, updatedVerticals);
248
+ writeGeneratedWorkspaceScripts(options.workspaceRoot, scope, enableTailwind, updatedVerticals);
249
+ addShellZephyrDependency(options.workspaceRoot, scope, vertical);
250
+ addShellWorkspaceDependency(options.workspaceRoot, scope, vertical);
251
+ updateRootWorkspaceScripts(options.workspaceRoot, scope, packageSource, updatedVerticals);
252
+ }
253
+ export { addShellWorkspaceDependency, addShellZephyrDependency, addUltramodernVertical, assertCanCreate, assertValidVerticalName, existingPackageSource, existingTailwindEnabled, nextAvailablePort, ownershipEntry, rewriteShellAppFiles, updateRootWorkspaceScripts, verticalTopologyEntry, verticalsFromTopology };
@@ -0,0 +1,150 @@
1
+ import "node:module";
2
+ import { appI18nNamespace, remoteDependencyAlias, resolveRemoteRefs, shellApp } from "./descriptors.js";
3
+ import { readFileTemplate, renderFileTemplate } from "./fs-io.js";
4
+ import { packageName, tailwindPrefixForApp } from "./naming.js";
5
+ function createBoundaryDebugMetadata(scope, remotes = []) {
6
+ return {
7
+ appId: shellApp.id,
8
+ boundaries: [
9
+ shellApp,
10
+ ...remotes
11
+ ].map((app)=>({
12
+ appId: app.id,
13
+ label: app.displayName,
14
+ mfName: app.mfName,
15
+ ownerTeam: app.ownership.team,
16
+ packageName: packageName(scope, app.packageSuffix),
17
+ role: 'shell' === app.kind ? 'host' : 'vertical'
18
+ })),
19
+ schemaVersion: 1
20
+ };
21
+ }
22
+ function createAppEnvDts(app, remotes = []) {
23
+ const remoteModuleDeclarations = resolveRemoteRefs(app, remotes).flatMap((remote)=>Object.keys(remote.exposes ?? {}).filter((expose)=>'./Route' !== expose).map((expose)=>{
24
+ const moduleName = `${remoteDependencyAlias(remote)}/${expose.replace(/^\.\//u, '')}`;
25
+ return `declare module '${moduleName}' {
26
+ const Component: React.ComponentType<Record<string, never>>;
27
+ export default Component;
28
+ }
29
+ `;
30
+ })).join('\n');
31
+ const reactTypeReference = remoteModuleDeclarations ? "/// <reference types='react' />\n" : '';
32
+ const siteUrlDeclaration = 'declare const ULTRAMODERN_SITE_URL: string;';
33
+ return `${reactTypeReference}/// <reference types='@modern-js/app-tools/types' />
34
+
35
+ ${siteUrlDeclaration}
36
+ declare module '*.svg' {
37
+ const url: string;
38
+ export default url;
39
+ }
40
+ declare module '*.css';
41
+ ${remoteModuleDeclarations ? `\n${remoteModuleDeclarations}` : ''}`;
42
+ }
43
+ function createAppRuntimeConfig(app, scope, remotes = []) {
44
+ const pluginsConfig = 'shell' === app.kind ? ` plugins: [
45
+ ultramodernBoundaryDebuggerPlugin({
46
+ metadata: ${JSON.stringify(createBoundaryDebugMetadata(scope, remotes), null, 6).split('\n').join('\n ')},
47
+ }),
48
+ ],
49
+ ` : '';
50
+ return `import { defineRuntimeConfig } from '@modern-js/runtime';
51
+ ${'shell' === app.kind ? "import { ultramodernBoundaryDebuggerPlugin } from '@modern-js/runtime/boundary-debugger';\n" : ''}import { createInstance } from 'i18next';
52
+ import csResource from '../locales/cs/${appI18nNamespace(app)}.json';
53
+ import enResource from '../locales/en/${appI18nNamespace(app)}.json';
54
+ import { ultramodernRouteNamespace } from './routes/ultramodern-route-metadata';
55
+
56
+ type LocaleResource = string | { readonly [key: string]: LocaleResource };
57
+
58
+ const flattenLocaleResource = (
59
+ resource: LocaleResource,
60
+ prefix = '',
61
+ ): Record<string, string> => {
62
+ if (typeof resource === 'string') {
63
+ return prefix.length > 0 ? { [prefix]: resource } : {};
64
+ }
65
+
66
+ return Object.fromEntries(
67
+ Object.entries(resource).flatMap(([key, value]) => {
68
+ const nextKey = prefix.length > 0 ? \`\${prefix}.\${key}\` : key;
69
+ return typeof value === 'string'
70
+ ? [[nextKey, value]]
71
+ : Object.entries(flattenLocaleResource(value, nextKey));
72
+ }),
73
+ );
74
+ };
75
+
76
+ const i18nInstance = createInstance();
77
+ const resources = {
78
+ cs: { [ultramodernRouteNamespace]: flattenLocaleResource(csResource) },
79
+ en: { [ultramodernRouteNamespace]: flattenLocaleResource(enResource) },
80
+ } as const;
81
+
82
+ export default defineRuntimeConfig({
83
+ i18n: {
84
+ i18nInstance,
85
+ initOptions: {
86
+ defaultNS: ultramodernRouteNamespace,
87
+ fallbackLng: 'en',
88
+ interpolation: {
89
+ escapeValue: false,
90
+ },
91
+ ns: [ultramodernRouteNamespace, 'translation'],
92
+ resources,
93
+ supportedLngs: ['en', 'cs'],
94
+ },
95
+ },
96
+ ${pluginsConfig}
97
+ router: {
98
+ framework: 'tanstack',
99
+ },
100
+ });
101
+ `;
102
+ }
103
+ function createCssTokenImport(scope) {
104
+ return `@import '${packageName(scope, 'shared-design-tokens')}/tokens.css';\n`;
105
+ }
106
+ function createTailwindImport(prefix) {
107
+ return `@import 'tailwindcss' prefix(${prefix}) source(none);\n@source '..';\n`;
108
+ }
109
+ function createShellStyles(enableTailwind, scope) {
110
+ return `${enableTailwind ? createTailwindImport(tailwindPrefixForApp(shellApp)) : ''}${createCssTokenImport(scope)}`;
111
+ }
112
+ function createRemoteStyles(enableTailwind, scope, app) {
113
+ return `${enableTailwind ? createTailwindImport(tailwindPrefixForApp(app)) : ''}${createCssTokenImport(scope)}`;
114
+ }
115
+ function createAppStyles(enableTailwind, scope, app) {
116
+ return 'shell' === app.kind ? createShellStyles(enableTailwind, scope) : createRemoteStyles(enableTailwind, scope, app);
117
+ }
118
+ function createPostcssConfig() {
119
+ return `export default {
120
+ plugins: {
121
+ '@tailwindcss/postcss': {},
122
+ },
123
+ };
124
+ `;
125
+ }
126
+ function createTailwindConfig() {
127
+ return `import type { Config } from 'tailwindcss';
128
+
129
+ export default {} satisfies Config;
130
+ `;
131
+ }
132
+ function createSharedDesignTokensCss() {
133
+ return `@theme {
134
+ --color-um-accent: #2f8f68;
135
+ --color-um-canvas: #f1eadc;
136
+ --color-um-foreground: #133225;
137
+ --color-um-link: #166b4b;
138
+ --color-um-surface: #f6fbf7;
139
+ }
140
+ `;
141
+ }
142
+ function createRouteHeadModule(app) {
143
+ return renderFileTemplate('app/ultramodern-route-head.tsx', {
144
+ appDisplayNameJson: JSON.stringify(app.displayName)
145
+ });
146
+ }
147
+ function createShellFrameComponent() {
148
+ return readFileTemplate('app/shell-frame.tsx');
149
+ }
150
+ export { createAppEnvDts, createAppRuntimeConfig, createAppStyles, createBoundaryDebugMetadata, createCssTokenImport, createPostcssConfig, createRemoteStyles, createRouteHeadModule, createSharedDesignTokensCss, createShellFrameComponent, createShellStyles, createTailwindConfig, createTailwindImport };