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
@@ -0,0 +1,84 @@
1
+ /**
2
+ * zudojs-cli — Edits `add` makes to plain project files: `.env.example`,
3
+ * `.gitignore`, `package.json` and `pnpm-workspace.yaml`. Every edit is
4
+ * additive and idempotent; existing values are never replaced (except the
5
+ * scripts a recipe names explicitly, and only from their generated value).
6
+ */
7
+ import { existsSync, readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import { renderEnvVariables } from "../../templates/backendApp/index.js";
10
+ /** `.env.example` with the variables it does not declare yet appended. */
11
+ export function withEnvVariables(current, variables) {
12
+ const declared = new Set(current.split("\n").map((line) => line.split("=")[0]?.trim() ?? ""));
13
+ const missing = variables.filter((v) => !declared.has(v.name));
14
+ if (missing.length === 0)
15
+ return undefined;
16
+ const separator = current === "" || current.endsWith("\n") ? "" : "\n";
17
+ return `${current}${separator}${renderEnvVariables(missing)}\n`;
18
+ }
19
+ /** `.gitignore` with the lines it lacks appended. */
20
+ export function withGitignoreLines(current, lines) {
21
+ const present = new Set(current.split("\n").map((line) => line.trim()));
22
+ const missing = lines.filter((line) => !present.has(line));
23
+ if (missing.length === 0)
24
+ return undefined;
25
+ const separator = current === "" || current.endsWith("\n") ? "" : "\n";
26
+ return `${current}${separator}${missing.join("\n")}\n`;
27
+ }
28
+ /** Merges `changes` into `pkg` in place. */
29
+ export function mergePackageJson(pkg, changes) {
30
+ pkg.dependencies ??= {};
31
+ for (const [name, range] of Object.entries(changes.dependencies)) {
32
+ if (!(name in pkg.dependencies))
33
+ pkg.dependencies[name] = range;
34
+ }
35
+ if (changes.devDependencies !== undefined) {
36
+ pkg.devDependencies ??= {};
37
+ for (const [name, range] of Object.entries(changes.devDependencies)) {
38
+ if (!(name in pkg.devDependencies) && !(name in pkg.dependencies)) {
39
+ pkg.devDependencies[name] = range;
40
+ }
41
+ }
42
+ }
43
+ if (changes.scripts !== undefined || changes.replaceScripts !== undefined) {
44
+ pkg.scripts ??= {};
45
+ for (const [name, command] of Object.entries(changes.scripts ?? {})) {
46
+ if (!(name in pkg.scripts))
47
+ pkg.scripts[name] = command;
48
+ }
49
+ for (const [name, { from, to }] of Object.entries(changes.replaceScripts ?? {})) {
50
+ if (pkg.scripts[name] === from)
51
+ pkg.scripts[name] = to;
52
+ }
53
+ }
54
+ pkg.zudojs ??= {};
55
+ const block = pkg.zudojs;
56
+ const features = new Set(Array.isArray(block.features)
57
+ ? block.features.filter((f) => typeof f === "string")
58
+ : []);
59
+ features.add(changes.feature);
60
+ block.features = [...features];
61
+ }
62
+ /**
63
+ * `pnpm-workspace.yaml` with `names` added to both build-script allow-lists
64
+ * (pnpm 10 `onlyBuiltDependencies`, pnpm 11 `allowBuilds`). Returns
65
+ * `undefined` when there is no such file or nothing to add.
66
+ */
67
+ export function withAllowedBuilds(root, names) {
68
+ const path = join(root, "pnpm-workspace.yaml");
69
+ if (names.length === 0 || !existsSync(path))
70
+ return undefined;
71
+ let source = readFileSync(path, "utf-8");
72
+ const original = source;
73
+ for (const name of names) {
74
+ const quoted = JSON.stringify(name);
75
+ if (/^onlyBuiltDependencies:\s*$/m.test(source) && !source.includes(` - ${quoted}`)) {
76
+ source = source.replace(/^onlyBuiltDependencies:\s*$/m, `onlyBuiltDependencies:\n - ${quoted}`);
77
+ }
78
+ if (/^allowBuilds:\s*$/m.test(source) && !source.includes(` ${quoted}: true`)) {
79
+ source = source.replace(/^allowBuilds:\s*$/m, `allowBuilds:\n ${quoted}: true`);
80
+ }
81
+ }
82
+ return source === original ? undefined : source;
83
+ }
84
+ //# sourceMappingURL=recipeApply.files.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * zudojs-cli — Project-level parts of `add`: project recipes (docker),
3
+ * `.gitignore` lines and the pnpm build-script allow-list.
4
+ */
5
+ import type { ProjectRecipe, ProjectRecipeContext } from "../recipe.type.js";
6
+ import type { RecipeOutcome } from "./recipeApply.app.js";
7
+ /** Writes a project recipe's files (keeping existing ones) and env. */
8
+ export declare function applyProjectRecipe(recipe: ProjectRecipe, context: ProjectRecipeContext): Promise<RecipeOutcome>;
9
+ /** Appends `.gitignore` lines and pnpm allow-list entries; returns the files changed. */
10
+ export declare function applyProjectSettings(root: string, gitignore: readonly string[], allowBuilds: readonly string[]): Promise<readonly string[]>;
11
+ //# sourceMappingURL=recipeApply.project.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * zudojs-cli — Project-level parts of `add`: project recipes (docker),
3
+ * `.gitignore` lines and the pnpm build-script allow-list.
4
+ */
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { writeFile } from "../../utils/utils.fileSystem.js";
8
+ import { withAllowedBuilds, withEnvVariables, withGitignoreLines } from "./recipeApply.files.js";
9
+ /** Writes a project recipe's files (keeping existing ones) and env. */
10
+ export async function applyProjectRecipe(recipe, context) {
11
+ const written = [];
12
+ const kept = [];
13
+ const edited = [];
14
+ for (const [path, content] of Object.entries(recipe.files(context))) {
15
+ if (existsSync(join(context.root, path))) {
16
+ kept.push(path);
17
+ }
18
+ else {
19
+ await writeFile(context.root, path, content);
20
+ written.push(path);
21
+ }
22
+ }
23
+ const env = recipe.env?.(context) ?? [];
24
+ if (env.length > 0) {
25
+ const path = join(context.root, ".env.example");
26
+ const next = withEnvVariables(existsSync(path) ? readFileSync(path, "utf-8") : "", env);
27
+ if (next !== undefined) {
28
+ await writeFile(context.root, ".env.example", next);
29
+ edited.push(".env.example");
30
+ }
31
+ }
32
+ return { written, kept, edited, manualSteps: [] };
33
+ }
34
+ /** Appends `.gitignore` lines and pnpm allow-list entries; returns the files changed. */
35
+ export async function applyProjectSettings(root, gitignore, allowBuilds) {
36
+ const edited = [];
37
+ const ignorePath = join(root, ".gitignore");
38
+ const ignore = withGitignoreLines(existsSync(ignorePath) ? readFileSync(ignorePath, "utf-8") : "", gitignore);
39
+ if (ignore !== undefined) {
40
+ await writeFile(root, ".gitignore", ignore);
41
+ edited.push(".gitignore");
42
+ }
43
+ const workspace = withAllowedBuilds(root, allowBuilds);
44
+ if (workspace !== undefined) {
45
+ await writeFile(root, "pnpm-workspace.yaml", workspace);
46
+ edited.push("pnpm-workspace.yaml");
47
+ }
48
+ return edited;
49
+ }
50
+ //# sourceMappingURL=recipeApply.project.js.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * zudojs-cli — Recording a feature and reporting what `add` did.
3
+ */
4
+ import type { CLIContext } from "../../cliType/cliType.type.js";
5
+ import type { RecipeOutcome } from "./recipeApply.app.js";
6
+ /** Adds `feature` to an app's `zudojs.features`. */
7
+ export declare function recordFeature(pkgPath: string, feature: string): void;
8
+ /**
9
+ * Adds `feature` to the workspace root's `zudojs.features` when the root is
10
+ * not itself an app that received it.
11
+ *
12
+ * A microservice root records the project's capabilities next to the
13
+ * manifest, but `add` only wrote the apps, so the root list went stale
14
+ * after the first `zudojs add`. Roots without a features list (fullstack)
15
+ * are left alone. Returns whether the root was updated.
16
+ */
17
+ export declare function recordProjectFeature(root: string, feature: string, targets: readonly string[]): boolean;
18
+ /** Logs what was written, kept, edited and what is left to do by hand. */
19
+ export declare function reportOutcomes(logger: CLIContext["logger"], cwd: string, root: string, outcomes: readonly RecipeOutcome[]): void;
20
+ //# sourceMappingURL=recipeApply.report.d.ts.map
@@ -0,0 +1,51 @@
1
+ /**
2
+ * zudojs-cli — Recording a feature and reporting what `add` did.
3
+ */
4
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { join, relative } from "node:path";
6
+ import { mergePackageJson } from "./recipeApply.files.js";
7
+ /** Adds `feature` to an app's `zudojs.features`. */
8
+ export function recordFeature(pkgPath, feature) {
9
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
10
+ mergePackageJson(pkg, { feature, dependencies: {} });
11
+ writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
12
+ }
13
+ /**
14
+ * Adds `feature` to the workspace root's `zudojs.features` when the root is
15
+ * not itself an app that received it.
16
+ *
17
+ * A microservice root records the project's capabilities next to the
18
+ * manifest, but `add` only wrote the apps, so the root list went stale
19
+ * after the first `zudojs add`. Roots without a features list (fullstack)
20
+ * are left alone. Returns whether the root was updated.
21
+ */
22
+ export function recordProjectFeature(root, feature, targets) {
23
+ const pkgPath = join(root, "package.json");
24
+ if (!existsSync(pkgPath) || targets.includes(pkgPath))
25
+ return false;
26
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
27
+ const block = pkg.zudojs;
28
+ if (!Array.isArray(block?.features) || block.features.includes(feature))
29
+ return false;
30
+ block.features = [...block.features, feature];
31
+ writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
32
+ return true;
33
+ }
34
+ /** Logs what was written, kept, edited and what is left to do by hand. */
35
+ export function reportOutcomes(logger, cwd, root, outcomes) {
36
+ const rel = (path) => relative(cwd, join(root, path)) || path;
37
+ const list = (label, paths) => {
38
+ const unique = [...new Set(paths)];
39
+ if (unique.length === 0)
40
+ return;
41
+ logger.info(`${label}:\n${unique.map((p) => ` - ${rel(p)}`).join("\n")}`);
42
+ };
43
+ list("Created", outcomes.flatMap((o) => o.written));
44
+ list("Updated", outcomes.flatMap((o) => o.edited));
45
+ list("Kept (already present)", outcomes.flatMap((o) => o.kept));
46
+ const manual = outcomes.flatMap((o) => o.manualSteps);
47
+ if (manual.length > 0) {
48
+ logger.warn(`Finish by hand:\n${manual.map((step) => ` - ${step}`).join("\n")}`);
49
+ }
50
+ }
51
+ //# sourceMappingURL=recipeApply.report.js.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * zudojs-cli — Files of the Prisma database recipe.
3
+ *
4
+ * Prisma 7: the `prisma-client` generator writes a TypeScript client into
5
+ * `src/generated/prisma` (ESM, `.js` import extensions, so `tsc` compiles
6
+ * it with the app), the connection URL lives in `prisma.config.ts`, and
7
+ * the client connects through the `@prisma/adapter-pg` driver adapter.
8
+ */
9
+ /** `prisma/schema.prisma`. */
10
+ export declare function renderPrismaSchema(): string;
11
+ /** `prisma.config.ts`: reads DATABASE_URL from the environment or `.env`. */
12
+ export declare function renderPrismaConfig(): string;
13
+ /** `src/integrations/database.ts`. */
14
+ export declare function renderDatabaseIntegration(): string;
15
+ //# sourceMappingURL=database.files.d.ts.map
@@ -0,0 +1,98 @@
1
+ /**
2
+ * zudojs-cli — Files of the Prisma database recipe.
3
+ *
4
+ * Prisma 7: the `prisma-client` generator writes a TypeScript client into
5
+ * `src/generated/prisma` (ESM, `.js` import extensions, so `tsc` compiles
6
+ * it with the app), the connection URL lives in `prisma.config.ts`, and
7
+ * the client connects through the `@prisma/adapter-pg` driver adapter.
8
+ */
9
+ /** `prisma/schema.prisma`. */
10
+ export function renderPrismaSchema() {
11
+ return `// Prisma schema: https://www.prisma.io/docs/orm/prisma-schema
12
+ // \`zudojs generate resource <name>\` appends a model here.
13
+
14
+ generator client {
15
+ provider = "prisma-client"
16
+ output = "../src/generated/prisma"
17
+ moduleFormat = "esm"
18
+ importFileExtension = "js"
19
+ }
20
+
21
+ datasource db {
22
+ provider = "postgresql"
23
+ }
24
+ `;
25
+ }
26
+ /** `prisma.config.ts`: reads DATABASE_URL from the environment or `.env`. */
27
+ export function renderPrismaConfig() {
28
+ return `import { defineConfig } from "prisma/config";
29
+
30
+ try {
31
+ process.loadEnvFile(".env");
32
+ } catch {
33
+ // No .env: DATABASE_URL comes from the environment.
34
+ }
35
+
36
+ export default defineConfig({
37
+ schema: "prisma/schema.prisma",
38
+ migrations: { path: "prisma/migrations" },
39
+ datasource: { url: process.env["DATABASE_URL"] ?? "" },
40
+ });
41
+ `;
42
+ }
43
+ /** `src/integrations/database.ts`. */
44
+ export function renderDatabaseIntegration() {
45
+ return `import { PrismaPg } from "@prisma/adapter-pg";
46
+ import {
47
+ createDatabaseClient,
48
+ type DatabaseClient,
49
+ } from "@zudojs/database";
50
+ import { ConfigurationError } from "@zudojs/errors";
51
+
52
+ import { PrismaClient } from "../generated/prisma/client.js";
53
+ import type { Integration } from "./integration.js";
54
+
55
+ let client: PrismaClient | undefined;
56
+ let database: DatabaseClient | undefined;
57
+
58
+ /** The connected Prisma client. Throws before the runtime has started. */
59
+ export function prisma(): PrismaClient {
60
+ if (client === undefined) {
61
+ throw new Error("The database is not connected: start the runtime first.");
62
+ }
63
+ return client;
64
+ }
65
+
66
+ export const databaseIntegration: Integration = {
67
+ name: "database",
68
+
69
+ async start({ config }) {
70
+ if (config.database.url === "") {
71
+ throw new ConfigurationError(
72
+ "DATABASE_URL is not set. Copy .env.example to .env, or set it in the environment.",
73
+ );
74
+ }
75
+ const next = new PrismaClient({
76
+ adapter: new PrismaPg({ connectionString: config.database.url }),
77
+ });
78
+ const wrapper = createDatabaseClient({ prisma: next });
79
+ await wrapper.connect();
80
+ client = next;
81
+ database = wrapper;
82
+ },
83
+
84
+ async stop() {
85
+ const current = database;
86
+ database = undefined;
87
+ client = undefined;
88
+ await current?.disconnect();
89
+ },
90
+
91
+ async health() {
92
+ if (database === undefined) return false;
93
+ return database.ping().then(() => true, () => false);
94
+ },
95
+ };
96
+ `;
97
+ }
98
+ //# sourceMappingURL=database.files.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add database` (alias `postgres`): PostgreSQL through
3
+ * Prisma 7 and @zudojs/database. Writes the schema, `prisma.config.ts`,
4
+ * the client integration and the `db:*` scripts; `generate resource` then
5
+ * writes Prisma-backed repositories and models.
6
+ */
7
+ import type { AppRecipe } from "../../recipe.type.js";
8
+ export declare const databaseRecipe: AppRecipe;
9
+ //# sourceMappingURL=database.recipe.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add database` (alias `postgres`): PostgreSQL through
3
+ * Prisma 7 and @zudojs/database. Writes the schema, `prisma.config.ts`,
4
+ * the client integration and the `db:*` scripts; `generate resource` then
5
+ * writes Prisma-backed repositories and models.
6
+ */
7
+ import { CLIValidationError } from "../../../errors/index.js";
8
+ import { zudojsDependencies } from "../../../constants/index.js";
9
+ import { DEPENDENCY_VERSION_RANGES } from "../../../resolvers/dependency/dependencyVersions.constant.js";
10
+ import { DATABASE_CONFIG_SECTION } from "../../../templates/backendApp/index.js";
11
+ import { renderDatabaseIntegration, renderPrismaConfig, renderPrismaSchema, } from "./database.files.js";
12
+ export const databaseRecipe = {
13
+ scope: "app",
14
+ feature: "database",
15
+ summary: "PostgreSQL via Prisma 7 (prisma/schema.prisma, src/integrations/database.ts, db:* scripts)",
16
+ validate: (context) => {
17
+ if (context.database !== "postgresql") {
18
+ throw new CLIValidationError(`The database recipe supports PostgreSQL only (@zudojs/database is a PostgreSQL layer); this project records "${context.database}". Change "database.provider" in .zudojs/manifest.json to "postgresql" to use it.`);
19
+ }
20
+ },
21
+ dependencies: {
22
+ ...zudojsDependencies(["@zudojs/database"]),
23
+ "@prisma/client": DEPENDENCY_VERSION_RANGES["@prisma/client"],
24
+ "@prisma/adapter-pg": DEPENDENCY_VERSION_RANGES["@prisma/adapter-pg"],
25
+ },
26
+ devDependencies: { prisma: DEPENDENCY_VERSION_RANGES.prisma },
27
+ scripts: {
28
+ postinstall: "prisma generate",
29
+ "db:generate": "prisma generate",
30
+ "db:migrate": "prisma migrate dev",
31
+ "db:deploy": "prisma migrate deploy",
32
+ },
33
+ replaceScripts: { build: { from: "tsc", to: "prisma generate && tsc" } },
34
+ env: (context) => [
35
+ { name: "DATABASE_URL", value: `postgresql://postgres:change-me@localhost:5432/${context.projectSlug}` },
36
+ ],
37
+ configSection: DATABASE_CONFIG_SECTION,
38
+ integration: { file: "database.ts", exportName: "databaseIntegration", source: renderDatabaseIntegration },
39
+ files: () => ({
40
+ "prisma/schema.prisma": renderPrismaSchema(),
41
+ "prisma.config.ts": renderPrismaConfig(),
42
+ }),
43
+ gitignore: (context) => [`${context.appRoot === "" ? "" : `${context.appRoot}/`}src/generated/`],
44
+ allowBuilds: ["prisma", "@prisma/engines", "@prisma/client"],
45
+ nextSteps: () => [
46
+ "Set DATABASE_URL in .env, then run the db:migrate script after adding models.",
47
+ "Resources generated from now on use Prisma; existing ones keep their in-memory repository until you swap it in src/container.ts.",
48
+ ],
49
+ };
50
+ //# sourceMappingURL=database.recipe.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * zudojs-cli — The Prisma/PostgreSQL database recipe.
3
+ */
4
+ export { databaseRecipe } from "./database.recipe.js";
5
+ export * from "./database.files.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * zudojs-cli — The Prisma/PostgreSQL database recipe.
3
+ */
4
+ export { databaseRecipe } from "./database.recipe.js";
5
+ export * from "./database.files.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add email`: an `EmailTransport` abstraction with two
3
+ * implementations: `console` (development default: logs the recipient and
4
+ * subject, never the body) and `smtp` (nodemailer). SMTP credentials come
5
+ * from the environment only; nothing secret is written to source.
6
+ */
7
+ import type { AppRecipe } from "../recipe.type.js";
8
+ export declare const emailRecipe: AppRecipe;
9
+ //# sourceMappingURL=email.recipe.d.ts.map
@@ -0,0 +1,122 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add email`: an `EmailTransport` abstraction with two
3
+ * implementations: `console` (development default: logs the recipient and
4
+ * subject, never the body) and `smtp` (nodemailer). SMTP credentials come
5
+ * from the environment only; nothing secret is written to source.
6
+ */
7
+ import { DEPENDENCY_VERSION_RANGES } from "../../resolvers/dependency/dependencyVersions.constant.js";
8
+ const source = () => `import { createTransport } from "nodemailer";
9
+
10
+ import type { AppConfig } from "../configs/index.js";
11
+ import type { Integration, IntegrationContext } from "./integration.js";
12
+
13
+ /** A message to send. */
14
+ export interface EmailMessage {
15
+ readonly to: string | readonly string[];
16
+ readonly subject: string;
17
+ readonly text: string;
18
+ readonly html?: string;
19
+ }
20
+
21
+ /** Sends email; swap implementations through EMAIL_TRANSPORT. */
22
+ export interface EmailTransport {
23
+ send(message: EmailMessage): Promise<void>;
24
+ verify(): Promise<boolean>;
25
+ close(): void;
26
+ }
27
+
28
+ function consoleTransport(logger: IntegrationContext["logger"]): EmailTransport {
29
+ return {
30
+ async send(message) {
31
+ logger.info("Email (console transport, not sent)", {
32
+ to: message.to,
33
+ subject: message.subject,
34
+ });
35
+ },
36
+ async verify() {
37
+ return true;
38
+ },
39
+ close() {},
40
+ };
41
+ }
42
+
43
+ function smtpTransport(settings: AppConfig["email"]): EmailTransport {
44
+ const transporter = createTransport({
45
+ host: settings.smtpHost,
46
+ port: settings.smtpPort,
47
+ secure: settings.smtpSecure,
48
+ ...(settings.smtpUser === ""
49
+ ? {}
50
+ : { auth: { user: settings.smtpUser, pass: settings.smtpPassword } }),
51
+ });
52
+ return {
53
+ async send(message) {
54
+ await transporter.sendMail({
55
+ from: settings.from,
56
+ to: typeof message.to === "string" ? message.to : [...message.to],
57
+ subject: message.subject,
58
+ text: message.text,
59
+ ...(message.html === undefined ? {} : { html: message.html }),
60
+ });
61
+ },
62
+ async verify() {
63
+ return transporter.verify().then(() => true, () => false);
64
+ },
65
+ close() {
66
+ transporter.close();
67
+ },
68
+ };
69
+ }
70
+
71
+ let transport: EmailTransport | undefined;
72
+
73
+ /** The configured transport. Throws before the runtime has started. */
74
+ export function email(): EmailTransport {
75
+ if (transport === undefined) {
76
+ throw new Error("Email is not configured: start the runtime first.");
77
+ }
78
+ return transport;
79
+ }
80
+
81
+ export const emailIntegration: Integration = {
82
+ name: "email",
83
+
84
+ async start({ config, logger }) {
85
+ const kind = config.email.transport;
86
+ if (kind !== "console" && kind !== "smtp") {
87
+ throw new Error(\`EMAIL_TRANSPORT must be "console" or "smtp", got "\${kind}".\`);
88
+ }
89
+ transport = kind === "smtp" ? smtpTransport(config.email) : consoleTransport(logger);
90
+ },
91
+
92
+ async stop() {
93
+ transport?.close();
94
+ transport = undefined;
95
+ },
96
+
97
+ async health() {
98
+ return transport === undefined ? false : transport.verify();
99
+ },
100
+ };
101
+ `;
102
+ export const emailRecipe = {
103
+ scope: "app",
104
+ feature: "email",
105
+ summary: "Email transport (src/integrations/email.ts): console in development, SMTP via nodemailer",
106
+ dependencies: { nodemailer: DEPENDENCY_VERSION_RANGES.nodemailer },
107
+ env: () => [
108
+ { name: "EMAIL_TRANSPORT", value: "console", comment: "console (logs only) or smtp" },
109
+ { name: "EMAIL_FROM", value: "no-reply@localhost" },
110
+ { name: "SMTP_HOST", value: "localhost" },
111
+ { name: "SMTP_PORT", value: "1025" },
112
+ { name: "SMTP_SECURE", value: "false" },
113
+ { name: "SMTP_USER", value: "" },
114
+ { name: "SMTP_PASSWORD", value: "", comment: "Issued by your SMTP provider; unused by the console transport and Mailpit" },
115
+ ],
116
+ configSection: `email: Object.freeze({ transport: text(config, "email_transport", "console"), from: text(config, "email_from", "no-reply@localhost"), smtpHost: text(config, "smtp_host", "localhost"), smtpPort: int(config, "smtp_port", 1025), smtpSecure: text(config, "smtp_secure", "false") === "true", smtpUser: text(config, "smtp_user", ""), smtpPassword: text(config, "smtp_password", "") }),`,
117
+ integration: { file: "email.ts", exportName: "emailIntegration", source },
118
+ nextSteps: () => [
119
+ `Send with: import { email } from "./integrations/email.js"; await email().send({ to, subject, text });`,
120
+ ],
121
+ };
122
+ //# sourceMappingURL=email.recipe.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * zudojs-cli — App recipes, one per feature.
3
+ */
4
+ export { emailRecipe } from "./email.recipe.js";
5
+ export { openapiRecipe } from "./openapi.recipe.js";
6
+ export { redisRecipe } from "./redis.recipe.js";
7
+ export { storageRecipe } from "./storage.recipe.js";
8
+ export { websocketsRecipe } from "./websockets.recipe.js";
9
+ export { databaseRecipe } from "./database/index.js";
10
+ export * from "./platform/index.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * zudojs-cli — App recipes, one per feature.
3
+ */
4
+ export { emailRecipe } from "./email.recipe.js";
5
+ export { openapiRecipe } from "./openapi.recipe.js";
6
+ export { redisRecipe } from "./redis.recipe.js";
7
+ export { storageRecipe } from "./storage.recipe.js";
8
+ export { websocketsRecipe } from "./websockets.recipe.js";
9
+ export { databaseRecipe } from "./database/index.js";
10
+ export * from "./platform/index.js";
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add openapi`: serves the OpenAPI document generated
3
+ * from the router at /openapi.json and a documentation page at /docs, by
4
+ * adding `mountOpenAPI` to `src/server.ts`.
5
+ */
6
+ import type { AppRecipe } from "../recipe.type.js";
7
+ export declare const openapiRecipe: AppRecipe;
8
+ //# sourceMappingURL=openapi.recipe.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add openapi`: serves the OpenAPI document generated
3
+ * from the router at /openapi.json and a documentation page at /docs, by
4
+ * adding `mountOpenAPI` to `src/server.ts`.
5
+ */
6
+ import { zudojsDependencies } from "../../constants/index.js";
7
+ import { openApiServerLines } from "../../templates/shared/server.template.js";
8
+ import { MARKERS } from "../../wiring/index.js";
9
+ export const openapiRecipe = {
10
+ scope: "app",
11
+ feature: "openapi",
12
+ summary: "OpenAPI document at /openapi.json and a docs page at /docs",
13
+ dependencies: zudojsDependencies(["@zudojs/openapi"]),
14
+ serverLines: (context) => {
15
+ const lines = openApiServerLines(context.projectSlug);
16
+ return [
17
+ { marker: MARKERS.serverImports, line: lines.importLine },
18
+ { marker: MARKERS.serverMounts, line: lines.mountLine },
19
+ ];
20
+ },
21
+ nextSteps: () => [
22
+ "Describe routes with the `openapi` route option; hide one with `openapi: false`.",
23
+ ],
24
+ };
25
+ //# sourceMappingURL=openapi.recipe.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * zudojs-cli — `zudojs add cache`: an in-memory cache (@zudojs/cache) with
3
+ * a bounded entry count and a default TTL from the environment.
4
+ */
5
+ import type { AppRecipe } from "../../recipe.type.js";
6
+ export declare const cacheRecipe: AppRecipe;
7
+ //# sourceMappingURL=cache.recipe.d.ts.map