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

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 (264) hide show
  1. package/package.json +9 -19
  2. package/src/add-api.action.ts +25 -0
  3. package/src/add-api.command.ts +31 -0
  4. package/src/add.command.ts +20 -0
  5. package/src/add.module.ts +11 -0
  6. package/src/cli.ts +4 -0
  7. package/src/create.command.ts +20 -0
  8. package/src/create.module.ts +11 -0
  9. package/src/domain/prompt.ts +50 -0
  10. package/{types/src/index.d.ts → src/index.ts} +0 -4
  11. package/src/models/compose.model.ts +205 -0
  12. package/src/models/config-yaml.model.ts +83 -0
  13. package/src/models/const.ts +20 -0
  14. package/src/models/dev-container.model.ts +136 -0
  15. package/src/models/docker-image.model.ts +343 -0
  16. package/src/models/env-file.model.ts +45 -0
  17. package/src/models/gitignore.model.ts +35 -0
  18. package/src/models/launch-json.model.ts +60 -0
  19. package/src/models/package-json.model.ts +169 -0
  20. package/src/models/project.model.ts +141 -0
  21. package/{types/src/models/source-file.d.ts → src/models/source-file.ts} +6 -4
  22. package/src/models/tsconfig.model.ts +29 -0
  23. package/src/models/vitest-config.model.ts +26 -0
  24. package/src/models/vscode-settings.model.ts +24 -0
  25. package/src/program.ts +63 -0
  26. package/{types/src/resolve-target-dir.d.ts → src/resolve-target-dir.ts} +4 -1
  27. package/src/services/scaffold.service.ts +89 -0
  28. package/src/version.ts +56 -0
  29. package/src/webapi/api-name.ts +73 -0
  30. package/src/webapi/cli-options.ts +56 -0
  31. package/{types/src/webapi/const.d.ts → src/webapi/const.ts} +21 -9
  32. package/src/webapi/create-api.ts +275 -0
  33. package/src/webapi/devcontainer/host-scripts.ts +35 -0
  34. package/src/webapi/features/auth.feature.ts +454 -0
  35. package/src/webapi/features/auth0-cli.ts +421 -0
  36. package/src/webapi/features/biome-format.ts +34 -0
  37. package/src/webapi/features/database.feature.ts +522 -0
  38. package/src/webapi/features/finalize.feature.ts +112 -0
  39. package/src/webapi/features/postman.feature.ts +287 -0
  40. package/src/webapi/models/api-package-json.model.ts +60 -0
  41. package/src/webapi/models/auth-config.model.ts +36 -0
  42. package/src/webapi/models/controller-source-file.model.ts +232 -0
  43. package/{es6/src/webapi/models/github-ci.model.js → src/webapi/models/github-ci.model.ts} +29 -27
  44. package/src/webapi/models/main-source-file.model.ts +208 -0
  45. package/src/webapi/models/production-dockerfile.model.ts +162 -0
  46. package/src/webapi/models/sample-files.model.ts +45 -0
  47. package/src/webapi/models/webapi-image.model.ts +21 -0
  48. package/src/webapi/postman/hello-openapi.ts +92 -0
  49. package/src/webapi/postman/local-view.ts +195 -0
  50. package/src/webapi/postman/openapi-to-postman.ts +208 -0
  51. package/src/webapi/workspace-readme.ts +192 -0
  52. package/src/webapi.action.ts +22 -0
  53. package/src/webapi.command.ts +41 -0
  54. package/tests/auth-postman.wiring.spec.ts +263 -0
  55. package/tests/auth0-cli.spec.ts +232 -0
  56. package/tests/biome-format.spec.ts +49 -0
  57. package/tests/cli.integration.spec.ts +658 -0
  58. package/tests/compose.model.spec.ts +51 -0
  59. package/tests/container-image.model.spec.ts +162 -0
  60. package/tests/dev-container.model.spec.ts +29 -0
  61. package/tests/devcontainer-base-image.spec.ts +32 -0
  62. package/tests/hello-di-inject.scaffold.spec.ts +18 -0
  63. package/tests/hello-route.contract.spec.ts +94 -0
  64. package/tests/package-json.order.spec.ts +59 -0
  65. package/tests/postman-from-openapi.spec.ts +197 -0
  66. package/tests/seed-devcontainer-templates.ts +40 -0
  67. package/tests/webapi/devcontainer/codebase-rag-mcp.spec.ts +96 -0
  68. package/LICENSE +0 -15
  69. package/commonjs/src/add-api.action.js +0 -37
  70. package/commonjs/src/add-api.command.js +0 -39
  71. package/commonjs/src/add.command.js +0 -22
  72. package/commonjs/src/add.module.js +0 -24
  73. package/commonjs/src/auth0-configure.action.js +0 -28
  74. package/commonjs/src/auth0-configure.command.js +0 -24
  75. package/commonjs/src/auth0-login.action.js +0 -28
  76. package/commonjs/src/auth0-login.command.js +0 -23
  77. package/commonjs/src/auth0.command.js +0 -22
  78. package/commonjs/src/auth0.module.js +0 -28
  79. package/commonjs/src/cli.js +0 -8
  80. package/commonjs/src/create.command.js +0 -22
  81. package/commonjs/src/create.module.js +0 -24
  82. package/commonjs/src/domain/prompt.js +0 -62
  83. package/commonjs/src/index.js +0 -48
  84. package/commonjs/src/models/compose.model.js +0 -258
  85. package/commonjs/src/models/config-yaml.model.js +0 -86
  86. package/commonjs/src/models/const.js +0 -30
  87. package/commonjs/src/models/dev-container.model.js +0 -172
  88. package/commonjs/src/models/docker-image.model.js +0 -277
  89. package/commonjs/src/models/env-file.model.js +0 -48
  90. package/commonjs/src/models/gitignore.model.js +0 -48
  91. package/commonjs/src/models/launch-json.model.js +0 -70
  92. package/commonjs/src/models/package-json.model.js +0 -156
  93. package/commonjs/src/models/project.model.js +0 -132
  94. package/commonjs/src/models/source-file.js +0 -4
  95. package/commonjs/src/models/tsconfig.model.js +0 -32
  96. package/commonjs/src/models/vitest-config.model.js +0 -33
  97. package/commonjs/src/models/vscode-settings.model.js +0 -29
  98. package/commonjs/src/program.js +0 -64
  99. package/commonjs/src/resolve-target-dir.js +0 -17
  100. package/commonjs/src/services/scaffold.service.js +0 -60
  101. package/commonjs/src/version.js +0 -55
  102. package/commonjs/src/webapi/api-name.js +0 -93
  103. package/commonjs/src/webapi/auth0-commands.js +0 -250
  104. package/commonjs/src/webapi/authorize-scopes.js +0 -79
  105. package/commonjs/src/webapi/cli-options.js +0 -99
  106. package/commonjs/src/webapi/const.js +0 -54
  107. package/commonjs/src/webapi/create-api.js +0 -265
  108. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.js +0 -164
  109. package/commonjs/src/webapi/devcontainer/codebase-rag-mcp.ts +0 -182
  110. package/commonjs/src/webapi/devcontainer/host-scripts.js +0 -50
  111. package/commonjs/src/webapi/devcontainer/templates/codebase-rag.env.example +0 -3
  112. package/commonjs/src/webapi/devcontainer/templates/initialize.sh +0 -169
  113. package/commonjs/src/webapi/devcontainer/templates/post-create.sh +0 -35
  114. package/commonjs/src/webapi/devcontainer/templates/post-start.sh +0 -65
  115. package/commonjs/src/webapi/devcontainer/templates/tty-prompt.sh +0 -38
  116. package/commonjs/src/webapi/features/auth.feature.js +0 -408
  117. package/commonjs/src/webapi/features/auth0-cli.js +0 -472
  118. package/commonjs/src/webapi/features/biome-format.js +0 -47
  119. package/commonjs/src/webapi/features/database.feature.js +0 -433
  120. package/commonjs/src/webapi/features/finalize.feature.js +0 -93
  121. package/commonjs/src/webapi/features/postman.feature.js +0 -322
  122. package/commonjs/src/webapi/models/api-package-json.model.js +0 -58
  123. package/commonjs/src/webapi/models/auth-config.model.js +0 -24
  124. package/commonjs/src/webapi/models/controller-source-file.model.js +0 -190
  125. package/commonjs/src/webapi/models/github-ci.model.js +0 -193
  126. package/commonjs/src/webapi/models/main-source-file.model.js +0 -165
  127. package/commonjs/src/webapi/models/production-dockerfile.model.js +0 -75
  128. package/commonjs/src/webapi/models/sample-files.model.js +0 -58
  129. package/commonjs/src/webapi/models/webapi-image.model.js +0 -25
  130. package/commonjs/src/webapi/postman/hello-openapi.js +0 -173
  131. package/commonjs/src/webapi/postman/local-view.js +0 -182
  132. package/commonjs/src/webapi/postman/openapi-to-postman.js +0 -238
  133. package/commonjs/src/webapi/workspace-readme.js +0 -109
  134. package/commonjs/src/webapi.action.js +0 -28
  135. package/commonjs/src/webapi.command.js +0 -43
  136. package/es6/src/add-api.action.js +0 -27
  137. package/es6/src/add-api.command.js +0 -29
  138. package/es6/src/add.command.js +0 -12
  139. package/es6/src/add.module.js +0 -14
  140. package/es6/src/auth0-configure.action.js +0 -18
  141. package/es6/src/auth0-configure.command.js +0 -14
  142. package/es6/src/auth0-login.action.js +0 -18
  143. package/es6/src/auth0-login.command.js +0 -13
  144. package/es6/src/auth0.command.js +0 -12
  145. package/es6/src/auth0.module.js +0 -18
  146. package/es6/src/cli.js +0 -4
  147. package/es6/src/create.command.js +0 -12
  148. package/es6/src/create.module.js +0 -14
  149. package/es6/src/domain/prompt.js +0 -41
  150. package/es6/src/index.js +0 -9
  151. package/es6/src/models/compose.model.js +0 -254
  152. package/es6/src/models/config-yaml.model.js +0 -74
  153. package/es6/src/models/const.js +0 -20
  154. package/es6/src/models/dev-container.model.js +0 -162
  155. package/es6/src/models/docker-image.model.js +0 -235
  156. package/es6/src/models/env-file.model.js +0 -44
  157. package/es6/src/models/gitignore.model.js +0 -38
  158. package/es6/src/models/launch-json.model.js +0 -60
  159. package/es6/src/models/package-json.model.js +0 -141
  160. package/es6/src/models/project.model.js +0 -117
  161. package/es6/src/models/source-file.js +0 -1
  162. package/es6/src/models/tsconfig.model.js +0 -22
  163. package/es6/src/models/vitest-config.model.js +0 -23
  164. package/es6/src/models/vscode-settings.model.js +0 -19
  165. package/es6/src/program.js +0 -50
  166. package/es6/src/resolve-target-dir.js +0 -7
  167. package/es6/src/services/scaffold.service.js +0 -50
  168. package/es6/src/version.js +0 -34
  169. package/es6/src/webapi/api-name.js +0 -57
  170. package/es6/src/webapi/auth0-commands.js +0 -185
  171. package/es6/src/webapi/authorize-scopes.js +0 -55
  172. package/es6/src/webapi/cli-options.js +0 -34
  173. package/es6/src/webapi/const.js +0 -21
  174. package/es6/src/webapi/create-api.js +0 -245
  175. package/es6/src/webapi/devcontainer/codebase-rag-mcp.js +0 -154
  176. package/es6/src/webapi/devcontainer/codebase-rag-mcp.ts +0 -182
  177. package/es6/src/webapi/devcontainer/host-scripts.js +0 -29
  178. package/es6/src/webapi/devcontainer/templates/codebase-rag.env.example +0 -3
  179. package/es6/src/webapi/devcontainer/templates/initialize.sh +0 -169
  180. package/es6/src/webapi/devcontainer/templates/post-create.sh +0 -35
  181. package/es6/src/webapi/devcontainer/templates/post-start.sh +0 -65
  182. package/es6/src/webapi/devcontainer/templates/tty-prompt.sh +0 -38
  183. package/es6/src/webapi/features/auth.feature.js +0 -357
  184. package/es6/src/webapi/features/auth0-cli.js +0 -406
  185. package/es6/src/webapi/features/biome-format.js +0 -40
  186. package/es6/src/webapi/features/database.feature.js +0 -423
  187. package/es6/src/webapi/features/finalize.feature.js +0 -83
  188. package/es6/src/webapi/features/postman.feature.js +0 -256
  189. package/es6/src/webapi/models/api-package-json.model.js +0 -53
  190. package/es6/src/webapi/models/auth-config.model.js +0 -20
  191. package/es6/src/webapi/models/controller-source-file.model.js +0 -181
  192. package/es6/src/webapi/models/main-source-file.model.js +0 -161
  193. package/es6/src/webapi/models/production-dockerfile.model.js +0 -66
  194. package/es6/src/webapi/models/sample-files.model.js +0 -40
  195. package/es6/src/webapi/models/webapi-image.model.js +0 -18
  196. package/es6/src/webapi/postman/hello-openapi.js +0 -166
  197. package/es6/src/webapi/postman/local-view.js +0 -167
  198. package/es6/src/webapi/postman/openapi-to-postman.js +0 -179
  199. package/es6/src/webapi/workspace-readme.js +0 -88
  200. package/es6/src/webapi.action.js +0 -18
  201. package/es6/src/webapi.command.js +0 -33
  202. package/types/src/add-api.action.d.ts +0 -13
  203. package/types/src/add-api.command.d.ts +0 -7
  204. package/types/src/add.command.d.ts +0 -6
  205. package/types/src/add.module.d.ts +0 -14
  206. package/types/src/auth0-configure.action.d.ts +0 -7
  207. package/types/src/auth0-configure.command.d.ts +0 -6
  208. package/types/src/auth0-login.action.d.ts +0 -4
  209. package/types/src/auth0-login.command.d.ts +0 -6
  210. package/types/src/auth0.command.d.ts +0 -6
  211. package/types/src/auth0.module.d.ts +0 -18
  212. package/types/src/cli.d.ts +0 -2
  213. package/types/src/create.command.d.ts +0 -6
  214. package/types/src/create.module.d.ts +0 -14
  215. package/types/src/domain/prompt.d.ts +0 -4
  216. package/types/src/models/compose.model.d.ts +0 -73
  217. package/types/src/models/config-yaml.model.d.ts +0 -27
  218. package/types/src/models/const.d.ts +0 -20
  219. package/types/src/models/dev-container.model.d.ts +0 -49
  220. package/types/src/models/docker-image.model.d.ts +0 -90
  221. package/types/src/models/env-file.model.d.ts +0 -16
  222. package/types/src/models/gitignore.model.d.ts +0 -9
  223. package/types/src/models/launch-json.model.d.ts +0 -7
  224. package/types/src/models/package-json.model.d.ts +0 -36
  225. package/types/src/models/project.model.d.ts +0 -60
  226. package/types/src/models/tsconfig.model.d.ts +0 -5
  227. package/types/src/models/vitest-config.model.d.ts +0 -5
  228. package/types/src/models/vscode-settings.model.d.ts +0 -7
  229. package/types/src/program.d.ts +0 -8
  230. package/types/src/services/scaffold.service.d.ts +0 -22
  231. package/types/src/version.d.ts +0 -6
  232. package/types/src/webapi/api-name.d.ts +0 -14
  233. package/types/src/webapi/auth0-commands.d.ts +0 -11
  234. package/types/src/webapi/authorize-scopes.d.ts +0 -7
  235. package/types/src/webapi/cli-options.d.ts +0 -6
  236. package/types/src/webapi/create-api.d.ts +0 -15
  237. package/types/src/webapi/devcontainer/codebase-rag-mcp.d.ts +0 -32
  238. package/types/src/webapi/devcontainer/codebase-rag-mcp.ts +0 -182
  239. package/types/src/webapi/devcontainer/host-scripts.d.ts +0 -7
  240. package/types/src/webapi/devcontainer/templates/codebase-rag.env.example +0 -3
  241. package/types/src/webapi/devcontainer/templates/initialize.sh +0 -169
  242. package/types/src/webapi/devcontainer/templates/post-create.sh +0 -35
  243. package/types/src/webapi/devcontainer/templates/post-start.sh +0 -65
  244. package/types/src/webapi/devcontainer/templates/tty-prompt.sh +0 -38
  245. package/types/src/webapi/features/auth.feature.d.ts +0 -10
  246. package/types/src/webapi/features/auth0-cli.d.ts +0 -84
  247. package/types/src/webapi/features/biome-format.d.ts +0 -5
  248. package/types/src/webapi/features/database.feature.d.ts +0 -7
  249. package/types/src/webapi/features/finalize.feature.d.ts +0 -2
  250. package/types/src/webapi/features/postman.feature.d.ts +0 -16
  251. package/types/src/webapi/models/api-package-json.model.d.ts +0 -18
  252. package/types/src/webapi/models/auth-config.model.d.ts +0 -26
  253. package/types/src/webapi/models/controller-source-file.model.d.ts +0 -46
  254. package/types/src/webapi/models/github-ci.model.d.ts +0 -9
  255. package/types/src/webapi/models/main-source-file.model.d.ts +0 -54
  256. package/types/src/webapi/models/production-dockerfile.model.d.ts +0 -18
  257. package/types/src/webapi/models/sample-files.model.d.ts +0 -7
  258. package/types/src/webapi/models/webapi-image.model.d.ts +0 -12
  259. package/types/src/webapi/postman/hello-openapi.d.ts +0 -19
  260. package/types/src/webapi/postman/local-view.d.ts +0 -17
  261. package/types/src/webapi/postman/openapi-to-postman.d.ts +0 -62
  262. package/types/src/webapi/workspace-readme.d.ts +0 -18
  263. package/types/src/webapi.action.d.ts +0 -14
  264. package/types/src/webapi.command.d.ts +0 -11
@@ -1,66 +0,0 @@
1
- import { WELL_KNOWN_FILES } from "../../models/const.js";
2
- import { DEFAULT_WEBAPI_NAME, webapiPackagedEntry, webapiProjectDir } from "../const.js";
3
- /**
4
- * Production Dockerfile for each API, in the API's own folder: `projects/<name>/Dockerfile`.
5
- * That is where `forge docker` and `forge package` look for a deployable, and the folder is
6
- * the Docker build context.
7
- *
8
- * The image copies `.package/`, which `forge package` writes before Docker runs: the API's
9
- * compiled code, the workspace libraries it imports, and a real (symlink-free) `node_modules`
10
- * of the third-party packages it reaches. So the image build installs nothing, runs no
11
- * workspace tooling, and needs no npm token.
12
- */ export class WebapiProductionDockerfile {
13
- apiNames;
14
- key = WELL_KNOWN_FILES.PRODUCTION_DOCKERFILE;
15
- constructor(apiNames = [
16
- DEFAULT_WEBAPI_NAME
17
- ]){
18
- this.apiNames = apiNames;
19
- }
20
- files() {
21
- const names = this.apiNames.length > 0 ? this.apiNames : [
22
- DEFAULT_WEBAPI_NAME
23
- ];
24
- return names.flatMap((name)=>[
25
- {
26
- filePath: `${webapiProjectDir(name)}/Dockerfile`,
27
- content: renderProductionDockerfile(name)
28
- },
29
- {
30
- filePath: `${webapiProjectDir(name)}/.dockerignore`,
31
- content: dockerignoreContent()
32
- }
33
- ]);
34
- }
35
- }
36
- export function renderProductionDockerfile(apiName) {
37
- const projectDir = webapiProjectDir(apiName);
38
- const entry = webapiPackagedEntry();
39
- return `# syntax=docker/dockerfile:1
40
- # Production image for ${apiName}. Docker only copies the packaged app; it installs nothing.
41
- #
42
- # Build the package first (release build, then .package/ in each API), then the image:
43
- # pnpm run package:${apiName}
44
- # docker build -t ${apiName} ${projectDir}
45
- # or, with the image name and tags from the workspace:
46
- # pnpm run package:${apiName} && pnpm exec forge docker --configuration release
47
- #
48
- # Hosts that build from a git clone (Railway, Fly) do not have .package/. Build and push the
49
- # image from CI instead, or run the package step before \`docker build\`.
50
- FROM node:24-bookworm-slim
51
- WORKDIR /app
52
- ENV NODE_ENV=production
53
-
54
- COPY .package/ ./
55
-
56
- EXPOSE 3000
57
- CMD ["node", "${entry}"]
58
- `;
59
- }
60
- /** The build context is the project folder; only the package belongs in the image. */ function dockerignoreContent() {
61
- return [
62
- "*",
63
- "!.package",
64
- ""
65
- ].join("\n");
66
- }
@@ -1,40 +0,0 @@
1
- const SAMPLE_CONFIG_CONTENT = `export class SampleConfig {\n\tpublic greeting: string = "";\n}\n`;
2
- const SAMPLE_SERVICE_CONTENT = [
3
- `import { inject, injectable } from "@decohere/crucible/decorators";`,
4
- `import { ConfigurationServiceToken } from "@decohere/core/configuration";`,
5
- `import type { IConfigurationService } from "@decohere/core/configuration";`,
6
- `import { SampleConfig } from "../sample.config.js";`,
7
- ``,
8
- `@injectable()`,
9
- `export class SampleService {`,
10
- `\tpublic constructor(`,
11
- `\t\t@inject(ConfigurationServiceToken) private readonly config: IConfigurationService,`,
12
- `\t) {}`,
13
- ``,
14
- `\tpublic async getGreeting(): Promise<string> {`,
15
- `\t\tconst config = await this.config.get(SampleConfig);`,
16
- `\t\treturn config.greeting;`,
17
- `\t}`,
18
- `}`,
19
- ``
20
- ].join("\n");
21
- export class SampleConfigModel {
22
- files() {
23
- return [
24
- {
25
- filePath: "src/sample.config.ts",
26
- content: SAMPLE_CONFIG_CONTENT
27
- }
28
- ];
29
- }
30
- }
31
- export class SampleServiceModel {
32
- files() {
33
- return [
34
- {
35
- filePath: "src/services/sample.service.ts",
36
- content: SAMPLE_SERVICE_CONTENT
37
- }
38
- ];
39
- }
40
- }
@@ -1,18 +0,0 @@
1
- import { DockerfileModel } from "../../models/docker-image.model.js";
2
- import { CREATE_VERSION, DEVCONTAINER_IMAGE_REPOSITORY } from "../../version.js";
3
- /**
4
- * Scaffolded app `.devcontainer/Dockerfile` — thin `FROM` the published base image.
5
- * Optional feature layers (e.g. postgresql-client) append via `addLayer`.
6
- */ export class WebapiDevContainer extends DockerfileModel {
7
- constructor(baseImage = `${DEVCONTAINER_IMAGE_REPOSITORY}:${CREATE_VERSION}`){
8
- super(baseImage);
9
- }
10
- files() {
11
- return [
12
- {
13
- filePath: ".devcontainer/Dockerfile",
14
- content: this.build()
15
- }
16
- ];
17
- }
18
- }
@@ -1,166 +0,0 @@
1
- /** Minimal OpenAPI 3 document shape used for Postman conversion. */ /**
2
- * Canonical Hello WebAPI OpenAPI document used to generate Postman requests.
3
- * Keep paths aligned with scaffolded HelloController (`/hello`, `/hello/{id}`).
4
- */ export function buildHelloOpenApiDocument(projectName) {
5
- return {
6
- openapi: "3.0.3",
7
- info: {
8
- title: `${projectName} WebAPI`,
9
- version: "1.0.0",
10
- description: "Generated from OpenAPI for Postman. Auth/env overlays are applied separately."
11
- },
12
- servers: [
13
- {
14
- url: "{{baseUrl}}"
15
- }
16
- ],
17
- paths: {
18
- "/hello": {
19
- get: {
20
- operationId: "HelloController.getAll",
21
- summary: "List (anonymous)",
22
- tags: [
23
- "Hello"
24
- ],
25
- parameters: [
26
- {
27
- name: "filter",
28
- in: "query",
29
- required: false,
30
- schema: {
31
- type: "string"
32
- }
33
- }
34
- ],
35
- responses: {
36
- "200": {
37
- description: "Successful response"
38
- }
39
- }
40
- },
41
- post: {
42
- operationId: "HelloController.create",
43
- summary: "Create",
44
- tags: [
45
- "Hello"
46
- ],
47
- requestBody: {
48
- required: true,
49
- content: {
50
- "application/json": {
51
- schema: {
52
- type: "object",
53
- properties: {
54
- message: {
55
- type: "string"
56
- }
57
- },
58
- required: [
59
- "message"
60
- ],
61
- example: {
62
- message: "hello"
63
- }
64
- }
65
- }
66
- }
67
- },
68
- responses: {
69
- "200": {
70
- description: "Successful response"
71
- }
72
- }
73
- }
74
- },
75
- "/hello/{id}": {
76
- get: {
77
- operationId: "HelloController.getOne",
78
- summary: "Get by id",
79
- tags: [
80
- "Hello"
81
- ],
82
- parameters: [
83
- {
84
- name: "id",
85
- in: "path",
86
- required: true,
87
- schema: {
88
- type: "string"
89
- }
90
- }
91
- ],
92
- responses: {
93
- "200": {
94
- description: "Successful response"
95
- }
96
- }
97
- },
98
- put: {
99
- operationId: "HelloController.update",
100
- summary: "Update",
101
- tags: [
102
- "Hello"
103
- ],
104
- parameters: [
105
- {
106
- name: "id",
107
- in: "path",
108
- required: true,
109
- schema: {
110
- type: "string"
111
- }
112
- }
113
- ],
114
- requestBody: {
115
- required: true,
116
- content: {
117
- "application/json": {
118
- schema: {
119
- type: "object",
120
- properties: {
121
- message: {
122
- type: "string"
123
- }
124
- },
125
- required: [
126
- "message"
127
- ],
128
- example: {
129
- message: "updated"
130
- }
131
- }
132
- }
133
- }
134
- },
135
- responses: {
136
- "200": {
137
- description: "Successful response"
138
- }
139
- }
140
- },
141
- delete: {
142
- operationId: "HelloController.remove",
143
- summary: "Delete",
144
- tags: [
145
- "Hello"
146
- ],
147
- parameters: [
148
- {
149
- name: "id",
150
- in: "path",
151
- required: true,
152
- schema: {
153
- type: "string"
154
- }
155
- }
156
- ],
157
- responses: {
158
- "200": {
159
- description: "Successful response"
160
- }
161
- }
162
- }
163
- }
164
- }
165
- };
166
- }
@@ -1,167 +0,0 @@
1
- import { randomUUID } from "node:crypto";
2
- import { openApiPathParamsToColon } from "./openapi-to-postman.js";
3
- function yamlQuote(value) {
4
- if (/[:#{}[\],&*?|<>=!%@`]/.test(value) || value.includes("\n") || value === "") {
5
- return JSON.stringify(value);
6
- }
7
- return value;
8
- }
9
- /** Local View / Native Git environment (YAML). */ export function buildEnvironmentYaml(name, auth, options) {
10
- const values = [
11
- {
12
- key: "baseUrl",
13
- value: "http://localhost:3000"
14
- }
15
- ];
16
- if (auth?.auth0Domain) {
17
- values.push({
18
- key: "auth0Domain",
19
- value: auth.auth0Domain
20
- }, {
21
- key: "auth0Audience",
22
- value: auth.auth0Audience ?? ""
23
- }, {
24
- key: "auth0ClientId",
25
- value: auth.auth0ClientId ?? ""
26
- }, {
27
- key: "authUrl",
28
- value: `https://${auth.auth0Domain}/authorize?audience=${auth.auth0Audience ?? ""}`
29
- }, {
30
- key: "accessTokenUrl",
31
- value: `https://${auth.auth0Domain}/oauth/token`
32
- }, {
33
- key: "callbackUrl",
34
- value: options.callbacks[0]
35
- }, {
36
- key: "scope",
37
- value: options.scopes
38
- });
39
- }
40
- const lines = [
41
- `name: ${yamlQuote(name)}`,
42
- "values:"
43
- ];
44
- for (const v of values){
45
- lines.push(` - key: ${v.key}`);
46
- lines.push(` value: ${yamlQuote(v.value)}`);
47
- lines.push(" enabled: true");
48
- }
49
- return `${lines.join("\n")}\n`;
50
- }
51
- /**
52
- * Build Postman Local View multi-file YAML from a v2.1 collection (routes)
53
- * plus hand-authored Auth0 overlay.
54
- */ export function buildLocalViewFilesFromCollection(collection, projectName, auth, options) {
55
- const collectionDir = `postman/collections/${projectName} WebAPI`;
56
- const files = [];
57
- const authBlock = auth?.auth0Domain ? [
58
- "auth:",
59
- ` - id: ${randomUUID()}`,
60
- " type: oauth2",
61
- " name: OAuth 2.0",
62
- " credentials:",
63
- " addTokenTo: header",
64
- " grant_type: authorization_code_with_pkce",
65
- ` authUrl: https://${auth.auth0Domain}/authorize?audience=${auth.auth0Audience ?? ""}`,
66
- ` accessTokenUrl: https://${auth.auth0Domain}/oauth/token`,
67
- ` clientId: ${yamlQuote(auth.auth0ClientId ?? "")}`,
68
- ` scope: ${yamlQuote(options.scopes)}`,
69
- ` redirect_uri: ${options.callbacks[0]}`,
70
- " useBrowser: true",
71
- " challengeAlgorithm: S256",
72
- " client_authentication: body",
73
- ' clientSecret: ""',
74
- ` tokenName: ${yamlQuote(`${projectName} Access Token`)}`,
75
- ""
76
- ].join("\n") : "";
77
- files.push({
78
- filePath: `${collectionDir}/.resources/definition.yaml`,
79
- content: [
80
- "$kind: collection",
81
- `name: ${yamlQuote(`${projectName} WebAPI`)}`,
82
- "schemaVersion: '3.0'",
83
- "description: >-",
84
- " Open this project root in Postman Local View (Files → Open folder).",
85
- " Select the Local environment, then Authorization → Get New Access Token (PKCE).",
86
- " Route requests are generated from OpenAPI; Auth0 overlay is hand-authored.",
87
- authBlock
88
- ].filter((l)=>l !== undefined).join("\n").replace(/\n+$/, "\n")
89
- });
90
- let folderOrder = 1000;
91
- for (const folder of collection.item ?? []){
92
- if (folder.item == null) {
93
- continue;
94
- }
95
- const folderName = folder.name ?? "Requests";
96
- files.push({
97
- filePath: `${collectionDir}/${folderName}/.resources/definition.yaml`,
98
- content: [
99
- "$kind: folder",
100
- `name: ${yamlQuote(folderName)}`,
101
- `order: ${folderOrder}`,
102
- ""
103
- ].join("\n")
104
- });
105
- folderOrder += 1000;
106
- let requestOrder = 1000;
107
- for (const child of folder.item){
108
- const yaml = requestToLocalViewYaml(child, requestOrder);
109
- if (yaml == null) {
110
- continue;
111
- }
112
- const fileName = `${sanitizeFileName(child.name ?? "Request")}.request.yaml`;
113
- files.push({
114
- filePath: `${collectionDir}/${folderName}/${fileName}`,
115
- content: yaml
116
- });
117
- requestOrder += 1000;
118
- }
119
- }
120
- return files;
121
- }
122
- function requestToLocalViewYaml(item, order) {
123
- const request = item.request;
124
- if (request == null) {
125
- return null;
126
- }
127
- const method = (request.method ?? "GET").toUpperCase();
128
- const url = requestUrlForLocalView(request);
129
- const lines = [
130
- "$kind: http-request",
131
- `name: ${yamlQuote(item.name ?? method)}`,
132
- `method: ${method}`,
133
- `url: ${yamlQuote(url)}`
134
- ];
135
- if (request.auth?.type === "noauth") {
136
- lines.push("auth:", " type: noauth");
137
- }
138
- const contentType = request.header?.find((h)=>h.key.toLowerCase() === "content-type")?.value;
139
- const rawBody = request.body?.raw?.trim();
140
- if (rawBody) {
141
- lines.push("headers:");
142
- lines.push(` Content-Type: ${contentType ?? "application/json"}`);
143
- lines.push("body:");
144
- lines.push(" type: json");
145
- lines.push(" content: |-");
146
- for (const bodyLine of rawBody.split("\n")){
147
- lines.push(` ${bodyLine}`);
148
- }
149
- }
150
- lines.push(`order: ${order}`, "");
151
- return lines.join("\n");
152
- }
153
- function requestUrlForLocalView(request) {
154
- const url = request.url;
155
- if (typeof url === "string") {
156
- return openApiPathParamsToColon(url);
157
- }
158
- if (url?.raw) {
159
- return openApiPathParamsToColon(url.raw);
160
- }
161
- const host = url?.host?.[0] ?? "{{baseUrl}}";
162
- const path = (url?.path ?? []).map((segment)=>openApiPathParamsToColon(String(segment))).join("/");
163
- return path ? `${host}/${path}` : host;
164
- }
165
- function sanitizeFileName(name) {
166
- return name.replace(/[^\w\s()-]+/g, "").trim() || "Request";
167
- }
@@ -1,179 +0,0 @@
1
- async function convertAsync(data, options) {
2
- // Loaded here, not at the top: the converter pulls in about 700 modules (lodash, faker, ajv,
3
- // …), which every scaffolder run paid for even with `--postman none`.
4
- const { default: converter } = await import("openapi-to-postmanv2");
5
- return new Promise((resolve, reject)=>{
6
- converter.convert({
7
- type: "json",
8
- data
9
- }, options, (err, result)=>{
10
- if (err) {
11
- reject(err);
12
- return;
13
- }
14
- resolve(result);
15
- });
16
- });
17
- }
18
- /** Convert an OpenAPI document to a Postman Collection v2.1 via openapi-to-postmanv2. */ export async function openApiToPostmanCollection(document) {
19
- const result = await convertAsync(document, {
20
- folderStrategy: "Tags",
21
- requestNameSource: "Fallback",
22
- includeAuthInfoInExample: false
23
- });
24
- if (!result.result || result.output?.[0]?.data == null) {
25
- throw new Error(result.reason ?? "openapi-to-postmanv2 conversion failed");
26
- }
27
- return result.output[0].data;
28
- }
29
- /**
30
- * Overlay Auth0 OAuth2 (PKCE) collection auth and fix Local View-friendly URLs.
31
- * Route items come from OpenAPI; auth/env remain hand-authored.
32
- */ export function applyPostmanAuthOverlay(collection, projectName, auth, options) {
33
- const next = {
34
- ...collection,
35
- info: {
36
- ...collection.info,
37
- name: `${projectName} WebAPI`,
38
- description: options.description,
39
- schema: collection.info.schema ?? "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
40
- }
41
- };
42
- if (auth?.auth0Domain) {
43
- next.auth = {
44
- type: "oauth2",
45
- oauth2: [
46
- {
47
- key: "grant_type",
48
- value: "authorization_code_with_pkce",
49
- type: "string"
50
- },
51
- {
52
- key: "authUrl",
53
- value: "https://{{auth0Domain}}/authorize?audience={{auth0Audience}}",
54
- type: "string"
55
- },
56
- {
57
- key: "accessTokenUrl",
58
- value: "https://{{auth0Domain}}/oauth/token",
59
- type: "string"
60
- },
61
- {
62
- key: "clientId",
63
- value: "{{auth0ClientId}}",
64
- type: "string"
65
- },
66
- {
67
- key: "scope",
68
- value: options.scopes,
69
- type: "string"
70
- },
71
- {
72
- key: "redirect_uri",
73
- value: options.callbacks[0],
74
- type: "string"
75
- },
76
- {
77
- key: "useBrowser",
78
- value: "true",
79
- type: "boolean"
80
- },
81
- {
82
- key: "addTokenTo",
83
- value: "header",
84
- type: "string"
85
- },
86
- {
87
- key: "challengeAlgorithm",
88
- value: "S256",
89
- type: "string"
90
- },
91
- {
92
- key: "client_authentication",
93
- value: "body",
94
- type: "string"
95
- },
96
- {
97
- key: "clientSecret",
98
- value: "",
99
- type: "string"
100
- },
101
- {
102
- key: "tokenName",
103
- value: `${projectName} Access Token`,
104
- type: "string"
105
- }
106
- ]
107
- };
108
- }
109
- next.item = rewriteCollectionItems(collection.item ?? [], {
110
- markListAnonymous: true
111
- });
112
- return next;
113
- }
114
- function rewriteCollectionItems(items, opts) {
115
- return items.map((item)=>{
116
- if (item.item != null) {
117
- return {
118
- ...item,
119
- item: rewriteCollectionItems(item.item, opts)
120
- };
121
- }
122
- const request = item.request;
123
- if (request == null) {
124
- return item;
125
- }
126
- const method = (request.method ?? "GET").toUpperCase();
127
- const rawUrl = requestUrlRaw(request);
128
- const nextRequest = {
129
- ...request,
130
- url: toPostmanUrl(rawUrl)
131
- };
132
- // List Hello stays anonymous (matches scaffold AllowAnonymous on GET /hello).
133
- if (opts.markListAnonymous && method === "GET" && normalizePath(rawUrl) === "/hello" && !rawUrl.includes("/:")) {
134
- nextRequest.auth = {
135
- type: "noauth"
136
- };
137
- }
138
- return {
139
- ...item,
140
- request: nextRequest
141
- };
142
- });
143
- }
144
- function requestUrlRaw(request) {
145
- const url = request.url;
146
- if (typeof url === "string") {
147
- return url;
148
- }
149
- if (url?.raw) {
150
- return url.raw;
151
- }
152
- const host = url?.host?.[0] ?? "{{baseUrl}}";
153
- const path = (url?.path ?? []).join("/");
154
- return path ? `${host}/${path}` : host;
155
- }
156
- /** OpenAPI `{id}` → Postman `:id`, without touching `{{variables}}`. */ export function openApiPathParamsToColon(url) {
157
- return url.replace(/(?<!\{)\{([A-Za-z_][\w]*)\}(?!\})/g, ":$1");
158
- }
159
- function normalizePath(rawUrl) {
160
- const withoutBase = rawUrl.replace(/\{\{baseUrl\}\}/g, "").split("?")[0] ?? "";
161
- const withSlash = withoutBase.startsWith("/") ? withoutBase : `/${withoutBase}`;
162
- return openApiPathParamsToColon(withSlash);
163
- }
164
- /** Prefer Postman template URL shape used by existing Local View / API uploads. */ function toPostmanUrl(rawUrl) {
165
- let pathPart = rawUrl.replace(/\{\{baseUrl\}\}/g, "");
166
- if (!pathPart.startsWith("/")) {
167
- pathPart = `/${pathPart}`;
168
- }
169
- // openapi-to-postman uses {id}; Local View / prior collections use :id
170
- pathPart = openApiPathParamsToColon(pathPart);
171
- const segments = pathPart.split("/").filter(Boolean);
172
- return {
173
- raw: `{{baseUrl}}${pathPart}`,
174
- host: [
175
- "{{baseUrl}}"
176
- ],
177
- path: segments
178
- };
179
- }