zudojs-cli 2.0.1 → 2.1.1

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 (248) hide show
  1. package/README.md +59 -7
  2. package/dist/src/adapters/frontend/angular.adapter.d.ts +0 -1
  3. package/dist/src/adapters/frontend/angular.adapter.js +14 -97
  4. package/dist/src/adapters/frontend/astro.adapter.d.ts +0 -1
  5. package/dist/src/adapters/frontend/astro.adapter.js +4 -64
  6. package/dist/src/adapters/frontend/fallback/fallback.helper.d.ts +41 -0
  7. package/dist/src/adapters/frontend/fallback/fallback.helper.js +57 -0
  8. package/dist/src/adapters/frontend/fallback/framework/angular/angular.fallback.d.ts +18 -0
  9. package/dist/src/adapters/frontend/fallback/framework/angular/angular.fallback.js +107 -0
  10. package/dist/src/adapters/frontend/fallback/framework/angular/angularWorkspace.fallback.d.ts +23 -0
  11. package/dist/src/adapters/frontend/fallback/framework/angular/angularWorkspace.fallback.js +125 -0
  12. package/dist/src/adapters/frontend/fallback/framework/angular/index.d.ts +8 -0
  13. package/dist/src/adapters/frontend/fallback/framework/angular/index.js +8 -0
  14. package/dist/src/adapters/frontend/fallback/framework/astro.fallback.d.ts +14 -0
  15. package/dist/src/adapters/frontend/fallback/framework/astro.fallback.js +76 -0
  16. package/dist/src/adapters/frontend/fallback/framework/index.d.ts +13 -0
  17. package/dist/src/adapters/frontend/fallback/framework/index.js +13 -0
  18. package/dist/src/adapters/frontend/fallback/framework/next.fallback.d.ts +13 -0
  19. package/dist/src/adapters/frontend/fallback/framework/next.fallback.js +105 -0
  20. package/dist/src/adapters/frontend/fallback/framework/nuxt.fallback.d.ts +14 -0
  21. package/dist/src/adapters/frontend/fallback/framework/nuxt.fallback.js +56 -0
  22. package/dist/src/adapters/frontend/fallback/framework/sveltekit.fallback.d.ts +15 -0
  23. package/dist/src/adapters/frontend/fallback/framework/sveltekit.fallback.js +94 -0
  24. package/dist/src/adapters/frontend/fallback/index.d.ts +12 -0
  25. package/dist/src/adapters/frontend/fallback/index.js +12 -0
  26. package/dist/src/adapters/frontend/fallback/vite/index.d.ts +11 -0
  27. package/dist/src/adapters/frontend/fallback/vite/index.js +11 -0
  28. package/dist/src/adapters/frontend/fallback/vite/react.fallback.d.ts +13 -0
  29. package/dist/src/adapters/frontend/fallback/vite/react.fallback.js +77 -0
  30. package/dist/src/adapters/frontend/fallback/vite/svelte.fallback.d.ts +14 -0
  31. package/dist/src/adapters/frontend/fallback/vite/svelte.fallback.js +95 -0
  32. package/dist/src/adapters/frontend/fallback/vite/vanilla.fallback.d.ts +13 -0
  33. package/dist/src/adapters/frontend/fallback/vite/vanilla.fallback.js +71 -0
  34. package/dist/src/adapters/frontend/fallback/vite/vue.fallback.d.ts +14 -0
  35. package/dist/src/adapters/frontend/fallback/vite/vue.fallback.js +78 -0
  36. package/dist/src/adapters/frontend/next.adapter.d.ts +0 -1
  37. package/dist/src/adapters/frontend/next.adapter.js +16 -95
  38. package/dist/src/adapters/frontend/nuxt.adapter.d.ts +1 -2
  39. package/dist/src/adapters/frontend/nuxt.adapter.js +32 -43
  40. package/dist/src/adapters/frontend/react-native.adapter.js +1 -1
  41. package/dist/src/adapters/frontend/react.adapter.d.ts +0 -1
  42. package/dist/src/adapters/frontend/react.adapter.js +7 -89
  43. package/dist/src/adapters/frontend/svelte.adapter.d.ts +0 -1
  44. package/dist/src/adapters/frontend/svelte.adapter.js +4 -86
  45. package/dist/src/adapters/frontend/sveltekit.adapter.d.ts +0 -1
  46. package/dist/src/adapters/frontend/sveltekit.adapter.js +4 -57
  47. package/dist/src/adapters/frontend/vanilla.adapter.d.ts +0 -1
  48. package/dist/src/adapters/frontend/vanilla.adapter.js +4 -47
  49. package/dist/src/adapters/frontend/vue.adapter.d.ts +0 -1
  50. package/dist/src/adapters/frontend/vue.adapter.js +4 -76
  51. package/dist/src/bin/bin.menu.d.ts +22 -0
  52. package/dist/src/bin/bin.menu.js +40 -0
  53. package/dist/src/bin/bin.runner.d.ts +38 -0
  54. package/dist/src/bin/bin.runner.js +51 -0
  55. package/dist/src/bin/index.d.ts +9 -0
  56. package/dist/src/bin/index.js +9 -0
  57. package/dist/src/bin/zudojs.js +15 -4
  58. package/dist/src/cliApplication/cliApplication.core.d.ts +4 -2
  59. package/dist/src/cliApplication/cliApplication.core.js +48 -36
  60. package/dist/src/cliApplication/cliApplication.logger.d.ts +5 -0
  61. package/dist/src/cliApplication/cliApplication.logger.js +5 -3
  62. package/dist/src/cliApplication/invocation/index.d.ts +12 -0
  63. package/dist/src/cliApplication/invocation/index.js +12 -0
  64. package/dist/src/cliApplication/invocation/invocation.hint.d.ts +30 -0
  65. package/dist/src/cliApplication/invocation/invocation.hint.js +74 -0
  66. package/dist/src/cliApplication/invocation/invocation.locate.d.ts +34 -0
  67. package/dist/src/cliApplication/invocation/invocation.locate.js +53 -0
  68. package/dist/src/cliApplication/invocation/invocation.name.d.ts +37 -0
  69. package/dist/src/cliApplication/invocation/invocation.name.js +69 -0
  70. package/dist/src/cliApplication/invocation/invocation.sanitize.d.ts +19 -0
  71. package/dist/src/cliApplication/invocation/invocation.sanitize.js +32 -0
  72. package/dist/src/cliParser/cliParser.core.js +3 -1
  73. package/dist/src/cliParser/cliParser.helper.d.ts +7 -0
  74. package/dist/src/cliParser/cliParser.helper.js +19 -2
  75. package/dist/src/cliParser/cliParser.longOption.js +2 -2
  76. package/dist/src/commands/add.command.d.ts +7 -3
  77. package/dist/src/commands/add.command.js +96 -57
  78. package/dist/src/commands/create.command.js +29 -42
  79. package/dist/src/commands/doctor.command.d.ts +2 -1
  80. package/dist/src/commands/doctor.command.js +52 -4
  81. package/dist/src/commands/generate.command.js +31 -16
  82. package/dist/src/commands/info.command.js +11 -1
  83. package/dist/src/constants/index.d.ts +21 -3
  84. package/dist/src/constants/index.js +40 -5
  85. package/dist/src/constants/zudojsVersions.generated.d.ts +9 -0
  86. package/dist/src/constants/zudojsVersions.generated.js +48 -0
  87. package/dist/src/constants/zudojsVersions.helper.d.ts +21 -0
  88. package/dist/src/constants/zudojsVersions.helper.js +29 -0
  89. package/dist/src/generators/frontend/frontendGenerator.core.js +9 -10
  90. package/dist/src/generators/frontend/frontendPipeline.d.ts +6 -1
  91. package/dist/src/generators/frontend/frontendPipeline.js +9 -1
  92. package/dist/src/generators/fullstack/fullstackComposer.core.js +7 -1
  93. package/dist/src/generators/index.d.ts +1 -2
  94. package/dist/src/generators/index.js +1 -2
  95. package/dist/src/generators/infrastructure/infrastructure.generator.js +13 -5
  96. package/dist/src/generators/integration/integrationGenerator.core.d.ts +2 -0
  97. package/dist/src/generators/integration/integrationGenerator.core.js +31 -2
  98. package/dist/src/generators/module/module.generator.js +36 -4
  99. package/dist/src/generators/resource/index.d.ts +8 -0
  100. package/dist/src/generators/resource/index.js +8 -0
  101. package/dist/src/generators/resource/resource.generator.d.ts +27 -0
  102. package/dist/src/generators/resource/resource.generator.js +87 -0
  103. package/dist/src/generators/resource/resource.layout.d.ts +26 -0
  104. package/dist/src/generators/resource/resource.layout.js +46 -0
  105. package/dist/src/generators/resource/resource.plan.d.ts +27 -0
  106. package/dist/src/generators/resource/resource.plan.js +46 -0
  107. package/dist/src/generators/resource/resource.run.d.ts +25 -0
  108. package/dist/src/generators/resource/resource.run.js +52 -0
  109. package/dist/src/prompts/cancel.prompt.d.ts +5 -1
  110. package/dist/src/prompts/cancel.prompt.js +4 -0
  111. package/dist/src/prompts/menu/index.d.ts +13 -0
  112. package/dist/src/prompts/menu/index.js +13 -0
  113. package/dist/src/prompts/menu/menu.adapter.d.ts +16 -0
  114. package/dist/src/prompts/menu/menu.adapter.js +56 -0
  115. package/dist/src/prompts/menu/menu.constant.d.ts +20 -0
  116. package/dist/src/prompts/menu/menu.constant.js +29 -0
  117. package/dist/src/prompts/menu/menu.flow.d.ts +18 -0
  118. package/dist/src/prompts/menu/menu.flow.js +82 -0
  119. package/dist/src/prompts/menu/menu.select.d.ts +26 -0
  120. package/dist/src/prompts/menu/menu.select.js +118 -0
  121. package/dist/src/prompts/menu/menu.type.d.ts +66 -0
  122. package/dist/src/prompts/menu/menu.type.js +8 -0
  123. package/dist/src/recipes/apply/index.d.ts +9 -0
  124. package/dist/src/recipes/apply/index.js +9 -0
  125. package/dist/src/recipes/apply/recipeApply.app.d.ts +20 -0
  126. package/dist/src/recipes/apply/recipeApply.app.js +79 -0
  127. package/dist/src/recipes/apply/recipeApply.context.d.ts +14 -0
  128. package/dist/src/recipes/apply/recipeApply.context.js +76 -0
  129. package/dist/src/recipes/apply/recipeApply.files.d.ts +39 -0
  130. package/dist/src/recipes/apply/recipeApply.files.js +84 -0
  131. package/dist/src/recipes/apply/recipeApply.project.d.ts +11 -0
  132. package/dist/src/recipes/apply/recipeApply.project.js +50 -0
  133. package/dist/src/recipes/apply/recipeApply.report.d.ts +20 -0
  134. package/dist/src/recipes/apply/recipeApply.report.js +51 -0
  135. package/dist/src/recipes/catalog/database/database.files.d.ts +15 -0
  136. package/dist/src/recipes/catalog/database/database.files.js +98 -0
  137. package/dist/src/recipes/catalog/database/database.recipe.d.ts +9 -0
  138. package/dist/src/recipes/catalog/database/database.recipe.js +50 -0
  139. package/dist/src/recipes/catalog/database/index.d.ts +6 -0
  140. package/dist/src/recipes/catalog/database/index.js +6 -0
  141. package/dist/src/recipes/catalog/email.recipe.d.ts +9 -0
  142. package/dist/src/recipes/catalog/email.recipe.js +122 -0
  143. package/dist/src/recipes/catalog/index.d.ts +11 -0
  144. package/dist/src/recipes/catalog/index.js +11 -0
  145. package/dist/src/recipes/catalog/openapi.recipe.d.ts +8 -0
  146. package/dist/src/recipes/catalog/openapi.recipe.js +25 -0
  147. package/dist/src/recipes/catalog/platform/cache.recipe.d.ts +7 -0
  148. package/dist/src/recipes/catalog/platform/cache.recipe.js +55 -0
  149. package/dist/src/recipes/catalog/platform/index.d.ts +9 -0
  150. package/dist/src/recipes/catalog/platform/index.js +9 -0
  151. package/dist/src/recipes/catalog/platform/messaging.recipe.d.ts +7 -0
  152. package/dist/src/recipes/catalog/platform/messaging.recipe.js +46 -0
  153. package/dist/src/recipes/catalog/platform/observability.recipe.d.ts +8 -0
  154. package/dist/src/recipes/catalog/platform/observability.recipe.js +49 -0
  155. package/dist/src/recipes/catalog/platform/queue.recipe.d.ts +7 -0
  156. package/dist/src/recipes/catalog/platform/queue.recipe.js +61 -0
  157. package/dist/src/recipes/catalog/platform/scheduler.recipe.d.ts +7 -0
  158. package/dist/src/recipes/catalog/platform/scheduler.recipe.js +56 -0
  159. package/dist/src/recipes/catalog/redis.recipe.d.ts +8 -0
  160. package/dist/src/recipes/catalog/redis.recipe.js +79 -0
  161. package/dist/src/recipes/catalog/storage.recipe.d.ts +7 -0
  162. package/dist/src/recipes/catalog/storage.recipe.js +49 -0
  163. package/dist/src/recipes/catalog/websockets.recipe.d.ts +10 -0
  164. package/dist/src/recipes/catalog/websockets.recipe.js +84 -0
  165. package/dist/src/recipes/docker/docker.compose.d.ts +19 -0
  166. package/dist/src/recipes/docker/docker.compose.js +90 -0
  167. package/dist/src/recipes/docker/docker.recipe.d.ts +10 -0
  168. package/dist/src/recipes/docker/docker.recipe.js +51 -0
  169. package/dist/src/recipes/docker/docker.refresh.d.ts +13 -0
  170. package/dist/src/recipes/docker/docker.refresh.js +37 -0
  171. package/dist/src/recipes/docker/index.d.ts +7 -0
  172. package/dist/src/recipes/docker/index.js +7 -0
  173. package/dist/src/recipes/index.d.ts +8 -0
  174. package/dist/src/recipes/index.js +8 -0
  175. package/dist/src/recipes/recipe.registry.d.ts +17 -0
  176. package/dist/src/recipes/recipe.registry.js +46 -0
  177. package/dist/src/recipes/recipe.type.d.ts +93 -0
  178. package/dist/src/recipes/recipe.type.js +12 -0
  179. package/dist/src/resolvers/dependency/dependencyVersions.constant.d.ts +100 -5
  180. package/dist/src/resolvers/dependency/dependencyVersions.constant.js +103 -34
  181. package/dist/src/resolvers/dependency/index.d.ts +1 -1
  182. package/dist/src/resolvers/dependency/index.js +1 -1
  183. package/dist/src/resolvers/project.resolver.d.ts +14 -1
  184. package/dist/src/resolvers/project.resolver.js +11 -3
  185. package/dist/src/scaffolders/scaffolder.helper.js +12 -1
  186. package/dist/src/templates/backendApp/backendApp.core.d.ts +45 -0
  187. package/dist/src/templates/backendApp/backendApp.core.js +66 -0
  188. package/dist/src/templates/backendApp/backendApp.modules.d.ts +26 -0
  189. package/dist/src/templates/backendApp/backendApp.modules.js +25 -0
  190. package/dist/src/templates/backendApp/backendApp.project.d.ts +26 -0
  191. package/dist/src/templates/backendApp/backendApp.project.js +87 -0
  192. package/dist/src/templates/backendApp/index.d.ts +8 -0
  193. package/dist/src/templates/backendApp/index.js +8 -0
  194. package/dist/src/templates/backendApp/parts/config.template.d.ts +28 -0
  195. package/dist/src/templates/backendApp/parts/config.template.js +118 -0
  196. package/dist/src/templates/backendApp/parts/httpUtils.template.d.ts +10 -0
  197. package/dist/src/templates/backendApp/parts/httpUtils.template.js +103 -0
  198. package/dist/src/templates/backendApp/parts/index.d.ts +9 -0
  199. package/dist/src/templates/backendApp/parts/index.js +9 -0
  200. package/dist/src/templates/backendApp/parts/integrations.template.d.ts +16 -0
  201. package/dist/src/templates/backendApp/parts/integrations.template.js +115 -0
  202. package/dist/src/templates/backendApp/parts/wiring.template.d.ts +26 -0
  203. package/dist/src/templates/backendApp/parts/wiring.template.js +111 -0
  204. package/dist/src/templates/microservice/microservice.template.js +61 -87
  205. package/dist/src/templates/modular-monolith/modularMonolith.template.js +25 -77
  206. package/dist/src/templates/monolith/monolith.template.d.ts +11 -26
  207. package/dist/src/templates/monolith/monolith.template.js +49 -146
  208. package/dist/src/templates/resource/index.d.ts +9 -0
  209. package/dist/src/templates/resource/index.js +9 -0
  210. package/dist/src/templates/resource/layers/index.d.ts +9 -0
  211. package/dist/src/templates/resource/layers/index.js +9 -0
  212. package/dist/src/templates/resource/layers/resourceData.template.d.ts +9 -0
  213. package/dist/src/templates/resource/layers/resourceData.template.js +108 -0
  214. package/dist/src/templates/resource/layers/resourcePrisma.template.d.ts +15 -0
  215. package/dist/src/templates/resource/layers/resourcePrisma.template.js +89 -0
  216. package/dist/src/templates/resource/layers/resourceRoutes.template.d.ts +13 -0
  217. package/dist/src/templates/resource/layers/resourceRoutes.template.js +128 -0
  218. package/dist/src/templates/resource/layers/resourceService.template.d.ts +13 -0
  219. package/dist/src/templates/resource/layers/resourceService.template.js +95 -0
  220. package/dist/src/templates/resource/resource.files.d.ts +33 -0
  221. package/dist/src/templates/resource/resource.files.js +99 -0
  222. package/dist/src/templates/resource/resource.names.d.ts +38 -0
  223. package/dist/src/templates/resource/resource.names.js +60 -0
  224. package/dist/src/templates/resource/resource.type.d.ts +19 -0
  225. package/dist/src/templates/resource/resource.type.js +15 -0
  226. package/dist/src/templates/shared/appRuntime.template.js +28 -11
  227. package/dist/src/templates/shared/capability.template.d.ts +13 -4
  228. package/dist/src/templates/shared/capability.template.js +21 -5
  229. package/dist/src/templates/shared/dockerfile.template.d.ts +12 -4
  230. package/dist/src/templates/shared/dockerfile.template.js +68 -29
  231. package/dist/src/templates/shared/pnpm.template.d.ts +8 -2
  232. package/dist/src/templates/shared/pnpm.template.js +9 -1
  233. package/dist/src/templates/shared/server.template.d.ts +23 -22
  234. package/dist/src/templates/shared/server.template.js +79 -53
  235. package/dist/src/types/scaffold.type.d.ts +6 -0
  236. package/dist/src/types/scaffold.type.js +2 -1
  237. package/dist/src/utils/utils.name.js +6 -0
  238. package/dist/src/utils/utils.writeGuard.d.ts +5 -0
  239. package/dist/src/utils/utils.writeGuard.js +23 -0
  240. package/dist/src/wiring/index.d.ts +10 -0
  241. package/dist/src/wiring/index.js +10 -0
  242. package/dist/src/wiring/wiring.dependencies.d.ts +29 -0
  243. package/dist/src/wiring/wiring.dependencies.js +83 -0
  244. package/dist/src/wiring/wiring.edits.d.ts +51 -0
  245. package/dist/src/wiring/wiring.edits.js +90 -0
  246. package/dist/src/wiring/wiring.markers.d.ts +53 -0
  247. package/dist/src/wiring/wiring.markers.js +87 -0
  248. package/package.json +20 -15
@@ -7,23 +7,30 @@ import { existsSync, readFileSync } from "node:fs";
7
7
  import { join, relative } from "node:path";
8
8
  import { CLIValidationError } from "../errors/index.js";
9
9
  import { FEATURE_PACKAGES } from "../constants/index.js";
10
+ import { parseManifest } from "../manifest/manifestFile.helper.js";
11
+ import { findProjectRoot } from "../resolvers/project.resolver.js";
10
12
  import { resolveProjectLayout, } from "../resolvers/layout/projectLayout.core.js";
11
13
  import { EnvironmentValidator, } from "../validators/environment/environmentValidator.core.js";
12
14
  /**
13
- * Runs every diagnostic for the project at `cwd`.
15
+ * Runs every diagnostic for the project containing `cwd` (any directory
16
+ * inside it: the root is found by walking up, as `generate` does).
14
17
  *
15
18
  * Exported so the checks can be run against a scaffolded directory in tests
16
19
  * without going through the logger.
17
20
  */
18
21
  export function runDoctorChecks(cwd) {
19
- const layout = resolveProjectLayout(cwd);
22
+ const layout = resolveProjectLayout(projectRootFor(cwd));
20
23
  const checks = [checkProject(layout)];
21
24
  if (!layout) {
22
25
  return checks;
23
26
  }
24
- checks.push(checkPackageManager(layout), checkInstalled(layout), checkTypeScriptConfig(layout), checkDependencies(layout), checkFeatures(layout));
27
+ checks.push(checkPackageManager(layout), checkInstalled(layout), checkTypeScriptConfig(layout), checkDependencies(layout), checkFeatures(layout), checkCapabilities(layout));
25
28
  return checks;
26
29
  }
30
+ /** The workspace root above `cwd`, or `cwd` itself outside any project. */
31
+ function projectRootFor(cwd) {
32
+ return findProjectRoot(cwd, { workspace: true }) ?? cwd;
33
+ }
27
34
  /**
28
35
  * Environment checks: Node.js, Git and the project's own package manager.
29
36
  *
@@ -32,7 +39,7 @@ export function runDoctorChecks(cwd) {
32
39
  * inline.
33
40
  */
34
41
  export async function runEnvironmentChecks(cwd) {
35
- const layout = resolveProjectLayout(cwd);
42
+ const layout = resolveProjectLayout(projectRootFor(cwd));
36
43
  const result = await new EnvironmentValidator().validate(layout?.projectType ?? "backend", layout?.packageManager);
37
44
  return result.checks.map((check) => check.name === "Node.js"
38
45
  ? checkNodeVersion(check)
@@ -271,4 +278,45 @@ function checkFeatures(layout) {
271
278
  : violations.join("; "),
272
279
  };
273
280
  }
281
+ /** The `zudojs.features` an app's package.json declares. */
282
+ function declaredFeatures(dir) {
283
+ const features = readPackageJson(dir)?.zudojs?.features;
284
+ return Array.isArray(features)
285
+ ? features.filter((f) => typeof f === "string")
286
+ : [];
287
+ }
288
+ /**
289
+ * The manifest's `capabilities` and the backend apps' `zudojs.features`
290
+ * must name the same set. zudojs-cli 2.0.1 recorded `events` and
291
+ * `security` in the manifest only, so `info` and `add` (which read the
292
+ * manifest) and `doctor` (which reads package.json) disagreed.
293
+ */
294
+ function checkCapabilities(layout) {
295
+ const name = "Capabilities";
296
+ const manifestPath = join(layout.root, ".zudojs", "manifest.json");
297
+ const manifest = existsSync(manifestPath)
298
+ ? parseManifest(readFileSync(manifestPath, "utf-8")).manifest
299
+ : null;
300
+ if (manifest === null || layout.backendDirs.length === 0) {
301
+ return { name, severity: "warning", passed: true, message: "Nothing to compare" };
302
+ }
303
+ const declared = new Set(layout.backendDirs.flatMap(declaredFeatures));
304
+ const recorded = new Set(manifest.capabilities);
305
+ const problems = [
306
+ ...[...recorded]
307
+ .filter((c) => !declared.has(c))
308
+ .map((c) => `"${c}" is in .zudojs/manifest.json but in no app's zudojs.features`),
309
+ ...[...declared]
310
+ .filter((c) => !recorded.has(c))
311
+ .map((c) => `"${c}" is in zudojs.features but not in .zudojs/manifest.json`),
312
+ ];
313
+ return {
314
+ name,
315
+ severity: "warning",
316
+ passed: problems.length === 0,
317
+ message: problems.length === 0
318
+ ? "The manifest and package.json record the same capabilities"
319
+ : problems.join("; "),
320
+ };
321
+ }
274
322
  //# sourceMappingURL=doctor.command.js.map
@@ -10,14 +10,11 @@ import { generateService } from "../generators/service/service.generator.js";
10
10
  import { generateModule } from "../generators/module/module.generator.js";
11
11
  import { generateCommand } from "../generators/command/command.generator.js";
12
12
  import { generateQuery } from "../generators/query/query.generator.js";
13
- import { generateController } from "../generators/controller/controller.generator.js";
14
- import { generateRepository } from "../generators/repository/repository.generator.js";
15
13
  import { generateMiddleware } from "../generators/middleware/middleware.generator.js";
16
14
  import { generateEvent } from "../generators/event/event.generator.js";
17
15
  import { generateJob } from "../generators/job/job.generator.js";
18
- import { generateRoute } from "../generators/route/route.generator.js";
19
16
  import { generateModel } from "../generators/model/model.generator.js";
20
- import { generateDto } from "../generators/dto/dto.generator.js";
17
+ import { isResourceSchematic, runResourceSchematic, } from "../generators/resource/index.js";
21
18
  import { generateValidator } from "../generators/validator/validator.generator.js";
22
19
  import { CLIGenerationError, CLINotInProjectError, CLIValidationError, } from "../errors/index.js";
23
20
  import { assertGeneratableName, assertSafePathSegment, } from "../utils/utils.name.js";
@@ -26,6 +23,7 @@ import { resolveProjectLayout } from "../resolvers/layout/projectLayout.core.js"
26
23
  import { findProjectRoot } from "../resolvers/project.resolver.js";
27
24
  import { describeError } from "./commandError.helper.js";
28
25
  import { captureWrites, findWriteConflicts } from "../utils/utils.writeGuard.js";
26
+ import { describeAddedDependencies, ensureZudojsDependencies, fileCount, } from "../wiring/index.js";
29
27
  /**
30
28
  * Resolves the directory a schematic is generated into.
31
29
  *
@@ -117,6 +115,12 @@ export async function runGenerateCommand(context) {
117
115
  if (!name) {
118
116
  throw new CLIValidationError("Resource name is required.");
119
117
  }
118
+ // A name with a path in it used to be normalized silently
119
+ // (`generate resource ../../x` wrote `x`), hiding a typo or a hostile
120
+ // argument in a script. Names are plain names.
121
+ if (/[\\/]|\.\./.test(name)) {
122
+ throw new CLIValidationError(`Invalid resource name: "${name}". Use a plain name such as "users"; paths are not allowed.`);
123
+ }
120
124
  // Reject names that normalize to nothing (`zudojs generate event "..."`
121
125
  // wrote src/events/.event.ts with an anonymous export), and reject option
122
126
  // values that are interpolated verbatim into a generated path. `--service ..`
@@ -179,6 +183,20 @@ export async function runGenerateCommand(context) {
179
183
  if (effectiveSchematic !== schematic) {
180
184
  context.logger.info('Mapping "service" → "module" for modular-monolith architecture.');
181
185
  }
186
+ if (isResourceSchematic(effectiveSchematic)) {
187
+ await runResourceSchematic(context, {
188
+ schematic: effectiveSchematic,
189
+ name,
190
+ cwd,
191
+ backendRoot: backendPrefix(cwd).replace(/\/$/, ""),
192
+ architecture: architecture ?? undefined,
193
+ service,
194
+ moduleName,
195
+ dryRun,
196
+ force,
197
+ });
198
+ return;
199
+ }
182
200
  const schematicOptions = {
183
201
  service,
184
202
  module: moduleName,
@@ -197,22 +215,27 @@ export async function runGenerateCommand(context) {
197
215
  const result = await runSchematic(effectiveSchematic, name, {
198
216
  ...schematicOptions,
199
217
  onModuleRegistered: (registration) => {
200
- if (registration.registered)
218
+ if (registration.manualSteps.length === 0)
201
219
  return;
202
- context.logger.warn(`Could not register the module in app.ts automatically. Add:\n${registration.manualSteps
220
+ context.logger.warn(`Could not register the module automatically. Add:\n${registration.manualSteps
203
221
  .map((step) => ` ${step}`)
204
222
  .join("\n")}`);
205
223
  },
206
224
  }, cwd);
207
225
  if (dryRun) {
208
- context.logger.info(`Dry run: ${result.length} files would be generated (nothing written):`);
226
+ context.logger.info(`Dry run: ${fileCount(result.length)} would be generated (nothing written):`);
209
227
  }
210
228
  else {
211
- context.logger.info(`Generated ${result.length} files:`);
229
+ context.logger.info(`Generated ${fileCount(result.length)}:`);
212
230
  }
213
231
  for (const file of result) {
214
232
  context.logger.info(` - ${file}`);
215
233
  }
234
+ if (!dryRun) {
235
+ for (const line of describeAddedDependencies(ensureZudojsDependencies(cwd, result))) {
236
+ context.logger.warn(line);
237
+ }
238
+ }
216
239
  }
217
240
  async function runSchematic(schematic, name, options, cwd) {
218
241
  try {
@@ -239,22 +262,14 @@ async function runSchematic(schematic, name, options, cwd) {
239
262
  return await generateCommand({ name, ...(cqrsService ? { service: cqrsService } : {}), basePath, dryRun }, cwd);
240
263
  case "query":
241
264
  return await generateQuery({ name, ...(cqrsService ? { service: cqrsService } : {}), basePath, dryRun }, cwd);
242
- case "controller":
243
- return await generateController({ name, basePath, dryRun }, cwd);
244
- case "repository":
245
- return await generateRepository({ name, basePath, dryRun }, cwd);
246
265
  case "middleware":
247
266
  return await generateMiddleware({ name, basePath, dryRun }, cwd);
248
267
  case "event":
249
268
  return await generateEvent({ name, basePath, dryRun }, cwd);
250
269
  case "job":
251
270
  return await generateJob({ name, basePath, dryRun }, cwd);
252
- case "route":
253
- return await generateRoute({ name, basePath, dryRun }, cwd);
254
271
  case "model":
255
272
  return await generateModel({ name, basePath, dryRun }, cwd);
256
- case "dto":
257
- return await generateDto({ name, basePath, dryRun }, cwd);
258
273
  case "validator":
259
274
  return await generateValidator({ name, basePath, dryRun }, cwd);
260
275
  default:
@@ -8,6 +8,8 @@ import { join, relative } from "node:path";
8
8
  import { CLI_VERSION } from "../constants/index.js";
9
9
  import { checkForNewerVersion } from "../cliVersion/cliVersion.update.js";
10
10
  import { resolveProjectLayout } from "../resolvers/layout/projectLayout.core.js";
11
+ import { ConfigurationResolver } from "../resolvers/configuration/configurationResolver.core.js";
12
+ import { findProjectRoot } from "../resolvers/project.resolver.js";
11
13
  export async function runInfoCommand(context) {
12
14
  context.logger.info("Zudojs CLI");
13
15
  context.logger.info(` Version: ${CLI_VERSION}`);
@@ -17,7 +19,9 @@ export async function runInfoCommand(context) {
17
19
  context.logger.info(` Update available: ${update.latest} (npm install -g zudojs-cli@latest)`);
18
20
  }
19
21
  context.logger.info("");
20
- const layout = resolveProjectLayout(context.cwd);
22
+ // From any directory inside the project, like `generate` and `build`.
23
+ const root = findProjectRoot(context.cwd, { workspace: true });
24
+ const layout = root === null ? null : resolveProjectLayout(root);
21
25
  if (!layout) {
22
26
  context.logger.info("Not in a Zudojs project directory.");
23
27
  context.logger.info("Run `zudojs create <project-name>` to create a new project.");
@@ -47,6 +51,12 @@ export async function runInfoCommand(context) {
47
51
  if (layout.services.length > 0) {
48
52
  context.logger.info(` Services: ${layout.services.join(", ")}`);
49
53
  }
54
+ // The manifest's list, which `create` and `add` keep equal to the
55
+ // backend apps' `zudojs.features`; `zudojs doctor` checks the two agree.
56
+ const capabilities = new ConfigurationResolver().resolve(layout.root)?.features ?? [];
57
+ if (layout.backendDirs.length > 0) {
58
+ context.logger.info(` Capabilities: ${capabilities.length > 0 ? capabilities.join(", ") : "(none)"}`);
59
+ }
50
60
  context.logger.info("");
51
61
  context.logger.info("Zudojs dependencies");
52
62
  const deps = new Map();
@@ -6,7 +6,10 @@
6
6
  import type { BackendArchitecture, DatabaseProvider, PackageManagerType } from "../types/projectConfiguration.type.js";
7
7
  export { CLI_VERSION } from "../cliConstant/cliVersion.js";
8
8
  /**
9
- * Version range every generated project depends on for `@zudojs/*` packages.
9
+ * Legacy version range for `@zudojs/*` packages. Generated projects now use
10
+ * {@link zudojsVersionRange}, which pins each package to the version this
11
+ * CLI build targets; this remains for the few places that must name a
12
+ * range without knowing the package.
10
13
  *
11
14
  * This is a caret range, not an exact pin, on purpose. The framework
12
15
  * packages are released independently, so at any moment their latest
@@ -16,13 +19,28 @@ export { CLI_VERSION } from "../cliConstant/cliVersion.js";
16
19
  * moved on. A range resolves each package to its newest compatible release.
17
20
  */
18
21
  export declare const ZUDOJS_PACKAGES_VERSION: "^1.0.0";
22
+ export { ZUDOJS_PACKAGE_VERSIONS } from "./zudojsVersions.generated.js";
23
+ export { ZUDOJS_FALLBACK_VERSION_RANGE, zudojsDependencies, zudojsVersionRange, } from "./zudojsVersions.helper.js";
19
24
  /**
20
- * Packages installed by `zudojs add <feature>`.
25
+ * Packages that back each feature `zudojs add <feature>` accepts.
21
26
  *
22
27
  * Also used by `zudojs doctor` to verify that every feature recorded in a
23
- * project is backed by its package.
28
+ * project is backed by its package. `add` does more than install these: it
29
+ * writes a working recipe for every feature (see `src/recipes/`), so a name
30
+ * is only listed here when it has one. `docs` used to be accepted and only
31
+ * installed `@zudojs/docs`, a documentation-site toolkit with nothing to
32
+ * wire into an application; it is refused with an explanation instead.
24
33
  */
25
34
  export declare const FEATURE_PACKAGES: Readonly<Record<string, readonly string[]>>;
35
+ /**
36
+ * Other names `zudojs add` understands, mapped to the feature they mean.
37
+ */
38
+ export declare const FEATURE_ALIASES: Readonly<Record<string, string>>;
39
+ /**
40
+ * Names `zudojs add` refuses, with the reason. They were accepted once, or
41
+ * are commonly guessed, but have no application recipe.
42
+ */
43
+ export declare const FEATURE_REFUSALS: Readonly<Record<string, string>>;
26
44
  /** A selectable answer offered by a prompt. */
27
45
  export interface CLIChoiceOption<Value extends string = string> {
28
46
  readonly value: Value;
@@ -5,7 +5,10 @@
5
5
  */
6
6
  export { CLI_VERSION } from "../cliConstant/cliVersion.js";
7
7
  /**
8
- * Version range every generated project depends on for `@zudojs/*` packages.
8
+ * Legacy version range for `@zudojs/*` packages. Generated projects now use
9
+ * {@link zudojsVersionRange}, which pins each package to the version this
10
+ * CLI build targets; this remains for the few places that must name a
11
+ * range without knowing the package.
9
12
  *
10
13
  * This is a caret range, not an exact pin, on purpose. The framework
11
14
  * packages are released independently, so at any moment their latest
@@ -15,25 +18,52 @@ export { CLI_VERSION } from "../cliConstant/cliVersion.js";
15
18
  * moved on. A range resolves each package to its newest compatible release.
16
19
  */
17
20
  export const ZUDOJS_PACKAGES_VERSION = "^1.0.0";
21
+ export { ZUDOJS_PACKAGE_VERSIONS } from "./zudojsVersions.generated.js";
22
+ export { ZUDOJS_FALLBACK_VERSION_RANGE, zudojsDependencies, zudojsVersionRange, } from "./zudojsVersions.helper.js";
18
23
  /**
19
- * Packages installed by `zudojs add <feature>`.
24
+ * Packages that back each feature `zudojs add <feature>` accepts.
20
25
  *
21
26
  * Also used by `zudojs doctor` to verify that every feature recorded in a
22
- * project is backed by its package.
27
+ * project is backed by its package. `add` does more than install these: it
28
+ * writes a working recipe for every feature (see `src/recipes/`), so a name
29
+ * is only listed here when it has one. `docs` used to be accepted and only
30
+ * installed `@zudojs/docs`, a documentation-site toolkit with nothing to
31
+ * wire into an application; it is refused with an explanation instead.
23
32
  */
24
33
  export const FEATURE_PACKAGES = {
25
34
  database: ["@zudojs/database"],
35
+ redis: ["redis"],
36
+ websockets: ["ws"],
37
+ email: ["nodemailer"],
38
+ docker: [],
26
39
  queue: ["@zudojs/queue"],
27
40
  messaging: ["@zudojs/messaging"],
28
41
  openapi: ["@zudojs/openapi"],
29
42
  observability: ["@zudojs/observability"],
30
- security: ["@zudojs/security"],
31
43
  cache: ["@zudojs/cache"],
32
44
  storage: ["@zudojs/storage"],
33
45
  // Used to install @zudojs/queue; the scheduler package exists and is the
34
46
  // one the feature name promises.
35
47
  scheduler: ["@zudojs/scheduler"],
36
- docs: ["@zudojs/docs"],
48
+ };
49
+ /**
50
+ * Other names `zudojs add` understands, mapped to the feature they mean.
51
+ */
52
+ export const FEATURE_ALIASES = {
53
+ postgres: "database",
54
+ postgresql: "database",
55
+ prisma: "database",
56
+ websocket: "websockets",
57
+ ws: "websockets",
58
+ mail: "email",
59
+ };
60
+ /**
61
+ * Names `zudojs add` refuses, with the reason. They were accepted once, or
62
+ * are commonly guessed, but have no application recipe.
63
+ */
64
+ export const FEATURE_REFUSALS = {
65
+ security: "it is built in. Every generated server applies the @zudojs/security default headers, a CORS policy (CORS_ORIGINS) and per-client rate limiting (RATE_LIMIT_MAX, RATE_LIMIT_WINDOW_MS), and depends on @zudojs/security already.",
66
+ docs: "@zudojs/docs builds documentation sites; it has nothing to wire into an application. Install it directly with your package manager if you need it.",
37
67
  };
38
68
  /** Backend architectures offered by `zudojs create`. */
39
69
  export const ARCHITECTURE_CHOICES = Object.freeze([
@@ -98,6 +128,11 @@ export const FEATURE_CHOICES = Object.freeze(Object.keys(FEATURE_PACKAGES).map((
98
128
  * This is the canonical list; the hand-written one named six of thirteen.
99
129
  */
100
130
  export const SCHEMA_CHOICES = Object.freeze([
131
+ {
132
+ value: "resource",
133
+ label: "Resource",
134
+ hint: "DTO, repository, service, controller, CRUD routes and a test, registered",
135
+ },
101
136
  { value: "service", label: "Service (CQRS)" },
102
137
  { value: "module", label: "Module" },
103
138
  { value: "command", label: "Command" },
@@ -0,0 +1,9 @@
1
+ /**
2
+ * zudojs-cli — Versions of the @zudojs/* packages this CLI build targets.
3
+ *
4
+ * GENERATED by scripts/generateZudojsVersions.mjs from the package.json of
5
+ * every workspace package.
6
+ * Do not edit by hand; run `node scripts/generateZudojsVersions.mjs`.
7
+ */
8
+ export declare const ZUDOJS_PACKAGE_VERSIONS: Readonly<Record<string, string>>;
9
+ //# sourceMappingURL=zudojsVersions.generated.d.ts.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * zudojs-cli — Versions of the @zudojs/* packages this CLI build targets.
3
+ *
4
+ * GENERATED by scripts/generateZudojsVersions.mjs from the package.json of
5
+ * every workspace package.
6
+ * Do not edit by hand; run `node scripts/generateZudojsVersions.mjs`.
7
+ */
8
+ export const ZUDOJS_PACKAGE_VERSIONS = Object.freeze({
9
+ "@zudojs/adapters": "1.2.1",
10
+ "@zudojs/api": "1.2.1",
11
+ "@zudojs/auth": "1.3.1",
12
+ "@zudojs/auth-oauth": "1.2.3",
13
+ "@zudojs/cache": "1.2.1",
14
+ "@zudojs/config": "1.3.1",
15
+ "@zudojs/constants": "1.1.2",
16
+ "@zudojs/container": "1.2.1",
17
+ "@zudojs/core": "1.2.2",
18
+ "@zudojs/cqrs": "1.2.1",
19
+ "@zudojs/crypto": "1.3.1",
20
+ "@zudojs/database": "1.3.1",
21
+ "@zudojs/docs": "1.0.4",
22
+ "@zudojs/errors": "1.3.0",
23
+ "@zudojs/events": "1.3.1",
24
+ "@zudojs/feature-flags": "1.4.0",
25
+ "@zudojs/http": "1.4.2",
26
+ "@zudojs/lifecycle": "1.2.1",
27
+ "@zudojs/logger": "1.4.1",
28
+ "@zudojs/messaging": "1.2.1",
29
+ "@zudojs/middleware": "1.1.0",
30
+ "@zudojs/observability": "1.2.1",
31
+ "@zudojs/openapi": "1.5.0",
32
+ "@zudojs/permissions": "1.4.1",
33
+ "@zudojs/plugins": "1.3.1",
34
+ "@zudojs/queue": "1.4.1",
35
+ "@zudojs/rpc": "1.4.1",
36
+ "@zudojs/runtime": "1.3.1",
37
+ "@zudojs/scheduler": "1.2.0",
38
+ "@zudojs/schema": "1.2.1",
39
+ "@zudojs/security": "1.3.1",
40
+ "@zudojs/serialization": "1.2.1",
41
+ "@zudojs/storage": "1.2.1",
42
+ "@zudojs/tenancy": "1.3.1",
43
+ "@zudojs/testing": "1.2.2",
44
+ "@zudojs/transactions": "1.2.0",
45
+ "@zudojs/types": "1.2.0",
46
+ "@zudojs/validation": "1.1.0",
47
+ });
48
+ //# sourceMappingURL=zudojsVersions.generated.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * zudojs-cli — Version ranges written for `@zudojs/*` dependencies.
3
+ *
4
+ * Every generated package.json used to depend on `^1.0.0` of every framework
5
+ * package, which resolves to any 1.x release — including ones that predate
6
+ * the APIs the generated code calls (`createRouter` OpenAPI metadata,
7
+ * `mountOpenAPI`, `createHttpTestClient`). Each package now gets a caret
8
+ * range on the version this CLI build was generated against
9
+ * ({@link ZUDOJS_PACKAGE_VERSIONS}), so a newer compatible release is still
10
+ * picked up but an older one never is.
11
+ */
12
+ /**
13
+ * Fallback for a package the version map does not know (for example a
14
+ * name recorded by an older project). A plain caret on the first major.
15
+ */
16
+ export declare const ZUDOJS_FALLBACK_VERSION_RANGE: "^1.0.0";
17
+ /** The range written for `name` (`^<version this CLI targets>`). */
18
+ export declare function zudojsVersionRange(name: string): string;
19
+ /** `{ name: range }` for a list of `@zudojs/*` packages, deduplicated. */
20
+ export declare function zudojsDependencies(names: readonly string[]): Record<string, string>;
21
+ //# sourceMappingURL=zudojsVersions.helper.d.ts.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * zudojs-cli — Version ranges written for `@zudojs/*` dependencies.
3
+ *
4
+ * Every generated package.json used to depend on `^1.0.0` of every framework
5
+ * package, which resolves to any 1.x release — including ones that predate
6
+ * the APIs the generated code calls (`createRouter` OpenAPI metadata,
7
+ * `mountOpenAPI`, `createHttpTestClient`). Each package now gets a caret
8
+ * range on the version this CLI build was generated against
9
+ * ({@link ZUDOJS_PACKAGE_VERSIONS}), so a newer compatible release is still
10
+ * picked up but an older one never is.
11
+ */
12
+ import { ZUDOJS_PACKAGE_VERSIONS } from "./zudojsVersions.generated.js";
13
+ /**
14
+ * Fallback for a package the version map does not know (for example a
15
+ * name recorded by an older project). A plain caret on the first major.
16
+ */
17
+ export const ZUDOJS_FALLBACK_VERSION_RANGE = "^1.0.0";
18
+ /** The range written for `name` (`^<version this CLI targets>`). */
19
+ export function zudojsVersionRange(name) {
20
+ const version = Object.hasOwn(ZUDOJS_PACKAGE_VERSIONS, name)
21
+ ? ZUDOJS_PACKAGE_VERSIONS[name]
22
+ : undefined;
23
+ return version === undefined ? ZUDOJS_FALLBACK_VERSION_RANGE : `^${version}`;
24
+ }
25
+ /** `{ name: range }` for a list of `@zudojs/*` packages, deduplicated. */
26
+ export function zudojsDependencies(names) {
27
+ return Object.fromEntries([...new Set(names)].map((name) => [name, zudojsVersionRange(name)]));
28
+ }
29
+ //# sourceMappingURL=zudojsVersions.helper.js.map
@@ -8,7 +8,6 @@ import { PackageManagerRegistry } from "../../registries/adapter/packageManagerR
8
8
  import { DependencyResolver } from "../../resolvers/dependency/dependencyResolver.core.js";
9
9
  import { CLIGenerationError } from "../../errors/index.js";
10
10
  import { runFrontendPipeline } from "./frontendPipeline.js";
11
- import { writeFileTree } from "../../utils/utils.fileSystem.js";
12
11
  import { renderPnpmWorkspaceFile } from "../../templates/shared/pnpm.template.js";
13
12
  /**
14
13
  * Generates frontend projects using framework adapters.
@@ -47,15 +46,15 @@ export class FrontendGenerator {
47
46
  const files = [];
48
47
  const errors = [];
49
48
  try {
50
- // A frontend-only project is its own pnpm root. Vite depends on
51
- // esbuild, whose install script pnpm 10+ refuses without this list,
52
- // and the pipeline installs dependencies right after scaffolding.
53
- if (context.packageManager === "pnpm") {
54
- await writeFileTree(context.projectPath, {
55
- "pnpm-workspace.yaml": renderPnpmWorkspaceFile(),
56
- });
57
- }
58
- const outcome = await runFrontendPipeline(adapter, context, this.packageManagerRegistry, this.dependencyResolver);
49
+ // A frontend-only project is its own pnpm root. Toolchains depend on
50
+ // packages with install scripts (esbuild, sharp, @parcel/watcher)
51
+ // that pnpm 10+ refuses without this list. It is written after the
52
+ // official scaffolder runs, which must see an empty directory, and
53
+ // before the pipeline installs dependencies.
54
+ const postScaffoldFiles = context.packageManager === "pnpm"
55
+ ? { "pnpm-workspace.yaml": renderPnpmWorkspaceFile() }
56
+ : {};
57
+ const outcome = await runFrontendPipeline(adapter, context, this.packageManagerRegistry, this.dependencyResolver, postScaffoldFiles);
59
58
  files.push(...outcome.files);
60
59
  errors.push(...outcome.errors);
61
60
  }
@@ -21,6 +21,11 @@ export interface FrontendPipelineResult {
21
21
  /**
22
22
  * Runs the full adapter sequence: availability check, scaffold, structure,
23
23
  * integration, dependency resolution, dependency installation, validation.
24
+ *
25
+ * @param postScaffoldFiles - Files written right after the scaffold step
26
+ * (e.g. a standalone project's `pnpm-workspace.yaml`). They must not exist
27
+ * earlier: `create-vite` cancels in a non-empty directory yet exits 0, so
28
+ * a pre-written file left the project with no Vite app at all.
24
29
  */
25
- export declare function runFrontendPipeline(adapter: FrontendAdapter, context: FrontendGenerationContext, packageManagerRegistry: PackageManagerRegistry, dependencyResolver: DependencyResolver): Promise<FrontendPipelineResult>;
30
+ export declare function runFrontendPipeline(adapter: FrontendAdapter, context: FrontendGenerationContext, packageManagerRegistry: PackageManagerRegistry, dependencyResolver: DependencyResolver, postScaffoldFiles?: Readonly<Record<string, string>>): Promise<FrontendPipelineResult>;
26
31
  //# sourceMappingURL=frontendPipeline.d.ts.map
@@ -32,8 +32,13 @@ function assertSafePackageNames(names) {
32
32
  /**
33
33
  * Runs the full adapter sequence: availability check, scaffold, structure,
34
34
  * integration, dependency resolution, dependency installation, validation.
35
+ *
36
+ * @param postScaffoldFiles - Files written right after the scaffold step
37
+ * (e.g. a standalone project's `pnpm-workspace.yaml`). They must not exist
38
+ * earlier: `create-vite` cancels in a non-empty directory yet exits 0, so
39
+ * a pre-written file left the project with no Vite app at all.
35
40
  */
36
- export async function runFrontendPipeline(adapter, context, packageManagerRegistry, dependencyResolver) {
41
+ export async function runFrontendPipeline(adapter, context, packageManagerRegistry, dependencyResolver, postScaffoldFiles = {}) {
37
42
  const files = [];
38
43
  const errors = [];
39
44
  // 0. Fail fast with a readable message when the framework's own toolchain
@@ -53,6 +58,9 @@ export async function runFrontendPipeline(adapter, context, packageManagerRegist
53
58
  // templates where one exists).
54
59
  await adapter.scaffold(context);
55
60
  files.push("scaffold");
61
+ if (Object.keys(postScaffoldFiles).length > 0) {
62
+ await writeFileTree(context.projectPath, { ...postScaffoldFiles });
63
+ }
56
64
  // 2. Apply the Zudojs structure over the scaffolded project.
57
65
  await adapter.applyZudojsStructure(context);
58
66
  files.push("structure");
@@ -13,6 +13,7 @@ import { DependencyResolver } from "../../resolvers/dependency/dependencyResolve
13
13
  import { runFrontendPipeline } from "../frontend/frontendPipeline.js";
14
14
  import { writeFileTree } from "../../utils/utils.fileSystem.js";
15
15
  import { renderPnpmWorkspaceFile } from "../../templates/shared/pnpm.template.js";
16
+ import { TYPESCRIPT_VERSION_RANGES } from "../../resolvers/dependency/dependencyVersions.constant.js";
16
17
  /**
17
18
  * Composes fullstack projects by orchestrating multiple generators.
18
19
  */
@@ -92,7 +93,12 @@ export class FullstackComposer {
92
93
  typecheck: scriptFor("typecheck"),
93
94
  },
94
95
  devDependencies: {
95
- typescript: "^5.0.0",
96
+ // The root compiler is hoisted over every workspace by npm, yarn
97
+ // and bun, so it must satisfy the frontend toolchain's TypeScript
98
+ // peer range; apps/api keeps its own TypeScript 7.
99
+ typescript: context.project.frontend
100
+ ? TYPESCRIPT_VERSION_RANGES.frontend
101
+ : TYPESCRIPT_VERSION_RANGES.backend,
96
102
  },
97
103
  };
98
104
  // The project's type, architecture and frontend are recorded in
@@ -11,6 +11,5 @@ export { generateModule } from "./module/module.generator.js";
11
11
  export { generateService } from "./service/service.generator.js";
12
12
  export { generateCommand } from "./command/command.generator.js";
13
13
  export { generateQuery } from "./query/query.generator.js";
14
- export { generateController } from "./controller/controller.generator.js";
15
- export { generateRepository } from "./repository/repository.generator.js";
14
+ export { generateResource, resolveResourceLayout, planResource, RESOURCE_SCHEMATICS, } from "./resource/index.js";
16
15
  //# sourceMappingURL=index.d.ts.map
@@ -11,6 +11,5 @@ export { generateModule } from "./module/module.generator.js";
11
11
  export { generateService } from "./service/service.generator.js";
12
12
  export { generateCommand } from "./command/command.generator.js";
13
13
  export { generateQuery } from "./query/query.generator.js";
14
- export { generateController } from "./controller/controller.generator.js";
15
- export { generateRepository } from "./repository/repository.generator.js";
14
+ export { generateResource, resolveResourceLayout, planResource, RESOURCE_SCHEMATICS, } from "./resource/index.js";
16
15
  //# sourceMappingURL=index.js.map
@@ -9,6 +9,13 @@ import { resolveDatabaseAdapter } from "../../adapters/databases/databaseAdapter
9
9
  import { resolveMicroserviceServices } from "../../templates/microservice/microservice.template.js";
10
10
  import { renderAppPackageDockerfile, renderWorkspaceAppDockerfile, } from "../../templates/shared/dockerfile.template.js";
11
11
  const SERVICE_NAME_PATTERN = /^[a-zA-Z0-9_-]+$/;
12
+ /**
13
+ * Database passwords are interpolated by compose from `.env`
14
+ * (see `.env.example`); compose refuses to start without them. The files
15
+ * used to carry `postgres`/`mysql` as literal passwords.
16
+ */
17
+ const POSTGRES_PASSWORD = "${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}";
18
+ const MYSQL_PASSWORD = "${MYSQL_ROOT_PASSWORD:?Set MYSQL_ROOT_PASSWORD in .env}";
12
19
  export class InfrastructureGenerator {
13
20
  async generate(options, basePath) {
14
21
  // Rejects engines with no adapter (e.g. mongodb) instead of falling
@@ -60,11 +67,12 @@ export class InfrastructureGenerator {
60
67
  return {
61
68
  image: "mysql:8",
62
69
  port: 3306,
70
+ // Read from .env by compose: no credential is written here.
63
71
  environment: [
64
- "MYSQL_ROOT_PASSWORD=mysql",
72
+ `MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD}`,
65
73
  `MYSQL_DATABASE=${options.projectName}`,
66
74
  ],
67
- url: `mysql://root:mysql@db:3306/${options.projectName}`,
75
+ url: `mysql://root:${MYSQL_PASSWORD}@db:3306/${options.projectName}`,
68
76
  dataPath: "/var/lib/mysql",
69
77
  };
70
78
  }
@@ -77,10 +85,10 @@ export class InfrastructureGenerator {
77
85
  port: 5432,
78
86
  environment: [
79
87
  "POSTGRES_USER=postgres",
80
- "POSTGRES_PASSWORD=postgres",
88
+ `POSTGRES_PASSWORD=${POSTGRES_PASSWORD}`,
81
89
  `POSTGRES_DB=${options.projectName}`,
82
90
  ],
83
- url: `postgresql://postgres:postgres@db:5432/${options.projectName}`,
91
+ url: `postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/${options.projectName}`,
84
92
  dataPath: "/var/lib/postgresql/data",
85
93
  };
86
94
  }
@@ -92,7 +100,7 @@ export class InfrastructureGenerator {
92
100
  return ` db:
93
101
  image: ${db.image}
94
102
  ports:
95
- - "${db.port}:${db.port}"
103
+ - "127.0.0.1:${db.port}:${db.port}"
96
104
  environment:
97
105
  ${db.environment.map((e) => ` - ${e}`).join("\n")}
98
106
  volumes:
@@ -30,6 +30,8 @@ export declare class IntegrationGenerator {
30
30
  private getBackendPath;
31
31
  private generateApiClient;
32
32
  private getApiClientPath;
33
+ /** Origins the frontend dev server is reached on. */
34
+ private frontendOrigins;
33
35
  private generateCorsConfig;
34
36
  private generateViteProxy;
35
37
  }