@decohere/scaffold 0.0.1-dev.18 → 0.0.1-dev.80

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 (240) hide show
  1. package/commonjs/src/add-api.action.js +39 -0
  2. package/commonjs/src/add-api.command.js +41 -0
  3. package/commonjs/src/add.command.js +24 -0
  4. package/commonjs/src/add.module.js +26 -0
  5. package/commonjs/src/cli.js +9 -0
  6. package/commonjs/src/create.command.js +24 -0
  7. package/commonjs/src/create.module.js +26 -0
  8. package/commonjs/src/domain/prompt.js +64 -0
  9. package/commonjs/src/index.js +38 -0
  10. package/commonjs/src/models/compose.model.js +150 -0
  11. package/commonjs/src/models/config-yaml.model.js +88 -0
  12. package/commonjs/src/models/const.js +32 -0
  13. package/commonjs/src/models/dev-container.model.js +116 -0
  14. package/commonjs/src/models/docker-image.model.js +259 -0
  15. package/commonjs/src/models/env-file.model.js +50 -0
  16. package/commonjs/src/models/gitignore.model.js +43 -0
  17. package/commonjs/src/models/launch-json.model.js +74 -0
  18. package/commonjs/src/models/package-json.model.js +149 -0
  19. package/commonjs/src/models/project.model.js +134 -0
  20. package/commonjs/src/models/source-file.js +6 -0
  21. package/commonjs/src/models/tsconfig.model.js +34 -0
  22. package/commonjs/src/models/vitest-config.model.js +35 -0
  23. package/commonjs/src/models/vscode-settings.model.js +31 -0
  24. package/commonjs/src/program.js +57 -0
  25. package/commonjs/src/resolve-target-dir.js +19 -0
  26. package/commonjs/src/services/scaffold.service.js +62 -0
  27. package/commonjs/src/version.js +57 -0
  28. package/commonjs/src/webapi/api-name.js +95 -0
  29. package/commonjs/src/webapi/cli-options.js +101 -0
  30. package/commonjs/src/webapi/const.js +50 -0
  31. package/commonjs/src/webapi/create-api.js +237 -0
  32. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.js +166 -0
  33. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  34. package/commonjs/src/webapi/devcontainer/host-scripts.js +52 -0
  35. package/commonjs/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  36. package/commonjs/src/webapi/devcontainer/templates/initialize.sh +169 -0
  37. package/commonjs/src/webapi/devcontainer/templates/post-create.sh +35 -0
  38. package/commonjs/src/webapi/devcontainer/templates/post-start.sh +65 -0
  39. package/commonjs/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  40. package/commonjs/src/webapi/features/auth.feature.js +441 -0
  41. package/commonjs/src/webapi/features/auth0-cli.js +435 -0
  42. package/commonjs/src/webapi/features/biome-format.js +49 -0
  43. package/commonjs/src/webapi/features/database.feature.js +433 -0
  44. package/commonjs/src/webapi/features/finalize.feature.js +95 -0
  45. package/commonjs/src/webapi/features/postman.feature.js +324 -0
  46. package/commonjs/src/webapi/models/api-package-json.model.js +60 -0
  47. package/commonjs/src/webapi/models/auth-config.model.js +26 -0
  48. package/commonjs/src/webapi/models/controller-source-file.model.js +193 -0
  49. package/commonjs/src/webapi/models/github-ci.model.js +193 -0
  50. package/commonjs/src/webapi/models/main-source-file.model.js +167 -0
  51. package/commonjs/src/webapi/models/production-dockerfile.model.js +157 -0
  52. package/commonjs/src/webapi/models/sample-files.model.js +60 -0
  53. package/commonjs/src/webapi/models/webapi-image.model.js +27 -0
  54. package/commonjs/src/webapi/postman/hello-openapi.js +175 -0
  55. package/commonjs/src/webapi/postman/local-view.js +184 -0
  56. package/commonjs/src/webapi/postman/openapi-to-postman.js +202 -0
  57. package/commonjs/src/webapi/workspace-readme.js +110 -0
  58. package/commonjs/src/webapi.action.js +30 -0
  59. package/commonjs/src/webapi.command.js +45 -0
  60. package/es6/src/add-api.action.js +29 -0
  61. package/es6/src/add-api.command.js +31 -0
  62. package/es6/src/add.command.js +14 -0
  63. package/es6/src/add.module.js +16 -0
  64. package/es6/src/cli.js +5 -0
  65. package/es6/src/create.command.js +14 -0
  66. package/es6/src/create.module.js +16 -0
  67. package/es6/src/domain/prompt.js +43 -0
  68. package/es6/src/index.js +8 -0
  69. package/es6/src/models/compose.model.js +144 -0
  70. package/es6/src/models/config-yaml.model.js +76 -0
  71. package/es6/src/models/const.js +22 -0
  72. package/es6/src/models/dev-container.model.js +106 -0
  73. package/es6/src/models/docker-image.model.js +217 -0
  74. package/es6/src/models/env-file.model.js +46 -0
  75. package/es6/src/models/gitignore.model.js +33 -0
  76. package/es6/src/models/launch-json.model.js +64 -0
  77. package/es6/src/models/package-json.model.js +137 -0
  78. package/es6/src/models/project.model.js +119 -0
  79. package/es6/src/models/source-file.js +3 -0
  80. package/es6/src/models/tsconfig.model.js +24 -0
  81. package/es6/src/models/vitest-config.model.js +25 -0
  82. package/es6/src/models/vscode-settings.model.js +21 -0
  83. package/es6/src/program.js +39 -0
  84. package/es6/src/resolve-target-dir.js +9 -0
  85. package/es6/src/services/scaffold.service.js +52 -0
  86. package/es6/src/version.js +36 -0
  87. package/es6/src/webapi/api-name.js +59 -0
  88. package/es6/src/webapi/cli-options.js +36 -0
  89. package/es6/src/webapi/const.js +20 -0
  90. package/es6/src/webapi/create-api.js +217 -0
  91. package/es6/src/webapi/devcontainer/codebase-rag-mcp.js +156 -0
  92. package/es6/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  93. package/es6/src/webapi/devcontainer/host-scripts.js +31 -0
  94. package/es6/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  95. package/es6/src/webapi/devcontainer/templates/initialize.sh +169 -0
  96. package/es6/src/webapi/devcontainer/templates/post-create.sh +35 -0
  97. package/es6/src/webapi/devcontainer/templates/post-start.sh +65 -0
  98. package/es6/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  99. package/es6/src/webapi/features/auth.feature.js +390 -0
  100. package/es6/src/webapi/features/auth0-cli.js +375 -0
  101. package/es6/src/webapi/features/biome-format.js +42 -0
  102. package/es6/src/webapi/features/database.feature.js +423 -0
  103. package/es6/src/webapi/features/finalize.feature.js +85 -0
  104. package/es6/src/webapi/features/postman.feature.js +258 -0
  105. package/es6/src/webapi/models/api-package-json.model.js +55 -0
  106. package/es6/src/webapi/models/auth-config.model.js +22 -0
  107. package/es6/src/webapi/models/controller-source-file.model.js +184 -0
  108. package/es6/src/webapi/models/github-ci.model.js +186 -0
  109. package/es6/src/webapi/models/main-source-file.model.js +163 -0
  110. package/es6/src/webapi/models/production-dockerfile.model.js +148 -0
  111. package/es6/src/webapi/models/sample-files.model.js +42 -0
  112. package/es6/src/webapi/models/webapi-image.model.js +20 -0
  113. package/es6/src/webapi/postman/hello-openapi.js +168 -0
  114. package/es6/src/webapi/postman/local-view.js +169 -0
  115. package/es6/src/webapi/postman/openapi-to-postman.js +179 -0
  116. package/es6/src/webapi/workspace-readme.js +89 -0
  117. package/es6/src/webapi.action.js +20 -0
  118. package/es6/src/webapi.command.js +35 -0
  119. package/package.json +8 -8
  120. package/types/src/add-api.action.d.ts +13 -0
  121. package/types/src/add-api.command.d.ts +7 -0
  122. package/types/src/add.command.d.ts +6 -0
  123. package/types/src/add.module.d.ts +14 -0
  124. package/types/src/cli.d.ts +2 -0
  125. package/types/src/create.command.d.ts +6 -0
  126. package/types/src/create.module.d.ts +14 -0
  127. package/types/src/domain/prompt.d.ts +4 -0
  128. package/types/src/models/compose.model.d.ts +64 -0
  129. package/types/src/models/config-yaml.model.d.ts +27 -0
  130. package/types/src/models/const.d.ts +20 -0
  131. package/types/src/models/dev-container.model.d.ts +37 -0
  132. package/types/src/models/docker-image.model.d.ts +84 -0
  133. package/types/src/models/env-file.model.d.ts +16 -0
  134. package/types/src/models/gitignore.model.d.ts +7 -0
  135. package/types/src/models/launch-json.model.d.ts +7 -0
  136. package/types/src/models/package-json.model.d.ts +35 -0
  137. package/types/src/models/project.model.d.ts +60 -0
  138. package/{src/models/source-file.ts → types/src/models/source-file.d.ts} +4 -6
  139. package/types/src/models/tsconfig.model.d.ts +5 -0
  140. package/types/src/models/vitest-config.model.d.ts +5 -0
  141. package/types/src/models/vscode-settings.model.d.ts +7 -0
  142. package/types/src/program.d.ts +3 -0
  143. package/{src/resolve-target-dir.ts → types/src/resolve-target-dir.d.ts} +1 -4
  144. package/types/src/services/scaffold.service.d.ts +22 -0
  145. package/types/src/version.d.ts +6 -0
  146. package/types/src/webapi/api-name.d.ts +14 -0
  147. package/types/src/webapi/cli-options.d.ts +6 -0
  148. package/{src/webapi/const.ts → types/src/webapi/const.d.ts} +7 -21
  149. package/types/src/webapi/create-api.d.ts +15 -0
  150. package/types/src/webapi/devcontainer/codebase-rag-mcp.d.ts +32 -0
  151. package/types/src/webapi/devcontainer/codebase-rag-mcp.ts +182 -0
  152. package/types/src/webapi/devcontainer/host-scripts.d.ts +7 -0
  153. package/types/src/webapi/devcontainer/templates/codebase-rag.env.example +3 -0
  154. package/types/src/webapi/devcontainer/templates/initialize.sh +169 -0
  155. package/types/src/webapi/devcontainer/templates/post-create.sh +35 -0
  156. package/types/src/webapi/devcontainer/templates/post-start.sh +65 -0
  157. package/types/src/webapi/devcontainer/templates/tty-prompt.sh +38 -0
  158. package/types/src/webapi/features/auth.feature.d.ts +10 -0
  159. package/types/src/webapi/features/auth0-cli.d.ts +80 -0
  160. package/types/src/webapi/features/biome-format.d.ts +5 -0
  161. package/types/src/webapi/features/database.feature.d.ts +7 -0
  162. package/types/src/webapi/features/finalize.feature.d.ts +2 -0
  163. package/types/src/webapi/features/postman.feature.d.ts +16 -0
  164. package/types/src/webapi/models/api-package-json.model.d.ts +18 -0
  165. package/types/src/webapi/models/auth-config.model.d.ts +26 -0
  166. package/types/src/webapi/models/controller-source-file.model.d.ts +46 -0
  167. package/types/src/webapi/models/github-ci.model.d.ts +9 -0
  168. package/types/src/webapi/models/main-source-file.model.d.ts +54 -0
  169. package/types/src/webapi/models/production-dockerfile.model.d.ts +23 -0
  170. package/types/src/webapi/models/sample-files.model.d.ts +7 -0
  171. package/types/src/webapi/models/webapi-image.model.d.ts +12 -0
  172. package/types/src/webapi/postman/hello-openapi.d.ts +19 -0
  173. package/types/src/webapi/postman/local-view.d.ts +17 -0
  174. package/types/src/webapi/postman/openapi-to-postman.d.ts +62 -0
  175. package/types/src/webapi/workspace-readme.d.ts +18 -0
  176. package/types/src/webapi.action.d.ts +14 -0
  177. package/types/src/webapi.command.d.ts +11 -0
  178. package/src/add-api.action.ts +0 -25
  179. package/src/add-api.command.ts +0 -31
  180. package/src/add.command.ts +0 -20
  181. package/src/add.module.ts +0 -11
  182. package/src/cli.ts +0 -4
  183. package/src/create.command.ts +0 -20
  184. package/src/create.module.ts +0 -11
  185. package/src/domain/prompt.ts +0 -50
  186. package/src/models/compose.model.ts +0 -205
  187. package/src/models/config-yaml.model.ts +0 -83
  188. package/src/models/const.ts +0 -20
  189. package/src/models/dev-container.model.ts +0 -136
  190. package/src/models/docker-image.model.ts +0 -343
  191. package/src/models/env-file.model.ts +0 -45
  192. package/src/models/gitignore.model.ts +0 -35
  193. package/src/models/launch-json.model.ts +0 -60
  194. package/src/models/package-json.model.ts +0 -169
  195. package/src/models/project.model.ts +0 -141
  196. package/src/models/tsconfig.model.ts +0 -29
  197. package/src/models/vitest-config.model.ts +0 -26
  198. package/src/models/vscode-settings.model.ts +0 -24
  199. package/src/program.ts +0 -63
  200. package/src/services/scaffold.service.ts +0 -89
  201. package/src/version.ts +0 -56
  202. package/src/webapi/api-name.ts +0 -73
  203. package/src/webapi/cli-options.ts +0 -56
  204. package/src/webapi/create-api.ts +0 -275
  205. package/src/webapi/devcontainer/host-scripts.ts +0 -35
  206. package/src/webapi/features/auth.feature.ts +0 -454
  207. package/src/webapi/features/auth0-cli.ts +0 -421
  208. package/src/webapi/features/biome-format.ts +0 -34
  209. package/src/webapi/features/database.feature.ts +0 -522
  210. package/src/webapi/features/finalize.feature.ts +0 -112
  211. package/src/webapi/features/postman.feature.ts +0 -287
  212. package/src/webapi/models/api-package-json.model.ts +0 -60
  213. package/src/webapi/models/auth-config.model.ts +0 -36
  214. package/src/webapi/models/controller-source-file.model.ts +0 -232
  215. package/src/webapi/models/github-ci.model.ts +0 -188
  216. package/src/webapi/models/main-source-file.model.ts +0 -208
  217. package/src/webapi/models/production-dockerfile.model.ts +0 -162
  218. package/src/webapi/models/sample-files.model.ts +0 -45
  219. package/src/webapi/models/webapi-image.model.ts +0 -21
  220. package/src/webapi/postman/hello-openapi.ts +0 -92
  221. package/src/webapi/postman/local-view.ts +0 -195
  222. package/src/webapi/postman/openapi-to-postman.ts +0 -208
  223. package/src/webapi/workspace-readme.ts +0 -192
  224. package/src/webapi.action.ts +0 -22
  225. package/src/webapi.command.ts +0 -41
  226. package/tests/auth-postman.wiring.spec.ts +0 -263
  227. package/tests/auth0-cli.spec.ts +0 -232
  228. package/tests/biome-format.spec.ts +0 -49
  229. package/tests/cli.integration.spec.ts +0 -658
  230. package/tests/compose.model.spec.ts +0 -51
  231. package/tests/container-image.model.spec.ts +0 -162
  232. package/tests/dev-container.model.spec.ts +0 -29
  233. package/tests/devcontainer-base-image.spec.ts +0 -32
  234. package/tests/hello-di-inject.scaffold.spec.ts +0 -18
  235. package/tests/hello-route.contract.spec.ts +0 -94
  236. package/tests/package-json.order.spec.ts +0 -59
  237. package/tests/postman-from-openapi.spec.ts +0 -197
  238. package/tests/seed-devcontainer-templates.ts +0 -40
  239. package/tests/webapi/devcontainer/codebase-rag-mcp.spec.ts +0 -96
  240. /package/{src/index.ts → types/src/index.d.ts} +0 -0
@@ -0,0 +1,89 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { WELL_KNOWN_FILES } from "../models/const.js";
4
+ import { apiNameFromProjectDir, listExistingApiNames } from "./api-name.js";
5
+ /** Pure renderer — keep feature sections short and copy-paste ready. */ export function renderWorkspaceReadme(input) {
6
+ const { projectName, apiNames, hasPostgres, hasAuth0, hasPostman } = input;
7
+ const apis = apiNames.length > 0 ? apiNames : [
8
+ "api"
9
+ ];
10
+ const lines = [
11
+ `# ${projectName}`,
12
+ "",
13
+ "Decohere web API workspace. Scaffolded with [`@decohere/create`](https://www.npmjs.com/package/@decohere/create).",
14
+ "",
15
+ "## Get started",
16
+ "",
17
+ "1. Open this folder in VS Code / Cursor.",
18
+ "2. **Reopen in Container** (or rebuild the Dev Container).",
19
+ " Host `initialize.sh` and container `post-start.sh` ask y/N (TTY only) before npm auth or codebase RAG MCP.",
20
+ " Skip or decline; missing TTY skips. RAG credentials land in `.cursor/` (gitignored).",
21
+ "3. Install dependencies if needed:",
22
+ "",
23
+ "```bash",
24
+ "pnpm install",
25
+ "```",
26
+ "",
27
+ "## Develop",
28
+ "",
29
+ "```bash",
30
+ "pnpm dev # Flux HMR (first API)",
31
+ "pnpm start # run the compiled first API",
32
+ "pnpm run build # forge release build"
33
+ ];
34
+ for (const name of apis){
35
+ lines.push(`pnpm run dev:${name} # HMR for ${name}`);
36
+ lines.push(`pnpm run start:${name} # production entry for ${name}`);
37
+ }
38
+ lines.push("```", "");
39
+ lines.push("## Logging", "", "In development, Scribe uses pino-pretty and rolling files under `logs/` (gitignored).", "When `NODE_ENV=production`, the process writes structured JSON to stdout and does not rotate files.", "Ship and retain those streams outside the app (platform logs, a sidecar, or a log agent) so shipping can change without rebuilding.", "", "Override roll path and rotation without changing app code:", "`SCRIBE_LOG_FILE`, `SCRIBE_LOG_SIZE`, `SCRIBE_LOG_FREQUENCY`, `SCRIBE_LOG_KEEP`.", "", 'Opt into in-process pretty or roll in production only with `{ when: "always" }` on `scribe.withPinoPretty` / `scribe.withPinoRoll`.', "");
40
+ if (hasPostgres) {
41
+ lines.push("## Database", "", "Postgres runs via Dev Container Compose:", "", "```bash", "pnpm db:up", "pnpm db:down", "pnpm db:reset", "```", "");
42
+ }
43
+ lines.push("## Deploy", "", "PaaS hosts (`docker build` from the repo root) use the scaffolded `Dockerfile`.", "The runtime image installs production dependencies only (`pnpm install --prod`);", "Forge, TypeScript, Biome, and Vitest stay in the build stage.", "", "```bash", `docker build -t ${projectName} .`, "```", "", "Extra APIs: `docker build -f Dockerfile.<name> .`", "");
44
+ lines.push("## Add another API", "", "```bash", "decohere add api <name>", "```", "", "Example: `decohere add api billing`", "");
45
+ if (hasAuth0) {
46
+ lines.push("## Auth0", "", "JWT auth is wired from `.env` (`AUTH0_ISSUER_BASE_URL`, `AUTH0_AUDIENCE`).", "Set those values (or re-run scaffold with `--auth auth0`) before calling protected routes.", "");
47
+ }
48
+ if (hasPostman) {
49
+ lines.push("## Postman", "", "Open this **project root** in Postman Local View (Files → Open folder), not the `postman/` subfolder.", "Select the Local environment, then Authorization → Get New Access Token when Auth0 is enabled.", "");
50
+ }
51
+ lines.push("## More", "", "- Package docs: https://www.npmjs.com/package/@decohere/create", "- After `decohere add api`, this README is refreshed so scripts and APIs stay accurate.", "");
52
+ return `${lines.join("\n")}`;
53
+ }
54
+ export function resolveWorkspaceReadmeInput(workspace, options) {
55
+ const newNames = workspace.getProjects().map((project)=>apiNameFromProjectDir(project.dir));
56
+ const apiNames = options.add ? mergeApiNames(listExistingApiNames(workspace.targetDir), newNames) : newNames;
57
+ const pkg = workspace.getModel(WELL_KNOWN_FILES.PACKAGE_JSON);
58
+ const env = workspace.getModel(WELL_KNOWN_FILES.ENV_FILE);
59
+ const hasPostgres = options.databaseProvider === "postgres/typeorm" || Boolean(pkg?.hasScript("db:up"));
60
+ const hasAuth0 = options.authProvider === "auth0" || Boolean(env?.hasEntry("AUTH0_ISSUER_BASE_URL"));
61
+ const hasPostman = options.postmanProvider === "local" || options.postmanProvider === "api" || existsSync(join(workspace.targetDir, "postman")) || existsSync(join(workspace.targetDir, ".postman"));
62
+ return {
63
+ projectName: workspace.name,
64
+ apiNames,
65
+ hasPostgres,
66
+ hasAuth0,
67
+ hasPostman
68
+ };
69
+ }
70
+ export function writeWorkspaceReadme(workspace, options) {
71
+ const content = renderWorkspaceReadme(resolveWorkspaceReadmeInput(workspace, options));
72
+ workspace.addFile({
73
+ files: ()=>[
74
+ {
75
+ filePath: "README.md",
76
+ content
77
+ }
78
+ ]
79
+ });
80
+ }
81
+ function mergeApiNames(existing, added) {
82
+ const seen = new Set(existing);
83
+ return [
84
+ ...existing,
85
+ ...added.filter((name)=>!seen.has(name))
86
+ ];
87
+ }
88
+
89
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvd29ya3NwYWNlLXJlYWRtZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBleGlzdHNTeW5jIH0gZnJvbSBcIm5vZGU6ZnNcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBXRUxMX0tOT1dOX0ZJTEVTIH0gZnJvbSBcIi4uL21vZGVscy9jb25zdC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBFbnZGaWxlIH0gZnJvbSBcIi4uL21vZGVscy9lbnYtZmlsZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBQYWNrYWdlSnNvbiB9IGZyb20gXCIuLi9tb2RlbHMvcGFja2FnZS1qc29uLm1vZGVsLmpzXCI7XG5pbXBvcnQgdHlwZSB7IFdvcmtzcGFjZVNjYWZmb2xkIH0gZnJvbSBcIi4uL21vZGVscy9wcm9qZWN0Lm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBhcGlOYW1lRnJvbVByb2plY3REaXIsIGxpc3RFeGlzdGluZ0FwaU5hbWVzIH0gZnJvbSBcIi4vYXBpLW5hbWUuanNcIjtcblxuZXhwb3J0IHR5cGUgV29ya3NwYWNlUmVhZG1lT3B0aW9ucyA9IHtcblx0YWRkPzogYm9vbGVhbjtcblx0ZGF0YWJhc2VQcm92aWRlcj86IFwibm9uZVwiIHwgXCJwb3N0Z3Jlcy90eXBlb3JtXCI7XG5cdGF1dGhQcm92aWRlcj86IFwiYXV0aDBcIiB8IFwibm9uZVwiO1xuXHRwb3N0bWFuUHJvdmlkZXI/OiBcImFwaVwiIHwgXCJsb2NhbFwiIHwgXCJub25lXCI7XG59O1xuXG5leHBvcnQgdHlwZSBXb3Jrc3BhY2VSZWFkbWVJbnB1dCA9IHtcblx0cHJvamVjdE5hbWU6IHN0cmluZztcblx0YXBpTmFtZXM6IHJlYWRvbmx5IHN0cmluZ1tdO1xuXHRoYXNQb3N0Z3JlczogYm9vbGVhbjtcblx0aGFzQXV0aDA6IGJvb2xlYW47XG5cdGhhc1Bvc3RtYW46IGJvb2xlYW47XG59O1xuXG4vKiogUHVyZSByZW5kZXJlciDigJQga2VlcCBmZWF0dXJlIHNlY3Rpb25zIHNob3J0IGFuZCBjb3B5LXBhc3RlIHJlYWR5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlbmRlcldvcmtzcGFjZVJlYWRtZShpbnB1dDogV29ya3NwYWNlUmVhZG1lSW5wdXQpOiBzdHJpbmcge1xuXHRjb25zdCB7IHByb2plY3ROYW1lLCBhcGlOYW1lcywgaGFzUG9zdGdyZXMsIGhhc0F1dGgwLCBoYXNQb3N0bWFuIH0gPSBpbnB1dDtcblx0Y29uc3QgYXBpcyA9IGFwaU5hbWVzLmxlbmd0aCA+IDAgPyBhcGlOYW1lcyA6IFtcImFwaVwiXTtcblx0Y29uc3QgbGluZXM6IHN0cmluZ1tdID0gW1xuXHRcdGAjICR7cHJvamVjdE5hbWV9YCxcblx0XHRcIlwiLFxuXHRcdFwiRGVjb2hlcmUgd2ViIEFQSSB3b3Jrc3BhY2UuIFNjYWZmb2xkZWQgd2l0aCBbYEBkZWNvaGVyZS9jcmVhdGVgXShodHRwczovL3d3dy5ucG1qcy5jb20vcGFja2FnZS9AZGVjb2hlcmUvY3JlYXRlKS5cIixcblx0XHRcIlwiLFxuXHRcdFwiIyMgR2V0IHN0YXJ0ZWRcIixcblx0XHRcIlwiLFxuXHRcdFwiMS4gT3BlbiB0aGlzIGZvbGRlciBpbiBWUyBDb2RlIC8gQ3Vyc29yLlwiLFxuXHRcdFwiMi4gKipSZW9wZW4gaW4gQ29udGFpbmVyKiogKG9yIHJlYnVpbGQgdGhlIERldiBDb250YWluZXIpLlwiLFxuXHRcdFwiICAgSG9zdCBgaW5pdGlhbGl6ZS5zaGAgYW5kIGNvbnRhaW5lciBgcG9zdC1zdGFydC5zaGAgYXNrIHkvTiAoVFRZIG9ubHkpIGJlZm9yZSBucG0gYXV0aCBvciBjb2RlYmFzZSBSQUcgTUNQLlwiLFxuXHRcdFwiICAgU2tpcCBvciBkZWNsaW5lOyBtaXNzaW5nIFRUWSBza2lwcy4gUkFHIGNyZWRlbnRpYWxzIGxhbmQgaW4gYC5jdXJzb3IvYCAoZ2l0aWdub3JlZCkuXCIsXG5cdFx0XCIzLiBJbnN0YWxsIGRlcGVuZGVuY2llcyBpZiBuZWVkZWQ6XCIsXG5cdFx0XCJcIixcblx0XHRcImBgYGJhc2hcIixcblx0XHRcInBucG0gaW5zdGFsbFwiLFxuXHRcdFwiYGBgXCIsXG5cdFx0XCJcIixcblx0XHRcIiMjIERldmVsb3BcIixcblx0XHRcIlwiLFxuXHRcdFwiYGBgYmFzaFwiLFxuXHRcdFwicG5wbSBkZXYgICAgICAgICAgICAgICMgRmx1eCBITVIgKGZpcnN0IEFQSSlcIixcblx0XHRcInBucG0gc3RhcnQgICAgICAgICAgICAjIHJ1biB0aGUgY29tcGlsZWQgZmlyc3QgQVBJXCIsXG5cdFx0XCJwbnBtIHJ1biBidWlsZCAgICAgICAgIyBmb3JnZSByZWxlYXNlIGJ1aWxkXCIsXG5cdF07XG5cblx0Zm9yIChjb25zdCBuYW1lIG9mIGFwaXMpIHtcblx0XHRsaW5lcy5wdXNoKGBwbnBtIHJ1biBkZXY6JHtuYW1lfSAgICAgIyBITVIgZm9yICR7bmFtZX1gKTtcblx0XHRsaW5lcy5wdXNoKGBwbnBtIHJ1biBzdGFydDoke25hbWV9ICAgIyBwcm9kdWN0aW9uIGVudHJ5IGZvciAke25hbWV9YCk7XG5cdH1cblxuXHRsaW5lcy5wdXNoKFwiYGBgXCIsIFwiXCIpO1xuXG5cdGxpbmVzLnB1c2goXG5cdFx0XCIjIyBMb2dnaW5nXCIsXG5cdFx0XCJcIixcblx0XHRcIkluIGRldmVsb3BtZW50LCBTY3JpYmUgdXNlcyBwaW5vLXByZXR0eSBhbmQgcm9sbGluZyBmaWxlcyB1bmRlciBgbG9ncy9gIChnaXRpZ25vcmVkKS5cIixcblx0XHRcIldoZW4gYE5PREVfRU5WPXByb2R1Y3Rpb25gLCB0aGUgcHJvY2VzcyB3cml0ZXMgc3RydWN0dXJlZCBKU09OIHRvIHN0ZG91dCBhbmQgZG9lcyBub3Qgcm90YXRlIGZpbGVzLlwiLFxuXHRcdFwiU2hpcCBhbmQgcmV0YWluIHRob3NlIHN0cmVhbXMgb3V0c2lkZSB0aGUgYXBwIChwbGF0Zm9ybSBsb2dzLCBhIHNpZGVjYXIsIG9yIGEgbG9nIGFnZW50KSBzbyBzaGlwcGluZyBjYW4gY2hhbmdlIHdpdGhvdXQgcmVidWlsZGluZy5cIixcblx0XHRcIlwiLFxuXHRcdFwiT3ZlcnJpZGUgcm9sbCBwYXRoIGFuZCByb3RhdGlvbiB3aXRob3V0IGNoYW5naW5nIGFwcCBjb2RlOlwiLFxuXHRcdFwiYFNDUklCRV9MT0dfRklMRWAsIGBTQ1JJQkVfTE9HX1NJWkVgLCBgU0NSSUJFX0xPR19GUkVRVUVOQ1lgLCBgU0NSSUJFX0xPR19LRUVQYC5cIixcblx0XHRcIlwiLFxuXHRcdCdPcHQgaW50byBpbi1wcm9jZXNzIHByZXR0eSBvciByb2xsIGluIHByb2R1Y3Rpb24gb25seSB3aXRoIGB7IHdoZW46IFwiYWx3YXlzXCIgfWAgb24gYHNjcmliZS53aXRoUGlub1ByZXR0eWAgLyBgc2NyaWJlLndpdGhQaW5vUm9sbGAuJyxcblx0XHRcIlwiLFxuXHQpO1xuXG5cdGlmIChoYXNQb3N0Z3Jlcykge1xuXHRcdGxpbmVzLnB1c2goXG5cdFx0XHRcIiMjIERhdGFiYXNlXCIsXG5cdFx0XHRcIlwiLFxuXHRcdFx0XCJQb3N0Z3JlcyBydW5zIHZpYSBEZXYgQ29udGFpbmVyIENvbXBvc2U6XCIsXG5cdFx0XHRcIlwiLFxuXHRcdFx0XCJgYGBiYXNoXCIsXG5cdFx0XHRcInBucG0gZGI6dXBcIixcblx0XHRcdFwicG5wbSBkYjpkb3duXCIsXG5cdFx0XHRcInBucG0gZGI6cmVzZXRcIixcblx0XHRcdFwiYGBgXCIsXG5cdFx0XHRcIlwiLFxuXHRcdCk7XG5cdH1cblxuXHRsaW5lcy5wdXNoKFxuXHRcdFwiIyMgRGVwbG95XCIsXG5cdFx0XCJcIixcblx0XHRcIlBhYVMgaG9zdHMgKGBkb2NrZXIgYnVpbGRgIGZyb20gdGhlIHJlcG8gcm9vdCkgdXNlIHRoZSBzY2FmZm9sZGVkIGBEb2NrZXJmaWxlYC5cIixcblx0XHRcIlRoZSBydW50aW1lIGltYWdlIGluc3RhbGxzIHByb2R1Y3Rpb24gZGVwZW5kZW5jaWVzIG9ubHkgKGBwbnBtIGluc3RhbGwgLS1wcm9kYCk7XCIsXG5cdFx0XCJGb3JnZSwgVHlwZVNjcmlwdCwgQmlvbWUsIGFuZCBWaXRlc3Qgc3RheSBpbiB0aGUgYnVpbGQgc3RhZ2UuXCIsXG5cdFx0XCJcIixcblx0XHRcImBgYGJhc2hcIixcblx0XHRgZG9ja2VyIGJ1aWxkIC10ICR7cHJvamVjdE5hbWV9IC5gLFxuXHRcdFwiYGBgXCIsXG5cdFx0XCJcIixcblx0XHRcIkV4dHJhIEFQSXM6IGBkb2NrZXIgYnVpbGQgLWYgRG9ja2VyZmlsZS48bmFtZT4gLmBcIixcblx0XHRcIlwiLFxuXHQpO1xuXG5cdGxpbmVzLnB1c2goXG5cdFx0XCIjIyBBZGQgYW5vdGhlciBBUElcIixcblx0XHRcIlwiLFxuXHRcdFwiYGBgYmFzaFwiLFxuXHRcdFwiZGVjb2hlcmUgYWRkIGFwaSA8bmFtZT5cIixcblx0XHRcImBgYFwiLFxuXHRcdFwiXCIsXG5cdFx0XCJFeGFtcGxlOiBgZGVjb2hlcmUgYWRkIGFwaSBiaWxsaW5nYFwiLFxuXHRcdFwiXCIsXG5cdCk7XG5cblx0aWYgKGhhc0F1dGgwKSB7XG5cdFx0bGluZXMucHVzaChcblx0XHRcdFwiIyMgQXV0aDBcIixcblx0XHRcdFwiXCIsXG5cdFx0XHRcIkpXVCBhdXRoIGlzIHdpcmVkIGZyb20gYC5lbnZgIChgQVVUSDBfSVNTVUVSX0JBU0VfVVJMYCwgYEFVVEgwX0FVRElFTkNFYCkuXCIsXG5cdFx0XHRcIlNldCB0aG9zZSB2YWx1ZXMgKG9yIHJlLXJ1biBzY2FmZm9sZCB3aXRoIGAtLWF1dGggYXV0aDBgKSBiZWZvcmUgY2FsbGluZyBwcm90ZWN0ZWQgcm91dGVzLlwiLFxuXHRcdFx0XCJcIixcblx0XHQpO1xuXHR9XG5cblx0aWYgKGhhc1Bvc3RtYW4pIHtcblx0XHRsaW5lcy5wdXNoKFxuXHRcdFx0XCIjIyBQb3N0bWFuXCIsXG5cdFx0XHRcIlwiLFxuXHRcdFx0XCJPcGVuIHRoaXMgKipwcm9qZWN0IHJvb3QqKiBpbiBQb3N0bWFuIExvY2FsIFZpZXcgKEZpbGVzIOKGkiBPcGVuIGZvbGRlciksIG5vdCB0aGUgYHBvc3RtYW4vYCBzdWJmb2xkZXIuXCIsXG5cdFx0XHRcIlNlbGVjdCB0aGUgTG9jYWwgZW52aXJvbm1lbnQsIHRoZW4gQXV0aG9yaXphdGlvbiDihpIgR2V0IE5ldyBBY2Nlc3MgVG9rZW4gd2hlbiBBdXRoMCBpcyBlbmFibGVkLlwiLFxuXHRcdFx0XCJcIixcblx0XHQpO1xuXHR9XG5cblx0bGluZXMucHVzaChcblx0XHRcIiMjIE1vcmVcIixcblx0XHRcIlwiLFxuXHRcdFwiLSBQYWNrYWdlIGRvY3M6IGh0dHBzOi8vd3d3Lm5wbWpzLmNvbS9wYWNrYWdlL0BkZWNvaGVyZS9jcmVhdGVcIixcblx0XHRcIi0gQWZ0ZXIgYGRlY29oZXJlIGFkZCBhcGlgLCB0aGlzIFJFQURNRSBpcyByZWZyZXNoZWQgc28gc2NyaXB0cyBhbmQgQVBJcyBzdGF5IGFjY3VyYXRlLlwiLFxuXHRcdFwiXCIsXG5cdCk7XG5cblx0cmV0dXJuIGAke2xpbmVzLmpvaW4oXCJcXG5cIil9YDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVXb3Jrc3BhY2VSZWFkbWVJbnB1dChcblx0d29ya3NwYWNlOiBXb3Jrc3BhY2VTY2FmZm9sZCxcblx0b3B0aW9uczogV29ya3NwYWNlUmVhZG1lT3B0aW9ucyxcbik6IFdvcmtzcGFjZVJlYWRtZUlucHV0IHtcblx0Y29uc3QgbmV3TmFtZXMgPSB3b3Jrc3BhY2Vcblx0XHQuZ2V0UHJvamVjdHMoKVxuXHRcdC5tYXAoKHByb2plY3QpID0+IGFwaU5hbWVGcm9tUHJvamVjdERpcihwcm9qZWN0LmRpcikpO1xuXHRjb25zdCBhcGlOYW1lcyA9IG9wdGlvbnMuYWRkXG5cdFx0PyBtZXJnZUFwaU5hbWVzKGxpc3RFeGlzdGluZ0FwaU5hbWVzKHdvcmtzcGFjZS50YXJnZXREaXIpLCBuZXdOYW1lcylcblx0XHQ6IG5ld05hbWVzO1xuXG5cdGNvbnN0IHBrZyA9IHdvcmtzcGFjZS5nZXRNb2RlbDxQYWNrYWdlSnNvbj4oV0VMTF9LTk9XTl9GSUxFUy5QQUNLQUdFX0pTT04pO1xuXHRjb25zdCBlbnYgPSB3b3Jrc3BhY2UuZ2V0TW9kZWw8RW52RmlsZT4oV0VMTF9LTk9XTl9GSUxFUy5FTlZfRklMRSk7XG5cblx0Y29uc3QgaGFzUG9zdGdyZXMgPVxuXHRcdG9wdGlvbnMuZGF0YWJhc2VQcm92aWRlciA9PT0gXCJwb3N0Z3Jlcy90eXBlb3JtXCIgfHwgQm9vbGVhbihwa2c/Lmhhc1NjcmlwdChcImRiOnVwXCIpKTtcblx0Y29uc3QgaGFzQXV0aDAgPVxuXHRcdG9wdGlvbnMuYXV0aFByb3ZpZGVyID09PSBcImF1dGgwXCIgfHwgQm9vbGVhbihlbnY/Lmhhc0VudHJ5KFwiQVVUSDBfSVNTVUVSX0JBU0VfVVJMXCIpKTtcblx0Y29uc3QgaGFzUG9zdG1hbiA9XG5cdFx0b3B0aW9ucy5wb3N0bWFuUHJvdmlkZXIgPT09IFwibG9jYWxcIiB8fFxuXHRcdG9wdGlvbnMucG9zdG1hblByb3ZpZGVyID09PSBcImFwaVwiIHx8XG5cdFx0ZXhpc3RzU3luYyhqb2luKHdvcmtzcGFjZS50YXJnZXREaXIsIFwicG9zdG1hblwiKSkgfHxcblx0XHRleGlzdHNTeW5jKGpvaW4od29ya3NwYWNlLnRhcmdldERpciwgXCIucG9zdG1hblwiKSk7XG5cblx0cmV0dXJuIHtcblx0XHRwcm9qZWN0TmFtZTogd29ya3NwYWNlLm5hbWUsXG5cdFx0YXBpTmFtZXMsXG5cdFx0aGFzUG9zdGdyZXMsXG5cdFx0aGFzQXV0aDAsXG5cdFx0aGFzUG9zdG1hbixcblx0fTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHdyaXRlV29ya3NwYWNlUmVhZG1lKFxuXHR3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkLFxuXHRvcHRpb25zOiBXb3Jrc3BhY2VSZWFkbWVPcHRpb25zLFxuKTogdm9pZCB7XG5cdGNvbnN0IGNvbnRlbnQgPSByZW5kZXJXb3Jrc3BhY2VSZWFkbWUocmVzb2x2ZVdvcmtzcGFjZVJlYWRtZUlucHV0KHdvcmtzcGFjZSwgb3B0aW9ucykpO1xuXHR3b3Jrc3BhY2UuYWRkRmlsZSh7XG5cdFx0ZmlsZXM6ICgpID0+IFt7IGZpbGVQYXRoOiBcIlJFQURNRS5tZFwiLCBjb250ZW50IH1dLFxuXHR9KTtcbn1cblxuZnVuY3Rpb24gbWVyZ2VBcGlOYW1lcyhleGlzdGluZzogcmVhZG9ubHkgc3RyaW5nW10sIGFkZGVkOiByZWFkb25seSBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcblx0Y29uc3Qgc2VlbiA9IG5ldyBTZXQoZXhpc3RpbmcpO1xuXHRyZXR1cm4gWy4uLmV4aXN0aW5nLCAuLi5hZGRlZC5maWx0ZXIoKG5hbWUpID0+ICFzZWVuLmhhcyhuYW1lKSldO1xufVxuIl0sIm5hbWVzIjpbImV4aXN0c1N5bmMiLCJqb2luIiwiV0VMTF9LTk9XTl9GSUxFUyIsImFwaU5hbWVGcm9tUHJvamVjdERpciIsImxpc3RFeGlzdGluZ0FwaU5hbWVzIiwicmVuZGVyV29ya3NwYWNlUmVhZG1lIiwiaW5wdXQiLCJwcm9qZWN0TmFtZSIsImFwaU5hbWVzIiwiaGFzUG9zdGdyZXMiLCJoYXNBdXRoMCIsImhhc1Bvc3RtYW4iLCJhcGlzIiwibGVuZ3RoIiwibGluZXMiLCJuYW1lIiwicHVzaCIsInJlc29sdmVXb3Jrc3BhY2VSZWFkbWVJbnB1dCIsIndvcmtzcGFjZSIsIm9wdGlvbnMiLCJuZXdOYW1lcyIsImdldFByb2plY3RzIiwibWFwIiwicHJvamVjdCIsImRpciIsImFkZCIsIm1lcmdlQXBpTmFtZXMiLCJ0YXJnZXREaXIiLCJwa2ciLCJnZXRNb2RlbCIsIlBBQ0tBR0VfSlNPTiIsImVudiIsIkVOVl9GSUxFIiwiZGF0YWJhc2VQcm92aWRlciIsIkJvb2xlYW4iLCJoYXNTY3JpcHQiLCJhdXRoUHJvdmlkZXIiLCJoYXNFbnRyeSIsInBvc3RtYW5Qcm92aWRlciIsIndyaXRlV29ya3NwYWNlUmVhZG1lIiwiY29udGVudCIsImFkZEZpbGUiLCJmaWxlcyIsImZpbGVQYXRoIiwiZXhpc3RpbmciLCJhZGRlZCIsInNlZW4iLCJTZXQiLCJmaWx0ZXIiLCJoYXMiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLFVBQVUsUUFBUSxVQUFV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
@@ -0,0 +1,20 @@
1
+ function _ts_decorate(decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ }
7
+ import { injectable } from "@decohere/crucible/decorators";
8
+ import { ActionResponse } from "@decohere/nexus/cli";
9
+ import { runScaffoldApi, toApiOptions } from "./webapi/cli-options.js";
10
+ export class WebapiAction {
11
+ async run(options) {
12
+ await runScaffoldApi(toApiOptions(options.directory, options));
13
+ return ActionResponse.Success("webapi");
14
+ }
15
+ }
16
+ WebapiAction = _ts_decorate([
17
+ injectable()
18
+ ], WebapiAction);
19
+
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkuYWN0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGluamVjdGFibGUgfSBmcm9tIFwiQGRlY29oZXJlL2NydWNpYmxlL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IHR5cGUgQWN0aW9uLCBBY3Rpb25SZXNwb25zZSB9IGZyb20gXCJAZGVjb2hlcmUvbmV4dXMvY2xpXCI7XG5pbXBvcnQgeyBydW5TY2FmZm9sZEFwaSwgdG9BcGlPcHRpb25zIH0gZnJvbSBcIi4vd2ViYXBpL2NsaS1vcHRpb25zLmpzXCI7XG5cbmV4cG9ydCB0eXBlIFdlYmFwaU9wdGlvbnMgPSB7XG5cdGRpcmVjdG9yeT86IHN0cmluZztcblx0ZD86IHN0cmluZztcblx0bmFtZT86IHN0cmluZyB8IHN0cmluZ1tdO1xuXHRkYXRhYmFzZT86IHN0cmluZztcblx0YXV0aD86IHN0cmluZztcblx0cG9zdG1hbj86IHN0cmluZztcblx0eWVzPzogYm9vbGVhbjtcblx0aW5zdGFsbD86IHN0cmluZztcbn07XG5cbkBpbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBXZWJhcGlBY3Rpb24gaW1wbGVtZW50cyBBY3Rpb248V2ViYXBpT3B0aW9ucz4ge1xuXHRwdWJsaWMgYXN5bmMgcnVuKG9wdGlvbnM6IFdlYmFwaU9wdGlvbnMpOiBQcm9taXNlPEFjdGlvblJlc3BvbnNlPiB7XG5cdFx0YXdhaXQgcnVuU2NhZmZvbGRBcGkodG9BcGlPcHRpb25zKG9wdGlvbnMuZGlyZWN0b3J5LCBvcHRpb25zKSk7XG5cdFx0cmV0dXJuIEFjdGlvblJlc3BvbnNlLlN1Y2Nlc3MoXCJ3ZWJhcGlcIik7XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJpbmplY3RhYmxlIiwiQWN0aW9uUmVzcG9uc2UiLCJydW5TY2FmZm9sZEFwaSIsInRvQXBpT3B0aW9ucyIsIldlYmFwaUFjdGlvbiIsInJ1biIsIm9wdGlvbnMiLCJkaXJlY3RvcnkiLCJTdWNjZXNzIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxTQUFTQSxVQUFVLFFBQVEsZ0NBQWdDO0FBQzNELFNBQXNCQyxjQUFjLFFBQVEsc0JBQXNCO0FBQ2xFLFNBQVNDLGNBQWMsRUFBRUMsWUFBWSxRQUFRLDBCQUEwQjtBQWN2RSxPQUFPLE1BQU1DO0lBQ1osTUFBYUMsSUFBSUMsT0FBc0IsRUFBMkI7UUFDakUsTUFBTUosZUFBZUMsYUFBYUcsUUFBUUMsU0FBUyxFQUFFRDtRQUNyRCxPQUFPTCxlQUFlTyxPQUFPLENBQUM7SUFDL0I7QUFDRCJ9
@@ -0,0 +1,35 @@
1
+ import { DecohereCommand } from "@decohere/nexus/cli";
2
+ import { addWebapiFeatureOptions, collectName } from "./webapi/cli-options.js";
3
+ import { WebapiAction } from "./webapi.action.js";
4
+ export class WebapiCommand extends DecohereCommand {
5
+ get actions() {
6
+ return [
7
+ WebapiAction
8
+ ];
9
+ }
10
+ constructor(name){
11
+ super(name);
12
+ this.description("Scaffold a Cortex web API workspace");
13
+ this.argument("[directory]", "Target directory (default: -d or current directory)");
14
+ this.option("-d <directory>", "Target directory (default: current directory)", ".");
15
+ this.option("--name <slug>", "API name under projects/ (repeatable; default: api)", collectName, []);
16
+ addWebapiFeatureOptions(this);
17
+ }
18
+ /**
19
+ * Commander passes positional args before options when `[directory]` is declared.
20
+ * ModuleFactory expects `(opts, cmd)` — stash the directory on the command.
21
+ */ action(fn) {
22
+ return super.action((...args)=>{
23
+ const cmd = args.at(-1);
24
+ const first = args[0];
25
+ const hasPositional = typeof first === "string" || first === undefined;
26
+ const opts = hasPositional ? args[1] : args[0];
27
+ if (typeof first === "string" && first !== "") {
28
+ cmd.setOptionValue("directory", first);
29
+ }
30
+ return fn(opts, cmd);
31
+ });
32
+ }
33
+ }
34
+
35
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkuY29tbWFuZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEZWNvaGVyZUNvbW1hbmQgfSBmcm9tIFwiQGRlY29oZXJlL25leHVzL2NsaVwiO1xuaW1wb3J0IHR5cGUgeyBPcHRpb25WYWx1ZXMgfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyBhZGRXZWJhcGlGZWF0dXJlT3B0aW9ucywgY29sbGVjdE5hbWUgfSBmcm9tIFwiLi93ZWJhcGkvY2xpLW9wdGlvbnMuanNcIjtcbmltcG9ydCB7IFdlYmFwaUFjdGlvbiB9IGZyb20gXCIuL3dlYmFwaS5hY3Rpb24uanNcIjtcblxuZXhwb3J0IGNsYXNzIFdlYmFwaUNvbW1hbmQgZXh0ZW5kcyBEZWNvaGVyZUNvbW1hbmQge1xuXHRwdWJsaWMgb3ZlcnJpZGUgZ2V0IGFjdGlvbnMoKSB7XG5cdFx0cmV0dXJuIFtXZWJhcGlBY3Rpb25dO1xuXHR9XG5cblx0cHVibGljIGNvbnN0cnVjdG9yKG5hbWU6IHN0cmluZykge1xuXHRcdHN1cGVyKG5hbWUpO1xuXHRcdHRoaXMuZGVzY3JpcHRpb24oXCJTY2FmZm9sZCBhIENvcnRleCB3ZWIgQVBJIHdvcmtzcGFjZVwiKTtcblx0XHR0aGlzLmFyZ3VtZW50KFwiW2RpcmVjdG9yeV1cIiwgXCJUYXJnZXQgZGlyZWN0b3J5IChkZWZhdWx0OiAtZCBvciBjdXJyZW50IGRpcmVjdG9yeSlcIik7XG5cdFx0dGhpcy5vcHRpb24oXCItZCA8ZGlyZWN0b3J5PlwiLCBcIlRhcmdldCBkaXJlY3RvcnkgKGRlZmF1bHQ6IGN1cnJlbnQgZGlyZWN0b3J5KVwiLCBcIi5cIik7XG5cdFx0dGhpcy5vcHRpb24oXG5cdFx0XHRcIi0tbmFtZSA8c2x1Zz5cIixcblx0XHRcdFwiQVBJIG5hbWUgdW5kZXIgcHJvamVjdHMvIChyZXBlYXRhYmxlOyBkZWZhdWx0OiBhcGkpXCIsXG5cdFx0XHRjb2xsZWN0TmFtZSxcblx0XHRcdFtdIGFzIHN0cmluZ1tdLFxuXHRcdCk7XG5cdFx0YWRkV2ViYXBpRmVhdHVyZU9wdGlvbnModGhpcyk7XG5cdH1cblxuXHQvKipcblx0ICogQ29tbWFuZGVyIHBhc3NlcyBwb3NpdGlvbmFsIGFyZ3MgYmVmb3JlIG9wdGlvbnMgd2hlbiBgW2RpcmVjdG9yeV1gIGlzIGRlY2xhcmVkLlxuXHQgKiBNb2R1bGVGYWN0b3J5IGV4cGVjdHMgYChvcHRzLCBjbWQpYCDigJQgc3Rhc2ggdGhlIGRpcmVjdG9yeSBvbiB0aGUgY29tbWFuZC5cblx0ICovXG5cdHB1YmxpYyBvdmVycmlkZSBhY3Rpb24oZm46ICguLi5hcmdzOiB1bmtub3duW10pID0+IHZvaWQgfCBQcm9taXNlPHZvaWQ+KTogdGhpcyB7XG5cdFx0cmV0dXJuIHN1cGVyLmFjdGlvbigoLi4uYXJnczogdW5rbm93bltdKSA9PiB7XG5cdFx0XHRjb25zdCBjbWQgPSBhcmdzLmF0KC0xKSBhcyBEZWNvaGVyZUNvbW1hbmQ7XG5cdFx0XHRjb25zdCBmaXJzdCA9IGFyZ3NbMF07XG5cdFx0XHRjb25zdCBoYXNQb3NpdGlvbmFsID0gdHlwZW9mIGZpcnN0ID09PSBcInN0cmluZ1wiIHx8IGZpcnN0ID09PSB1bmRlZmluZWQ7XG5cdFx0XHRjb25zdCBvcHRzID0gaGFzUG9zaXRpb25hbCA/IChhcmdzWzFdIGFzIE9wdGlvblZhbHVlcykgOiAoYXJnc1swXSBhcyBPcHRpb25WYWx1ZXMpO1xuXHRcdFx0aWYgKHR5cGVvZiBmaXJzdCA9PT0gXCJzdHJpbmdcIiAmJiBmaXJzdCAhPT0gXCJcIikge1xuXHRcdFx0XHRjbWQuc2V0T3B0aW9uVmFsdWUoXCJkaXJlY3RvcnlcIiwgZmlyc3QpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZuKG9wdHMsIGNtZCk7XG5cdFx0fSk7XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJEZWNvaGVyZUNvbW1hbmQiLCJhZGRXZWJhcGlGZWF0dXJlT3B0aW9ucyIsImNvbGxlY3ROYW1lIiwiV2ViYXBpQWN0aW9uIiwiV2ViYXBpQ29tbWFuZCIsImFjdGlvbnMiLCJuYW1lIiwiZGVzY3JpcHRpb24iLCJhcmd1bWVudCIsIm9wdGlvbiIsImFjdGlvbiIsImZuIiwiYXJncyIsImNtZCIsImF0IiwiZmlyc3QiLCJoYXNQb3NpdGlvbmFsIiwidW5kZWZpbmVkIiwib3B0cyIsInNldE9wdGlvblZhbHVlIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxlQUFlLFFBQVEsc0JBQXNCO0FBRXRELFNBQVNDLHVCQUF1QixFQUFFQyxXQUFXLFFBQVEsMEJBQTBCO0FBQy9FLFNBQVNDLFlBQVksUUFBUSxxQkFBcUI7QUFFbEQsT0FBTyxNQUFNQyxzQkFBc0JKO0lBQ2xDLElBQW9CSyxVQUFVO1FBQzdCLE9BQU87WUFBQ0Y7U0FBYTtJQUN0QjtJQUVBLFlBQW1CRyxJQUFZLENBQUU7UUFDaEMsS0FBSyxDQUFDQTtRQUNOLElBQUksQ0FBQ0MsV0FBVyxDQUFDO1FBQ2pCLElBQUksQ0FBQ0MsUUFBUSxDQUFDLGVBQWU7UUFDN0IsSUFBSSxDQUFDQyxNQUFNLENBQUMsa0JBQWtCLGlEQUFpRDtRQUMvRSxJQUFJLENBQUNBLE1BQU0sQ0FDVixpQkFDQSx1REFDQVAsYUFDQSxFQUFFO1FBRUhELHdCQUF3QixJQUFJO0lBQzdCO0lBRUE7OztFQUdDLEdBQ0QsQUFBZ0JTLE9BQU9DLEVBQWdELEVBQVE7UUFDOUUsT0FBTyxLQUFLLENBQUNELE9BQU8sQ0FBQyxHQUFHRTtZQUN2QixNQUFNQyxNQUFNRCxLQUFLRSxFQUFFLENBQUMsQ0FBQztZQUNyQixNQUFNQyxRQUFRSCxJQUFJLENBQUMsRUFBRTtZQUNyQixNQUFNSSxnQkFBZ0IsT0FBT0QsVUFBVSxZQUFZQSxVQUFVRTtZQUM3RCxNQUFNQyxPQUFPRixnQkFBaUJKLElBQUksQ0FBQyxFQUFFLEdBQXFCQSxJQUFJLENBQUMsRUFBRTtZQUNqRSxJQUFJLE9BQU9HLFVBQVUsWUFBWUEsVUFBVSxJQUFJO2dCQUM5Q0YsSUFBSU0sY0FBYyxDQUFDLGFBQWFKO1lBQ2pDO1lBQ0EsT0FBT0osR0FBR08sTUFBTUw7UUFDakI7SUFDRDtBQUNEIn0=
package/package.json CHANGED
@@ -1,10 +1,6 @@
1
1
  {
2
2
  "name": "@decohere/scaffold",
3
- "version": "0.0.1-dev.18",
4
- "decohere": {
5
- "dockerImageRepository": "ghcr.io/typesmiths/decohere/create",
6
- "devcontainerImageRepository": "ghcr.io/typesmiths/decohere/devcontainer"
7
- },
3
+ "version": "0.0.1-dev.80",
8
4
  "description": "Decohere project scaffolder (runs inside ghcr.io/typesmiths/decohere/create)",
9
5
  "keywords": [
10
6
  "decohere",
@@ -26,10 +22,14 @@
26
22
  "test": "echo \"Error: no test specified\" && exit 1"
27
23
  },
28
24
  "dependencies": {
29
- "@decohere/crucible": "0.0.1-dev.5",
30
- "@decohere/nexus": "0.0.1-dev.5",
25
+ "@decohere/crucible": "0.0.1-dev.80",
26
+ "@decohere/nexus": "0.0.1-dev.80",
31
27
  "commander": "^13.1.0",
32
28
  "openapi-to-postmanv2": "^5.0.0"
33
29
  },
34
- "devDependencies": {}
30
+ "devDependencies": {},
31
+ "decohere": {
32
+ "dockerImageRepository": "ghcr.io/typesmiths/decohere/create",
33
+ "devcontainerImageRepository": "ghcr.io/typesmiths/decohere/devcontainer"
34
+ }
35
35
  }
@@ -0,0 +1,13 @@
1
+ import { type Action, ActionResponse } from "@decohere/nexus/cli";
2
+ export type AddApiOptions = {
3
+ apiName?: string;
4
+ d?: string;
5
+ database?: string;
6
+ auth?: string;
7
+ postman?: string;
8
+ yes?: boolean;
9
+ install?: string;
10
+ };
11
+ export declare class AddApiAction implements Action<AddApiOptions> {
12
+ run(options: AddApiOptions): Promise<ActionResponse>;
13
+ }
@@ -0,0 +1,7 @@
1
+ import { DecohereCommand } from "@decohere/nexus/cli";
2
+ import { AddApiAction } from "./add-api.action.js";
3
+ export declare class AddApiCommand extends DecohereCommand {
4
+ get actions(): (typeof AddApiAction)[];
5
+ constructor(name: string);
6
+ action(fn: (...args: unknown[]) => void | Promise<void>): this;
7
+ }
@@ -0,0 +1,6 @@
1
+ import type { Actions } from "@decohere/nexus/cli";
2
+ import { type CommandHandler, type CommandResponse, type CommandType, DecohereCommand } from "@decohere/nexus/cli";
3
+ export declare class AddCommand extends DecohereCommand {
4
+ constructor(commands: Record<string, CommandType>, handler: CommandHandler);
5
+ run(_actions: Actions, _options: never): Promise<CommandResponse>;
6
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleManifest } from "@decohere/nexus/cli";
2
+ import { AddCommand } from "./add.command.js";
3
+ import { AddApiAction } from "./add-api.action.js";
4
+ import { AddApiCommand } from "./add-api.command.js";
5
+ export declare class AddModule extends ModuleManifest {
6
+ readonly id = "add";
7
+ readonly command: typeof AddCommand;
8
+ readonly commands: {
9
+ api: typeof AddApiCommand;
10
+ };
11
+ readonly actions: {
12
+ api: typeof AddApiAction;
13
+ };
14
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { Actions } from "@decohere/nexus/cli";
2
+ import { type CommandHandler, type CommandResponse, type CommandType, DecohereCommand } from "@decohere/nexus/cli";
3
+ export declare class CreateCommand extends DecohereCommand {
4
+ constructor(commands: Record<string, CommandType>, handler: CommandHandler);
5
+ run(_actions: Actions, _options: never): Promise<CommandResponse>;
6
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleManifest } from "@decohere/nexus/cli";
2
+ import { CreateCommand } from "./create.command.js";
3
+ import { WebapiAction } from "./webapi.action.js";
4
+ import { WebapiCommand } from "./webapi.command.js";
5
+ export declare class CreateModule extends ModuleManifest {
6
+ readonly id = "create";
7
+ readonly command: typeof CreateCommand;
8
+ readonly commands: {
9
+ webapi: typeof WebapiCommand;
10
+ };
11
+ readonly actions: {
12
+ webapi: typeof WebapiAction;
13
+ };
14
+ }
@@ -0,0 +1,4 @@
1
+ /** Release stdin so the process can exit after interactive prompts. */
2
+ export declare function closePrompt(): void;
3
+ export declare function ask(question: string, fallback?: string): Promise<string>;
4
+ export declare function pick<T>(label: string, items: T[], display: (item: T) => string): Promise<T | null>;
@@ -0,0 +1,64 @@
1
+ import type { KeyedModel } from "./source-file.js";
2
+ export type ComposeNetworkRef = string | {
3
+ /** Network key under `networks:` on this service */
4
+ [networkKey: string]: {
5
+ aliases?: string[];
6
+ };
7
+ };
8
+ export interface ComposeHealthcheck {
9
+ test: string[];
10
+ interval?: string;
11
+ timeout?: string;
12
+ retries?: number;
13
+ }
14
+ export interface ComposeService {
15
+ build?: string;
16
+ image?: string;
17
+ container_name?: string;
18
+ /** Quoted in YAML (`0:0` must not parse as a number). */
19
+ user?: string;
20
+ env_file?: string[];
21
+ environment?: Record<string, string>;
22
+ ports?: string[];
23
+ volumes?: string[];
24
+ command?: string;
25
+ restart?: string;
26
+ depends_on?: string[];
27
+ /** Compose profiles (service only starts when profile is enabled). */
28
+ profiles?: string[];
29
+ /** Attach to compose networks (string name or map with aliases). */
30
+ networks?: ComposeNetworkRef[];
31
+ healthcheck?: ComposeHealthcheck;
32
+ }
33
+ export type ComposeNetwork = {
34
+ /** Fixed Docker network name (shareable across compose projects). */
35
+ name: string;
36
+ external?: boolean;
37
+ };
38
+ /**
39
+ * Live builder for `docker-compose.yml`.
40
+ *
41
+ * Features call `addService` / `addVolume` / `addNetwork` in their scaffold phases.
42
+ */
43
+ export declare class DockerCompose implements KeyedModel {
44
+ readonly key: string;
45
+ private _projectName;
46
+ private readonly _headerComments;
47
+ private readonly _services;
48
+ private readonly _volumes;
49
+ private readonly _networks;
50
+ /** Compose project name (`name:` top-level) — isolates containers/volumes. */
51
+ setProjectName(name: string): this;
52
+ /** File-level `#` comments rendered above `name:` / `services:`. */
53
+ addHeaderComment(...lines: string[]): this;
54
+ addService(name: string, config: ComposeService): this;
55
+ files(): {
56
+ filePath: string;
57
+ content: string;
58
+ }[];
59
+ addVolume(name: string): this;
60
+ addNetwork(key: string, network: ComposeNetwork): this;
61
+ /** Append an env_file path to an existing service. */
62
+ addEnvFile(serviceName: string, filePath: string): this;
63
+ getContent(): string;
64
+ }
@@ -0,0 +1,27 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ /**
3
+ * Builder for a YAML config file (e.g. config/config.yaml or config/config.dev.yaml).
4
+ *
5
+ * Starts with a base section passed to the constructor. Features call
6
+ * `addSection(yaml)` during their scaffold phase to append their own block.
7
+ * `files()` joins all sections with a blank line separator.
8
+ */
9
+ export declare class ConfigYaml implements KeyedModel {
10
+ readonly key: string;
11
+ private readonly filePath;
12
+ private readonly _sections;
13
+ constructor(key: string, filePath: string, baseContent: string);
14
+ addSection(yaml: string): this;
15
+ /** True when a datasource with this `name:` already appears in the file. */
16
+ hasDataSource(name: string): boolean;
17
+ hasDataSources(): boolean;
18
+ /**
19
+ * Insert a `dataSources` list item. Used by `webapi add` so we do not write a
20
+ * second top-level `database:` key (YAML last-key-wins).
21
+ */
22
+ appendDataSource(item: string): this;
23
+ static fromFile(key: string, relativePath: string, absolutePath: string): ConfigYaml;
24
+ files(): SourceFile[];
25
+ }
26
+ /** Insert a YAML list item under `dataSources:`; append a new `database:` block if missing. */
27
+ export declare function injectYamlDataSource(yaml: string, item: string): string;
@@ -0,0 +1,20 @@
1
+ export declare const WELL_KNOWN_FILES: {
2
+ VSCODE_SETTINGS: string;
3
+ LAUNCH_JSON: string;
4
+ DOCKER_COMPOSE: string;
5
+ DEVCONTAINER_JSON: string;
6
+ DOCKERFILE: string;
7
+ PRODUCTION_DOCKERFILE: string;
8
+ GITHUB_CI: string;
9
+ PACKAGE_JSON: string;
10
+ API_PACKAGE_JSON: string;
11
+ TSCONFIG: string;
12
+ VITEST_CONFIG: string;
13
+ MAIN_TS: string;
14
+ CONTROLLER_TS: string;
15
+ CONFIG_YAML: string;
16
+ CONFIG_DEV_YAML: string;
17
+ GITIGNORE: string;
18
+ AUTH_CONFIG: string;
19
+ ENV_FILE: string;
20
+ };
@@ -0,0 +1,37 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ /**
3
+ * Model for `.devcontainer/devcontainer.json`.
4
+ *
5
+ * Features call builder methods (`addExtension`, `forwardPort`, etc.) during
6
+ * their configure phase. `MonoRepoScaffold` calls `files()` at render time.
7
+ */
8
+ export type PortAttributes = {
9
+ label?: string;
10
+ /** When true, host port must match the container port (no random remap). */
11
+ requireLocalPort?: boolean;
12
+ onAutoForward?: "notify" | "openBrowser" | "openPreview" | "silent" | "ignore";
13
+ };
14
+ export declare class DevContainer implements KeyedModel {
15
+ readonly key: string;
16
+ private readonly _extensions;
17
+ private readonly _ports;
18
+ private readonly _portAttributes;
19
+ private readonly _mounts;
20
+ private _postCreateCommand?;
21
+ private _updateContentCommand?;
22
+ private _postStartCommand?;
23
+ private _initializeCommand?;
24
+ private _remoteUser;
25
+ private _useCompose;
26
+ constructor();
27
+ addExtension(...ids: string[]): this;
28
+ forwardPort(...ports: number[]): this;
29
+ setPortAttributes(port: number, attrs: PortAttributes): this;
30
+ setPostCreateCommand(cmd: string): this;
31
+ setUpdateContentCommand(cmd: string): this;
32
+ setPostStartCommand(cmd: string): this;
33
+ setInitializeCommand(cmd: string): this;
34
+ setRemoteUser(user: string): this;
35
+ useCompose(): this;
36
+ files(): SourceFile[];
37
+ }
@@ -0,0 +1,84 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ export type LayerWriter = (dockerfile: DockerfileModel) => void;
3
+ export declare class DockerStep {
4
+ readonly key: string;
5
+ readonly content: string;
6
+ readonly order: number;
7
+ constructor(key: string, content: string, order?: number);
8
+ static run(key: string, command: string, order?: number): DockerStep;
9
+ static raw(key: string, content: string, order?: number): DockerStep;
10
+ static entrypoint(key: string, value: string | readonly string[], order?: number): DockerStep;
11
+ }
12
+ /** Named volume + paths for interactive bash history in app Dev Containers. */
13
+ export declare const commandHistory: {
14
+ readonly volumeName: "bashhistory";
15
+ readonly dir: "/commandhistory";
16
+ readonly fileName: ".bash_history";
17
+ readonly histFile: "/commandhistory/.bash_history";
18
+ };
19
+ export declare function withCommandHistory(options?: {
20
+ historyDir?: string;
21
+ historyFileName?: string;
22
+ username?: string;
23
+ order?: number;
24
+ }): LayerWriter;
25
+ export declare function withNodeUser(options?: {
26
+ username?: string;
27
+ includeUserInstruction?: boolean;
28
+ order?: number;
29
+ }): LayerWriter;
30
+ export declare function withPnpm(options?: {
31
+ version?: string;
32
+ usernameExpr?: string;
33
+ order?: number;
34
+ }): LayerWriter;
35
+ /**
36
+ * Client-only (`psql`, etc.). Escalates to root so this also works when layered on
37
+ * a published base image that already switched to `USER node`.
38
+ */
39
+ export declare function withPostgresqlClient(options?: {
40
+ order?: number;
41
+ username?: string;
42
+ }): LayerWriter;
43
+ /** GitHub CLI — install before USER switches away from root. */
44
+ export declare function withGithubCli(options?: {
45
+ order?: number;
46
+ }): LayerWriter;
47
+ export declare function withWorkspaceNodeModulesOwnership(options?: {
48
+ workspaceDir?: string;
49
+ usernameExpr?: string;
50
+ order?: number;
51
+ }): LayerWriter;
52
+ export declare function withVsCodeJsDebugBootloaderFix(options?: {
53
+ bashrcPath?: string;
54
+ order?: number;
55
+ }): LayerWriter;
56
+ export declare class DockerfileModel implements KeyedModel {
57
+ readonly key: string;
58
+ private readonly _steps;
59
+ private readonly _layerWriters;
60
+ private _fromImage;
61
+ private _layerCounter;
62
+ constructor(baseImage: string);
63
+ from(baseImage: string): this;
64
+ addLayer(layer: LayerWriter | string, order?: 5000): this;
65
+ addStep(step: DockerStep): this;
66
+ removeStep(key: string): this;
67
+ entrypoint(value: string | readonly string[], order?: 10000): this;
68
+ addRunStep(cmd: string): this;
69
+ build(): string;
70
+ protected registerBaseLayers(): void;
71
+ files(): SourceFile[];
72
+ }
73
+ /**
74
+ * Shared layers for the published `ghcr.io/typesmiths/decohere/devcontainer` image.
75
+ * Checked in at `projects/devcontainer/Dockerfile` — keep in sync via the unit test.
76
+ */
77
+ export declare class AppDevContainerBaseImage extends DockerfileModel {
78
+ protected registerBaseLayers(): void;
79
+ }
80
+ /** Generic Dev Container image helpers (history + bootloader) without webapi defaults. */
81
+ export declare class DevContainerImageModel extends DockerfileModel {
82
+ protected registerBaseLayers(): void;
83
+ files(): SourceFile[];
84
+ }
@@ -0,0 +1,16 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ /**
3
+ * Accumulates key=value pairs and renders them as a `.env` file.
4
+ *
5
+ * Register once in the workspace; features call `addEntry` during their
6
+ * scaffold phase to contribute environment variables. The final file is
7
+ * written at render time when `workspace.scaffold()` is called.
8
+ */
9
+ export declare class EnvFile implements KeyedModel {
10
+ readonly key: string;
11
+ private readonly _entries;
12
+ addEntry(key: string, value: string): this;
13
+ hasEntry(key: string): boolean;
14
+ static fromFile(absolutePath: string): EnvFile;
15
+ files(): SourceFile[];
16
+ }
@@ -0,0 +1,7 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ export declare class Gitignore implements KeyedModel {
3
+ readonly key: string;
4
+ private ignoreList;
5
+ add(...patterns: string[]): this;
6
+ files(): SourceFile[];
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ export declare class LaunchJson implements KeyedModel {
3
+ private readonly apiNames;
4
+ readonly key: string;
5
+ constructor(apiNames?: readonly string[]);
6
+ files(): SourceFile[];
7
+ }
@@ -0,0 +1,35 @@
1
+ import type { KeyedModel, SourceFile } from "./source-file.js";
2
+ export type PackageJsonOptions = {
3
+ startEntry?: string;
4
+ /** API slugs in this workspace. Drives `start:<name>` / `dev:<name>`. */
5
+ apiNames?: readonly string[];
6
+ /** Host workspace name used in `@<workspace>/<api>` for flux `--project`. */
7
+ workspaceName?: string;
8
+ };
9
+ /**
10
+ * Builder for the root `package.json`.
11
+ *
12
+ * Starts with the core API dependencies. Features call `addDependency` /
13
+ * `addDevDependency` during their scaffold phase to inject their own deps
14
+ * before `files()` is called at render time.
15
+ */
16
+ export declare class PackageJson implements KeyedModel {
17
+ private readonly name;
18
+ readonly key: string;
19
+ private _dependencies;
20
+ private _devDependencies;
21
+ private _scripts;
22
+ private _version;
23
+ private _type;
24
+ private _rest;
25
+ constructor(name: string, options?: PackageJsonOptions);
26
+ /** Load an existing root package.json so `webapi add` can merge scripts/deps. */
27
+ static fromFile(filePath: string): PackageJson;
28
+ addDependency(name: string, version: string): this;
29
+ addDevDependency(name: string, version: string): this;
30
+ addScript(name: string, command: string): this;
31
+ hasScript(name: string): boolean;
32
+ files(): SourceFile[];
33
+ }
34
+ /** Stable A→Z key order for package.json dependency maps. */
35
+ export declare function sortStringMap(map: Record<string, string>): Record<string, string>;