@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,258 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { pick } from "../../domain/prompt.js";
5
+ import { WELL_KNOWN_FILES } from "../../models/const.js";
6
+ import { buildHelloOpenApiDocument } from "../postman/hello-openapi.js";
7
+ import { buildEnvironmentYaml, buildLocalViewFilesFromCollection } from "../postman/local-view.js";
8
+ import { applyPostmanAuthOverlay, openApiToPostmanCollection } from "../postman/openapi-to-postman.js";
9
+ import * as auth0Cli from "./auth0-cli.js";
10
+ /** Postman OAuth callback URLs (popup + "Authorize using browser"). */ const POSTMAN_CALLBACKS = [
11
+ "https://oauth.pstmn.io/v1/callback",
12
+ "https://oauth.pstmn.io/v1/browser-callback"
13
+ ];
14
+ /** Scopes requested for Auth0 access tokens (OIDC + Hello CASL permissions). */ const POSTMAN_SCOPES = [
15
+ "openid",
16
+ "profile",
17
+ "email",
18
+ "read:Hello",
19
+ "create:Hello",
20
+ "update:Hello",
21
+ "delete:Hello"
22
+ ].join(" ");
23
+ const COLLECTION_DESCRIPTION = "Open the project root in Postman Local View (not the postman/ folder). " + "Select the Local environment, then Authorization → Get New Access Token (PKCE). " + "Routes are generated from OpenAPI; Auth0 overlay is hand-authored.";
24
+ async function getOptions(_workspace, cliOptions) {
25
+ if (cliOptions.postmanProvider != null) return {};
26
+ const choices = [
27
+ {
28
+ label: "none",
29
+ description: "skip"
30
+ },
31
+ {
32
+ label: "local",
33
+ description: "Local View / Native Git files (no API key)"
34
+ },
35
+ {
36
+ label: "api",
37
+ description: "also upload to Postman.com (needs API key)"
38
+ }
39
+ ];
40
+ const selected = await pick("\n Postman: ", choices, (c)=>`${c.label} — ${c.description}`);
41
+ const provider = selected?.label ?? "none";
42
+ if (provider === "none") return {
43
+ postmanProvider: "none"
44
+ };
45
+ if (provider === "local") return {
46
+ postmanProvider: "local"
47
+ };
48
+ const apiKey = process.env.POSTMAN_API_KEY ?? await import("../../domain/prompt.js").then((m)=>m.ask("\n Postman API key (app.getpostman.com/settings/me/api-keys): "));
49
+ const headers = {
50
+ "X-Api-Key": apiKey,
51
+ "Content-Type": "application/json"
52
+ };
53
+ const wsRes = await fetch("https://api.getpostman.com/workspaces", {
54
+ headers
55
+ });
56
+ if (!wsRes.ok) {
57
+ console.error("\n Postman API key invalid — falling back to local files.");
58
+ return {
59
+ postmanProvider: "local"
60
+ };
61
+ }
62
+ const { workspaces } = await wsRes.json();
63
+ const wsChoices = [
64
+ {
65
+ label: "<new workspace>",
66
+ id: null
67
+ },
68
+ ...workspaces.map((w)=>({
69
+ label: `${w.name} (${w.type})`,
70
+ id: w.id
71
+ }))
72
+ ];
73
+ const wsPicked = await pick("\n Postman workspace: ", wsChoices, (c)=>c.label);
74
+ let workspaceId;
75
+ if (!wsPicked || wsPicked.id === null) {
76
+ const { ask } = await import("../../domain/prompt.js");
77
+ const wsName = await ask(` Workspace name: `);
78
+ const createRes = await fetch("https://api.getpostman.com/workspaces", {
79
+ method: "POST",
80
+ headers,
81
+ body: JSON.stringify({
82
+ workspace: {
83
+ name: wsName,
84
+ type: "personal"
85
+ }
86
+ })
87
+ });
88
+ const { workspace: ws } = await createRes.json();
89
+ workspaceId = ws.id;
90
+ console.log(` ✓ Workspace created: ${wsName}`);
91
+ } else {
92
+ workspaceId = wsPicked.id;
93
+ }
94
+ return {
95
+ postmanProvider: "api",
96
+ apiKey,
97
+ workspaceId
98
+ };
99
+ }
100
+ /** Build Postman collection: OpenAPI routes + Auth0 auth overlay. */ export async function buildHybridPostmanCollection(projectName, auth) {
101
+ const openapi = buildHelloOpenApiDocument(projectName);
102
+ const base = await openApiToPostmanCollection(openapi);
103
+ if (base.info._postman_id == null) {
104
+ base.info._postman_id = randomUUID();
105
+ }
106
+ return applyPostmanAuthOverlay(base, projectName, auth, {
107
+ callbacks: POSTMAN_CALLBACKS,
108
+ scopes: POSTMAN_SCOPES,
109
+ description: COLLECTION_DESCRIPTION
110
+ });
111
+ }
112
+ /** Read a previously scaffolded auth0ClientId so re-scaffold never blanks it. */ function readExistingSpaClientId(targetDir, projectName) {
113
+ const envPath = join(targetDir, "postman/environments", `${projectName}-Local.environment.yaml`);
114
+ if (!existsSync(envPath)) return undefined;
115
+ const text = readFileSync(envPath, "utf8");
116
+ const match = text.match(/key:\s*auth0ClientId\s*\n\s*value:\s*["']?([^"'\n]+)/);
117
+ const value = match?.[1]?.trim();
118
+ return value && value.length > 0 ? value : undefined;
119
+ }
120
+ /**
121
+ * Resolve the Postman SPA client id. Never returns empty — preserves an existing
122
+ * env value on Auth0 failure, otherwise throws so we do not write a blank env.
123
+ */ function resolveSpaClientId(workspace) {
124
+ const appName = `${workspace.name} Postman`;
125
+ try {
126
+ const app = auth0Cli.ensureSpaApp(appName, [
127
+ ...POSTMAN_CALLBACKS
128
+ ]);
129
+ console.log(app.reused ? ` ✓ Reusing Auth0 SPA app for Postman PKCE (${app.client_id})` : ` ✓ Auth0 SPA app created for Postman PKCE (${app.client_id})`);
130
+ try {
131
+ auth0Cli.enableConnectionForClient(auth0Cli.DB_CONNECTION_NAME, app.client_id);
132
+ console.log(` ✓ Enabled ${auth0Cli.DB_CONNECTION_NAME} on Postman SPA`);
133
+ } catch (err) {
134
+ console.error(` ✗ Failed to enable DB connection on SPA: ${err instanceof Error ? err.message : err}`);
135
+ }
136
+ return app.client_id;
137
+ } catch (err) {
138
+ const existing = readExistingSpaClientId(workspace.targetDir, workspace.name);
139
+ if (existing) {
140
+ console.error(` ✗ Failed to ensure Auth0 SPA app (${err instanceof Error ? err.message : err})`);
141
+ console.log(` ✓ Keeping existing auth0ClientId from Postman environment (${existing})`);
142
+ return existing;
143
+ }
144
+ const detail = err instanceof Error ? err.message : String(err);
145
+ // Entity-limit messages are already actionable; avoid burying them.
146
+ if (auth0Cli.isAuth0EntityLimitError(err)) {
147
+ throw new Error(detail);
148
+ }
149
+ throw new Error(`Failed to ensure Auth0 SPA app for Postman — auth0ClientId would be empty: ${detail}`);
150
+ }
151
+ }
152
+ async function scaffold(workspace, options) {
153
+ if (options.postmanProvider === "none" || options.postmanProvider == null) return;
154
+ const authConfigModel = workspace.getModel(WELL_KNOWN_FILES.AUTH_CONFIG);
155
+ const authCfg = authConfigModel?.config;
156
+ const spaClientId = authCfg?.issuerBaseUrl ? resolveSpaClientId(workspace) : undefined;
157
+ const auth0Env = authCfg?.issuerBaseUrl ? {
158
+ auth0Domain: authCfg.issuerBaseUrl.replace(/^https?:\/\//, ""),
159
+ auth0Audience: authCfg.audience,
160
+ auth0ClientId: spaClientId
161
+ } : undefined;
162
+ const projectName = workspace.name;
163
+ const envName = `${projectName} Local`;
164
+ const collection = await buildHybridPostmanCollection(projectName, auth0Env);
165
+ const localFiles = buildLocalViewFilesFromCollection(collection, projectName, auth0Env, {
166
+ callbacks: POSTMAN_CALLBACKS,
167
+ scopes: POSTMAN_SCOPES
168
+ });
169
+ const envYaml = buildEnvironmentYaml(envName, auth0Env, {
170
+ callbacks: POSTMAN_CALLBACKS,
171
+ scopes: POSTMAN_SCOPES
172
+ });
173
+ workspace.addFile({
174
+ files: ()=>[
175
+ {
176
+ filePath: ".postman/resources.yaml",
177
+ content: [
178
+ "# Open this project root in Postman (Files → Open folder), not the postman/ subfolder.",
179
+ "# Postman fills workspace.id when you connect Local View.",
180
+ "#",
181
+ "# All resources under postman/ are registered automatically.",
182
+ "# Route requests are generated from OpenAPI; Auth0 overlay is hand-authored.",
183
+ ""
184
+ ].join("\n")
185
+ },
186
+ {
187
+ filePath: `postman/environments/${projectName}-Local.environment.yaml`,
188
+ content: envYaml
189
+ },
190
+ ...localFiles
191
+ ]
192
+ });
193
+ if (options.postmanProvider === "api" && options.apiKey) {
194
+ const headers = {
195
+ "X-Api-Key": options.apiKey,
196
+ "Content-Type": "application/json"
197
+ };
198
+ const colRes = await fetch(`https://api.getpostman.com/collections?workspace=${options.workspaceId}`, {
199
+ method: "POST",
200
+ headers,
201
+ body: JSON.stringify({
202
+ collection
203
+ })
204
+ });
205
+ if (colRes.ok) {
206
+ console.log(" ✓ Postman collection uploaded");
207
+ } else {
208
+ console.error(" ✗ Failed to upload Postman collection");
209
+ }
210
+ const envValues = [
211
+ {
212
+ key: "baseUrl",
213
+ value: "http://localhost:3000",
214
+ enabled: true
215
+ },
216
+ ...auth0Env?.auth0Domain ? [
217
+ {
218
+ key: "auth0Domain",
219
+ value: auth0Env.auth0Domain,
220
+ enabled: true
221
+ },
222
+ {
223
+ key: "auth0Audience",
224
+ value: auth0Env.auth0Audience ?? "",
225
+ enabled: true
226
+ },
227
+ {
228
+ key: "auth0ClientId",
229
+ value: auth0Env.auth0ClientId ?? "",
230
+ enabled: true
231
+ }
232
+ ] : []
233
+ ];
234
+ const envRes = await fetch(`https://api.getpostman.com/environments?workspace=${options.workspaceId}`, {
235
+ method: "POST",
236
+ headers,
237
+ body: JSON.stringify({
238
+ environment: {
239
+ name: envName,
240
+ values: envValues
241
+ }
242
+ })
243
+ });
244
+ if (envRes.ok) {
245
+ console.log(" ✓ Postman environment uploaded");
246
+ } else {
247
+ console.error(" ✗ Failed to upload Postman environment");
248
+ }
249
+ }
250
+ }
251
+ export const PostmanFeature = {
252
+ getOptions,
253
+ scaffold
254
+ };
255
+ export { buildHelloOpenApiDocument } from "../postman/hello-openapi.js";
256
+ export { POSTMAN_CALLBACKS, POSTMAN_SCOPES };
257
+
258
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvZmVhdHVyZXMvcG9zdG1hbi5mZWF0dXJlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgcGljayB9IGZyb20gXCIuLi8uLi9kb21haW4vcHJvbXB0LmpzXCI7XG5pbXBvcnQgeyBXRUxMX0tOT1dOX0ZJTEVTIH0gZnJvbSBcIi4uLy4uL21vZGVscy9jb25zdC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBXb3Jrc3BhY2VTY2FmZm9sZCB9IGZyb20gXCIuLi8uLi9tb2RlbHMvcHJvamVjdC5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBGZWF0dXJlIH0gZnJvbSBcIi4uLy4uL3NlcnZpY2VzL3NjYWZmb2xkLnNlcnZpY2UuanNcIjtcbmltcG9ydCB0eXBlIHsgQXV0aENvbmZpZ01vZGVsIH0gZnJvbSBcIi4uL21vZGVscy9hdXRoLWNvbmZpZy5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgYnVpbGRIZWxsb09wZW5BcGlEb2N1bWVudCB9IGZyb20gXCIuLi9wb3N0bWFuL2hlbGxvLW9wZW5hcGkuanNcIjtcbmltcG9ydCB7XG5cdGJ1aWxkRW52aXJvbm1lbnRZYW1sLFxuXHRidWlsZExvY2FsVmlld0ZpbGVzRnJvbUNvbGxlY3Rpb24sXG59IGZyb20gXCIuLi9wb3N0bWFuL2xvY2FsLXZpZXcuanNcIjtcbmltcG9ydCB7XG5cdHR5cGUgQXV0aDBFbnYsXG5cdGFwcGx5UG9zdG1hbkF1dGhPdmVybGF5LFxuXHRvcGVuQXBpVG9Qb3N0bWFuQ29sbGVjdGlvbixcbn0gZnJvbSBcIi4uL3Bvc3RtYW4vb3BlbmFwaS10by1wb3N0bWFuLmpzXCI7XG5pbXBvcnQgKiBhcyBhdXRoMENsaSBmcm9tIFwiLi9hdXRoMC1jbGkuanNcIjtcblxuLyoqIFBvc3RtYW4gT0F1dGggY2FsbGJhY2sgVVJMcyAocG9wdXAgKyBcIkF1dGhvcml6ZSB1c2luZyBicm93c2VyXCIpLiAqL1xuY29uc3QgUE9TVE1BTl9DQUxMQkFDS1MgPSBbXG5cdFwiaHR0cHM6Ly9vYXV0aC5wc3Rtbi5pby92MS9jYWxsYmFja1wiLFxuXHRcImh0dHBzOi8vb2F1dGgucHN0bW4uaW8vdjEvYnJvd3Nlci1jYWxsYmFja1wiLFxuXSBhcyBjb25zdDtcblxuLyoqIFNjb3BlcyByZXF1ZXN0ZWQgZm9yIEF1dGgwIGFjY2VzcyB0b2tlbnMgKE9JREMgKyBIZWxsbyBDQVNMIHBlcm1pc3Npb25zKS4gKi9cbmNvbnN0IFBPU1RNQU5fU0NPUEVTID0gW1xuXHRcIm9wZW5pZFwiLFxuXHRcInByb2ZpbGVcIixcblx0XCJlbWFpbFwiLFxuXHRcInJlYWQ6SGVsbG9cIixcblx0XCJjcmVhdGU6SGVsbG9cIixcblx0XCJ1cGRhdGU6SGVsbG9cIixcblx0XCJkZWxldGU6SGVsbG9cIixcbl0uam9pbihcIiBcIik7XG5cbmNvbnN0IENPTExFQ1RJT05fREVTQ1JJUFRJT04gPVxuXHRcIk9wZW4gdGhlIHByb2plY3Qgcm9vdCBpbiBQb3N0bWFuIExvY2FsIFZpZXcgKG5vdCB0aGUgcG9zdG1hbi8gZm9sZGVyKS4gXCIgK1xuXHRcIlNlbGVjdCB0aGUgTG9jYWwgZW52aXJvbm1lbnQsIHRoZW4gQXV0aG9yaXphdGlvbiDihpIgR2V0IE5ldyBBY2Nlc3MgVG9rZW4gKFBLQ0UpLiBcIiArXG5cdFwiUm91dGVzIGFyZSBnZW5lcmF0ZWQgZnJvbSBPcGVuQVBJOyBBdXRoMCBvdmVybGF5IGlzIGhhbmQtYXV0aG9yZWQuXCI7XG5cbmV4cG9ydCB0eXBlIFBvc3RtYW5PcHRpb25zID0ge1xuXHRwb3N0bWFuUHJvdmlkZXI/OiBcImFwaVwiIHwgXCJsb2NhbFwiIHwgXCJub25lXCI7XG5cdGFwaUtleT86IHN0cmluZztcblx0d29ya3NwYWNlSWQ/OiBzdHJpbmc7XG59O1xuXG5hc3luYyBmdW5jdGlvbiBnZXRPcHRpb25zKFxuXHRfd29ya3NwYWNlOiBXb3Jrc3BhY2VTY2FmZm9sZCxcblx0Y2xpT3B0aW9uczogUGFydGlhbDxQb3N0bWFuT3B0aW9ucz4sXG4pOiBQcm9taXNlPFBhcnRpYWw8UG9zdG1hbk9wdGlvbnM+PiB7XG5cdGlmIChjbGlPcHRpb25zLnBvc3RtYW5Qcm92aWRlciAhPSBudWxsKSByZXR1cm4ge307XG5cblx0Y29uc3QgY2hvaWNlcyA9IFtcblx0XHR7IGxhYmVsOiBcIm5vbmVcIiBhcyBjb25zdCwgZGVzY3JpcHRpb246IFwic2tpcFwiIH0sXG5cdFx0e1xuXHRcdFx0bGFiZWw6IFwibG9jYWxcIiBhcyBjb25zdCxcblx0XHRcdGRlc2NyaXB0aW9uOiBcIkxvY2FsIFZpZXcgLyBOYXRpdmUgR2l0IGZpbGVzIChubyBBUEkga2V5KVwiLFxuXHRcdH0sXG5cdFx0e1xuXHRcdFx0bGFiZWw6IFwiYXBpXCIgYXMgY29uc3QsXG5cdFx0XHRkZXNjcmlwdGlvbjogXCJhbHNvIHVwbG9hZCB0byBQb3N0bWFuLmNvbSAobmVlZHMgQVBJIGtleSlcIixcblx0XHR9LFxuXHRdO1xuXHRjb25zdCBzZWxlY3RlZCA9IGF3YWl0IHBpY2soXG5cdFx0XCJcXG4gIFBvc3RtYW46IFwiLFxuXHRcdGNob2ljZXMsXG5cdFx0KGMpID0+IGAke2MubGFiZWx9IOKAlCAke2MuZGVzY3JpcHRpb259YCxcblx0KTtcblx0Y29uc3QgcHJvdmlkZXIgPSBzZWxlY3RlZD8ubGFiZWwgPz8gXCJub25lXCI7XG5cblx0aWYgKHByb3ZpZGVyID09PSBcIm5vbmVcIikgcmV0dXJuIHsgcG9zdG1hblByb3ZpZGVyOiBcIm5vbmVcIiB9O1xuXHRpZiAocHJvdmlkZXIgPT09IFwibG9jYWxcIikgcmV0dXJuIHsgcG9zdG1hblByb3ZpZGVyOiBcImxvY2FsXCIgfTtcblxuXHRjb25zdCBhcGlLZXkgPVxuXHRcdHByb2Nlc3MuZW52LlBPU1RNQU5fQVBJX0tFWSA/P1xuXHRcdChhd2FpdCBpbXBvcnQoXCIuLi8uLi9kb21haW4vcHJvbXB0LmpzXCIpLnRoZW4oKG0pID0+XG5cdFx0XHRtLmFzayhcIlxcbiAgUG9zdG1hbiBBUEkga2V5IChhcHAuZ2V0cG9zdG1hbi5jb20vc2V0dGluZ3MvbWUvYXBpLWtleXMpOiBcIiksXG5cdFx0KSk7XG5cblx0Y29uc3QgaGVhZGVycyA9IHsgXCJYLUFwaS1LZXlcIjogYXBpS2V5LCBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIiB9O1xuXHRjb25zdCB3c1JlcyA9IGF3YWl0IGZldGNoKFwiaHR0cHM6Ly9hcGkuZ2V0cG9zdG1hbi5jb20vd29ya3NwYWNlc1wiLCB7IGhlYWRlcnMgfSk7XG5cblx0aWYgKCF3c1Jlcy5vaykge1xuXHRcdGNvbnNvbGUuZXJyb3IoXCJcXG4gIFBvc3RtYW4gQVBJIGtleSBpbnZhbGlkIOKAlCBmYWxsaW5nIGJhY2sgdG8gbG9jYWwgZmlsZXMuXCIpO1xuXHRcdHJldHVybiB7IHBvc3RtYW5Qcm92aWRlcjogXCJsb2NhbFwiIH07XG5cdH1cblxuXHRjb25zdCB7IHdvcmtzcGFjZXMgfSA9IChhd2FpdCB3c1Jlcy5qc29uKCkpIGFzIHtcblx0XHR3b3Jrc3BhY2VzOiBBcnJheTx7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZzsgdHlwZTogc3RyaW5nIH0+O1xuXHR9O1xuXG5cdHR5cGUgV3NDaG9pY2UgPSB7IGxhYmVsOiBzdHJpbmc7IGlkOiBzdHJpbmcgfCBudWxsIH07XG5cdGNvbnN0IHdzQ2hvaWNlczogV3NDaG9pY2VbXSA9IFtcblx0XHR7IGxhYmVsOiBcIjxuZXcgd29ya3NwYWNlPlwiLCBpZDogbnVsbCB9LFxuXHRcdC4uLndvcmtzcGFjZXMubWFwKCh3KSA9PiAoeyBsYWJlbDogYCR7dy5uYW1lfSAoJHt3LnR5cGV9KWAsIGlkOiB3LmlkIH0pKSxcblx0XTtcblxuXHRjb25zdCB3c1BpY2tlZCA9IGF3YWl0IHBpY2soXCJcXG4gIFBvc3RtYW4gd29ya3NwYWNlOiBcIiwgd3NDaG9pY2VzLCAoYykgPT4gYy5sYWJlbCk7XG5cblx0bGV0IHdvcmtzcGFjZUlkOiBzdHJpbmc7XG5cdGlmICghd3NQaWNrZWQgfHwgd3NQaWNrZWQuaWQgPT09IG51bGwpIHtcblx0XHRjb25zdCB7IGFzayB9ID0gYXdhaXQgaW1wb3J0KFwiLi4vLi4vZG9tYWluL3Byb21wdC5qc1wiKTtcblx0XHRjb25zdCB3c05hbWUgPSBhd2FpdCBhc2soYCAgV29ya3NwYWNlIG5hbWU6IGApO1xuXHRcdGNvbnN0IGNyZWF0ZVJlcyA9IGF3YWl0IGZldGNoKFwiaHR0cHM6Ly9hcGkuZ2V0cG9zdG1hbi5jb20vd29ya3NwYWNlc1wiLCB7XG5cdFx0XHRtZXRob2Q6IFwiUE9TVFwiLFxuXHRcdFx0aGVhZGVycyxcblx0XHRcdGJvZHk6IEpTT04uc3RyaW5naWZ5KHsgd29ya3NwYWNlOiB7IG5hbWU6IHdzTmFtZSwgdHlwZTogXCJwZXJzb25hbFwiIH0gfSksXG5cdFx0fSk7XG5cdFx0Y29uc3QgeyB3b3Jrc3BhY2U6IHdzIH0gPSAoYXdhaXQgY3JlYXRlUmVzLmpzb24oKSkgYXMgeyB3b3Jrc3BhY2U6IHsgaWQ6IHN0cmluZyB9IH07XG5cdFx0d29ya3NwYWNlSWQgPSB3cy5pZDtcblx0XHRjb25zb2xlLmxvZyhgICDinJMgV29ya3NwYWNlIGNyZWF0ZWQ6ICR7d3NOYW1lfWApO1xuXHR9IGVsc2Uge1xuXHRcdHdvcmtzcGFjZUlkID0gd3NQaWNrZWQuaWQ7XG5cdH1cblxuXHRyZXR1cm4geyBwb3N0bWFuUHJvdmlkZXI6IFwiYXBpXCIsIGFwaUtleSwgd29ya3NwYWNlSWQgfTtcbn1cblxuLyoqIEJ1aWxkIFBvc3RtYW4gY29sbGVjdGlvbjogT3BlbkFQSSByb3V0ZXMgKyBBdXRoMCBhdXRoIG92ZXJsYXkuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYnVpbGRIeWJyaWRQb3N0bWFuQ29sbGVjdGlvbihwcm9qZWN0TmFtZTogc3RyaW5nLCBhdXRoPzogQXV0aDBFbnYpIHtcblx0Y29uc3Qgb3BlbmFwaSA9IGJ1aWxkSGVsbG9PcGVuQXBpRG9jdW1lbnQocHJvamVjdE5hbWUpO1xuXHRjb25zdCBiYXNlID0gYXdhaXQgb3BlbkFwaVRvUG9zdG1hbkNvbGxlY3Rpb24ob3BlbmFwaSk7XG5cdGlmIChiYXNlLmluZm8uX3Bvc3RtYW5faWQgPT0gbnVsbCkge1xuXHRcdGJhc2UuaW5mby5fcG9zdG1hbl9pZCA9IHJhbmRvbVVVSUQoKTtcblx0fVxuXHRyZXR1cm4gYXBwbHlQb3N0bWFuQXV0aE92ZXJsYXkoYmFzZSwgcHJvamVjdE5hbWUsIGF1dGgsIHtcblx0XHRjYWxsYmFja3M6IFBPU1RNQU5fQ0FMTEJBQ0tTLFxuXHRcdHNjb3BlczogUE9TVE1BTl9TQ09QRVMsXG5cdFx0ZGVzY3JpcHRpb246IENPTExFQ1RJT05fREVTQ1JJUFRJT04sXG5cdH0pO1xufVxuXG4vKiogUmVhZCBhIHByZXZpb3VzbHkgc2NhZmZvbGRlZCBhdXRoMENsaWVudElkIHNvIHJlLXNjYWZmb2xkIG5ldmVyIGJsYW5rcyBpdC4gKi9cbmZ1bmN0aW9uIHJlYWRFeGlzdGluZ1NwYUNsaWVudElkKHRhcmdldERpcjogc3RyaW5nLCBwcm9qZWN0TmFtZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcblx0Y29uc3QgZW52UGF0aCA9IGpvaW4oXG5cdFx0dGFyZ2V0RGlyLFxuXHRcdFwicG9zdG1hbi9lbnZpcm9ubWVudHNcIixcblx0XHRgJHtwcm9qZWN0TmFtZX0tTG9jYWwuZW52aXJvbm1lbnQueWFtbGAsXG5cdCk7XG5cdGlmICghZXhpc3RzU3luYyhlbnZQYXRoKSkgcmV0dXJuIHVuZGVmaW5lZDtcblx0Y29uc3QgdGV4dCA9IHJlYWRGaWxlU3luYyhlbnZQYXRoLCBcInV0ZjhcIik7XG5cdGNvbnN0IG1hdGNoID0gdGV4dC5tYXRjaCgva2V5OlxccyphdXRoMENsaWVudElkXFxzKlxcblxccyp2YWx1ZTpcXHMqW1wiJ10/KFteXCInXFxuXSspLyk7XG5cdGNvbnN0IHZhbHVlID0gbWF0Y2g/LlsxXT8udHJpbSgpO1xuXHRyZXR1cm4gdmFsdWUgJiYgdmFsdWUubGVuZ3RoID4gMCA/IHZhbHVlIDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIFBvc3RtYW4gU1BBIGNsaWVudCBpZC4gTmV2ZXIgcmV0dXJucyBlbXB0eSDigJQgcHJlc2VydmVzIGFuIGV4aXN0aW5nXG4gKiBlbnYgdmFsdWUgb24gQXV0aDAgZmFpbHVyZSwgb3RoZXJ3aXNlIHRocm93cyBzbyB3ZSBkbyBub3Qgd3JpdGUgYSBibGFuayBlbnYuXG4gKi9cbmZ1bmN0aW9uIHJlc29sdmVTcGFDbGllbnRJZCh3b3Jrc3BhY2U6IFdvcmtzcGFjZVNjYWZmb2xkKTogc3RyaW5nIHtcblx0Y29uc3QgYXBwTmFtZSA9IGAke3dvcmtzcGFjZS5uYW1lfSBQb3N0bWFuYDtcblx0dHJ5IHtcblx0XHRjb25zdCBhcHAgPSBhdXRoMENsaS5lbnN1cmVTcGFBcHAoYXBwTmFtZSwgWy4uLlBPU1RNQU5fQ0FMTEJBQ0tTXSk7XG5cdFx0Y29uc29sZS5sb2coXG5cdFx0XHRhcHAucmV1c2VkXG5cdFx0XHRcdD8gYCAg4pyTIFJldXNpbmcgQXV0aDAgU1BBIGFwcCBmb3IgUG9zdG1hbiBQS0NFICgke2FwcC5jbGllbnRfaWR9KWBcblx0XHRcdFx0OiBgICDinJMgQXV0aDAgU1BBIGFwcCBjcmVhdGVkIGZvciBQb3N0bWFuIFBLQ0UgKCR7YXBwLmNsaWVudF9pZH0pYCxcblx0XHQpO1xuXHRcdHRyeSB7XG5cdFx0XHRhdXRoMENsaS5lbmFibGVDb25uZWN0aW9uRm9yQ2xpZW50KGF1dGgwQ2xpLkRCX0NPTk5FQ1RJT05fTkFNRSwgYXBwLmNsaWVudF9pZCk7XG5cdFx0XHRjb25zb2xlLmxvZyhgICDinJMgRW5hYmxlZCAke2F1dGgwQ2xpLkRCX0NPTk5FQ1RJT05fTkFNRX0gb24gUG9zdG1hbiBTUEFgKTtcblx0XHR9IGNhdGNoIChlcnIpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcdGAgIOKclyBGYWlsZWQgdG8gZW5hYmxlIERCIGNvbm5lY3Rpb24gb24gU1BBOiAke2VyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBlcnJ9YCxcblx0XHRcdCk7XG5cdFx0fVxuXHRcdHJldHVybiBhcHAuY2xpZW50X2lkO1xuXHR9IGNhdGNoIChlcnIpIHtcblx0XHRjb25zdCBleGlzdGluZyA9IHJlYWRFeGlzdGluZ1NwYUNsaWVudElkKHdvcmtzcGFjZS50YXJnZXREaXIsIHdvcmtzcGFjZS5uYW1lKTtcblx0XHRpZiAoZXhpc3RpbmcpIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcdGAgIOKclyBGYWlsZWQgdG8gZW5zdXJlIEF1dGgwIFNQQSBhcHAgKCR7ZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IGVycn0pYCxcblx0XHRcdCk7XG5cdFx0XHRjb25zb2xlLmxvZyhgICDinJMgS2VlcGluZyBleGlzdGluZyBhdXRoMENsaWVudElkIGZyb20gUG9zdG1hbiBlbnZpcm9ubWVudCAoJHtleGlzdGluZ30pYCk7XG5cdFx0XHRyZXR1cm4gZXhpc3Rpbmc7XG5cdFx0fVxuXHRcdGNvbnN0IGRldGFpbCA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKTtcblx0XHQvLyBFbnRpdHktbGltaXQgbWVzc2FnZXMgYXJlIGFscmVhZHkgYWN0aW9uYWJsZTsgYXZvaWQgYnVyeWluZyB0aGVtLlxuXHRcdGlmIChhdXRoMENsaS5pc0F1dGgwRW50aXR5TGltaXRFcnJvcihlcnIpKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoZGV0YWlsKTtcblx0XHR9XG5cdFx0dGhyb3cgbmV3IEVycm9yKFxuXHRcdFx0YEZhaWxlZCB0byBlbnN1cmUgQXV0aDAgU1BBIGFwcCBmb3IgUG9zdG1hbiDigJQgYXV0aDBDbGllbnRJZCB3b3VsZCBiZSBlbXB0eTogJHtkZXRhaWx9YCxcblx0XHQpO1xuXHR9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNjYWZmb2xkKHdvcmtzcGFjZTogV29ya3NwYWNlU2NhZmZvbGQsIG9wdGlvbnM6IFBvc3RtYW5PcHRpb25zKTogUHJvbWlzZTx2b2lkPiB7XG5cdGlmIChvcHRpb25zLnBvc3RtYW5Qcm92aWRlciA9PT0gXCJub25lXCIgfHwgb3B0aW9ucy5wb3N0bWFuUHJvdmlkZXIgPT0gbnVsbCkgcmV0dXJuO1xuXG5cdGNvbnN0IGF1dGhDb25maWdNb2RlbCA9IHdvcmtzcGFjZS5nZXRNb2RlbDxBdXRoQ29uZmlnTW9kZWw+KFdFTExfS05PV05fRklMRVMuQVVUSF9DT05GSUcpO1xuXHRjb25zdCBhdXRoQ2ZnID0gYXV0aENvbmZpZ01vZGVsPy5jb25maWc7XG5cblx0Y29uc3Qgc3BhQ2xpZW50SWQgPSBhdXRoQ2ZnPy5pc3N1ZXJCYXNlVXJsID8gcmVzb2x2ZVNwYUNsaWVudElkKHdvcmtzcGFjZSkgOiB1bmRlZmluZWQ7XG5cblx0Y29uc3QgYXV0aDBFbnY6IEF1dGgwRW52IHwgdW5kZWZpbmVkID0gYXV0aENmZz8uaXNzdWVyQmFzZVVybFxuXHRcdD8ge1xuXHRcdFx0XHRhdXRoMERvbWFpbjogYXV0aENmZy5pc3N1ZXJCYXNlVXJsLnJlcGxhY2UoL15odHRwcz86XFwvXFwvLywgXCJcIiksXG5cdFx0XHRcdGF1dGgwQXVkaWVuY2U6IGF1dGhDZmcuYXVkaWVuY2UsXG5cdFx0XHRcdGF1dGgwQ2xpZW50SWQ6IHNwYUNsaWVudElkLFxuXHRcdFx0fVxuXHRcdDogdW5kZWZpbmVkO1xuXG5cdGNvbnN0IHByb2plY3ROYW1lID0gd29ya3NwYWNlLm5hbWU7XG5cdGNvbnN0IGVudk5hbWUgPSBgJHtwcm9qZWN0TmFtZX0gTG9jYWxgO1xuXHRjb25zdCBjb2xsZWN0aW9uID0gYXdhaXQgYnVpbGRIeWJyaWRQb3N0bWFuQ29sbGVjdGlvbihwcm9qZWN0TmFtZSwgYXV0aDBFbnYpO1xuXHRjb25zdCBsb2NhbEZpbGVzID0gYnVpbGRMb2NhbFZpZXdGaWxlc0Zyb21Db2xsZWN0aW9uKGNvbGxlY3Rpb24sIHByb2plY3ROYW1lLCBhdXRoMEVudiwge1xuXHRcdGNhbGxiYWNrczogUE9TVE1BTl9DQUxMQkFDS1MsXG5cdFx0c2NvcGVzOiBQT1NUTUFOX1NDT1BFUyxcblx0fSk7XG5cdGNvbnN0IGVudllhbWwgPSBidWlsZEVudmlyb25tZW50WWFtbChlbnZOYW1lLCBhdXRoMEVudiwge1xuXHRcdGNhbGxiYWNrczogUE9TVE1BTl9DQUxMQkFDS1MsXG5cdFx0c2NvcGVzOiBQT1NUTUFOX1NDT1BFUyxcblx0fSk7XG5cblx0d29ya3NwYWNlLmFkZEZpbGUoe1xuXHRcdGZpbGVzOiAoKSA9PiBbXG5cdFx0XHR7XG5cdFx0XHRcdGZpbGVQYXRoOiBcIi5wb3N0bWFuL3Jlc291cmNlcy55YW1sXCIsXG5cdFx0XHRcdGNvbnRlbnQ6IFtcblx0XHRcdFx0XHRcIiMgT3BlbiB0aGlzIHByb2plY3Qgcm9vdCBpbiBQb3N0bWFuIChGaWxlcyDihpIgT3BlbiBmb2xkZXIpLCBub3QgdGhlIHBvc3RtYW4vIHN1YmZvbGRlci5cIixcblx0XHRcdFx0XHRcIiMgUG9zdG1hbiBmaWxscyB3b3Jrc3BhY2UuaWQgd2hlbiB5b3UgY29ubmVjdCBMb2NhbCBWaWV3LlwiLFxuXHRcdFx0XHRcdFwiI1wiLFxuXHRcdFx0XHRcdFwiIyBBbGwgcmVzb3VyY2VzIHVuZGVyIHBvc3RtYW4vIGFyZSByZWdpc3RlcmVkIGF1dG9tYXRpY2FsbHkuXCIsXG5cdFx0XHRcdFx0XCIjIFJvdXRlIHJlcXVlc3RzIGFyZSBnZW5lcmF0ZWQgZnJvbSBPcGVuQVBJOyBBdXRoMCBvdmVybGF5IGlzIGhhbmQtYXV0aG9yZWQuXCIsXG5cdFx0XHRcdFx0XCJcIixcblx0XHRcdFx0XS5qb2luKFwiXFxuXCIpLFxuXHRcdFx0fSxcblx0XHRcdHtcblx0XHRcdFx0ZmlsZVBhdGg6IGBwb3N0bWFuL2Vudmlyb25tZW50cy8ke3Byb2plY3ROYW1lfS1Mb2NhbC5lbnZpcm9ubWVudC55YW1sYCxcblx0XHRcdFx0Y29udGVudDogZW52WWFtbCxcblx0XHRcdH0sXG5cdFx0XHQuLi5sb2NhbEZpbGVzLFxuXHRcdF0sXG5cdH0pO1xuXG5cdGlmIChvcHRpb25zLnBvc3RtYW5Qcm92aWRlciA9PT0gXCJhcGlcIiAmJiBvcHRpb25zLmFwaUtleSkge1xuXHRcdGNvbnN0IGhlYWRlcnMgPSB7IFwiWC1BcGktS2V5XCI6IG9wdGlvbnMuYXBpS2V5LCBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIiB9O1xuXG5cdFx0Y29uc3QgY29sUmVzID0gYXdhaXQgZmV0Y2goXG5cdFx0XHRgaHR0cHM6Ly9hcGkuZ2V0cG9zdG1hbi5jb20vY29sbGVjdGlvbnM/d29ya3NwYWNlPSR7b3B0aW9ucy53b3Jrc3BhY2VJZH1gLFxuXHRcdFx0e1xuXHRcdFx0XHRtZXRob2Q6IFwiUE9TVFwiLFxuXHRcdFx0XHRoZWFkZXJzLFxuXHRcdFx0XHRib2R5OiBKU09OLnN0cmluZ2lmeSh7IGNvbGxlY3Rpb24gfSksXG5cdFx0XHR9LFxuXHRcdCk7XG5cdFx0aWYgKGNvbFJlcy5vaykge1xuXHRcdFx0Y29uc29sZS5sb2coXCIgIOKckyBQb3N0bWFuIGNvbGxlY3Rpb24gdXBsb2FkZWRcIik7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXCIgIOKclyBGYWlsZWQgdG8gdXBsb2FkIFBvc3RtYW4gY29sbGVjdGlvblwiKTtcblx0XHR9XG5cblx0XHRjb25zdCBlbnZWYWx1ZXMgPSBbXG5cdFx0XHR7IGtleTogXCJiYXNlVXJsXCIsIHZhbHVlOiBcImh0dHA6Ly9sb2NhbGhvc3Q6MzAwMFwiLCBlbmFibGVkOiB0cnVlIH0sXG5cdFx0XHQuLi4oYXV0aDBFbnY/LmF1dGgwRG9tYWluXG5cdFx0XHRcdD8gW1xuXHRcdFx0XHRcdFx0eyBrZXk6IFwiYXV0aDBEb21haW5cIiwgdmFsdWU6IGF1dGgwRW52LmF1dGgwRG9tYWluLCBlbmFibGVkOiB0cnVlIH0sXG5cdFx0XHRcdFx0XHR7IGtleTogXCJhdXRoMEF1ZGllbmNlXCIsIHZhbHVlOiBhdXRoMEVudi5hdXRoMEF1ZGllbmNlID8/IFwiXCIsIGVuYWJsZWQ6IHRydWUgfSxcblx0XHRcdFx0XHRcdHsga2V5OiBcImF1dGgwQ2xpZW50SWRcIiwgdmFsdWU6IGF1dGgwRW52LmF1dGgwQ2xpZW50SWQgPz8gXCJcIiwgZW5hYmxlZDogdHJ1ZSB9LFxuXHRcdFx0XHRcdF1cblx0XHRcdFx0OiBbXSksXG5cdFx0XTtcblx0XHRjb25zdCBlbnZSZXMgPSBhd2FpdCBmZXRjaChcblx0XHRcdGBodHRwczovL2FwaS5nZXRwb3N0bWFuLmNvbS9lbnZpcm9ubWVudHM/d29ya3NwYWNlPSR7b3B0aW9ucy53b3Jrc3BhY2VJZH1gLFxuXHRcdFx0e1xuXHRcdFx0XHRtZXRob2Q6IFwiUE9TVFwiLFxuXHRcdFx0XHRoZWFkZXJzLFxuXHRcdFx0XHRib2R5OiBKU09OLnN0cmluZ2lmeSh7XG5cdFx0XHRcdFx0ZW52aXJvbm1lbnQ6IHsgbmFtZTogZW52TmFtZSwgdmFsdWVzOiBlbnZWYWx1ZXMgfSxcblx0XHRcdFx0fSksXG5cdFx0XHR9LFxuXHRcdCk7XG5cdFx0aWYgKGVudlJlcy5vaykge1xuXHRcdFx0Y29uc29sZS5sb2coXCIgIOKckyBQb3N0bWFuIGVudmlyb25tZW50IHVwbG9hZGVkXCIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjb25zb2xlLmVycm9yKFwiICDinJcgRmFpbGVkIHRvIHVwbG9hZCBQb3N0bWFuIGVudmlyb25tZW50XCIpO1xuXHRcdH1cblx0fVxufVxuXG5leHBvcnQgY29uc3QgUG9zdG1hbkZlYXR1cmU6IEZlYXR1cmU8UG9zdG1hbk9wdGlvbnM+ID0geyBnZXRPcHRpb25zLCBzY2FmZm9sZCB9O1xuZXhwb3J0IHsgYnVpbGRIZWxsb09wZW5BcGlEb2N1bWVudCB9IGZyb20gXCIuLi9wb3N0bWFuL2hlbGxvLW9wZW5hcGkuanNcIjtcbmV4cG9ydCB7IFBPU1RNQU5fQ0FMTEJBQ0tTLCBQT1NUTUFOX1NDT1BFUyB9O1xuIl0sIm5hbWVzIjpbInJhbmRvbVVVSUQiLCJleGlzdHNTeW5jIiwicmVhZEZpbGVTeW5jIiwiam9pbiIsInBpY2siLCJXRUxMX0tOT1dOX0ZJTEVTIiwiYnVpbGRIZWxsb09wZW5BcGlEb2N1bWVudCIsImJ1aWxkRW52aXJvbm1lbnRZYW1sIiwiYnVpbGRMb2NhbFZpZXdGaWxlc0Zyb21Db2xsZWN0aW9uIiwiYXBwbHlQb3N0bWFuQXV0aE92ZXJsYXkiLCJvcGVuQXBpVG9Qb3N0bWFuQ29sbGVjdGlvbiIsImF1dGgwQ2xpIiwiUE9TVE1BTl9DQUxMQkFDS1MiLCJQT1NUTUFOX1NDT1BFUyIsIkNPTExFQ1RJT05fREVTQ1JJUFRJT04iLCJnZXRPcHRpb25zIiwiX3dvcmtzcGFjZSIsImNsaU9wdGlvbnMiLCJwb3N0bWFuUHJvdmlkZXIiLCJjaG9pY2VzIiwibGFiZWwiLCJkZXNjcmlwdGlvbiIsInNlbGVjdGVkIiwiYyIsInByb3ZpZGVyIiwiYXBpS2V5IiwicHJvY2VzcyIsImVudiIsIlBPU1RNQU5fQVBJX0tFWSIsInRoZW4iLCJtIiwiYXNrIiwiaGVhZGVycyIsIndzUmVzIiwiZmV0Y2giLCJvayIsImNvbnNvbGUiLCJlcnJvciIsIndvcmtzcGFjZXMiLCJqc29uIiwid3NDaG9pY2VzIiwiaWQiLCJtYXAiLCJ3IiwibmFtZSIsInR5cGUiLCJ3c1BpY2tlZCIsIndvcmtzcGFjZUlkIiwid3NOYW1lIiwiY3JlYXRlUmVzIiwibWV0aG9kIiwiYm9keSIsIkpTT04iLCJzdHJpbmdpZnkiLCJ3b3Jrc3BhY2UiLCJ3cyIsImxvZyIsImJ1aWxkSHlicmlkUG9zdG1hbkNvbGxlY3Rpb24iLCJwcm9qZWN0TmFtZSIsImF1dGgiLCJvcGVuYXBpIiwiYmFzZSIsImluZm8iLCJfcG9zdG1hbl9pZCIsImNhbGxiYWNrcyIsInNjb3BlcyIsInJlYWRFeGlzdGluZ1NwYUNsaWVudElkIiwidGFyZ2V0RGlyIiwiZW52UGF0aCIsInVuZGVmaW5lZCIsInRleHQiLCJtYXRjaCIsInZhbHVlIiwidHJpbSIsImxlbmd0aCIsInJlc29sdmVTcGFDbGllbnRJZCIsImFwcE5hbWUiLCJhcHAiLCJlbnN1cmVTcGFBcHAiLCJyZXVzZWQiLCJjbGllbnRfaWQiLCJlbmFibGVDb25uZWN0aW9uRm9yQ2xpZW50IiwiREJfQ09OTkVDVElPTl9OQU1FIiwiZXJyIiwiRXJyb3IiLCJtZXNzYWdlIiwiZXhpc3RpbmciLCJkZXRhaWwiLCJTdHJpbmciLCJpc0F1dGgwRW50aXR5TGltaXRFcnJvciIsInNjYWZmb2xkIiwib3B0aW9ucyIsImF1dGhDb25maWdNb2RlbCIsImdldE1vZGVsIiwiQVVUSF9DT05GSUciLCJhdXRoQ2ZnIiwiY29uZmlnIiwic3BhQ2xpZW50SWQiLCJpc3N1ZXJCYXNlVXJsIiwiYXV0aDBFbnYiLCJhdXRoMERvbWFpbiIsInJlcGxhY2UiLCJhdXRoMEF1ZGllbmNlIiwiYXVkaWVuY2UiLCJhdXRoMENsaWVudElkIiwiZW52TmFtZSIsImNvbGxlY3Rpb24iLCJsb2NhbEZpbGVzIiwiZW52WWFtbCIsImFkZEZpbGUiLCJmaWxlcyIsImZpbGVQYXRoIiwiY29udGVudCIsImNvbFJlcyIsImVudlZhbHVlcyIsImtleSIsImVuYWJsZWQiLCJlbnZSZXMiLCJlbnZpcm9ubWVudCIsInZhbHVlcyIsIlBvc3RtYW5GZWF0dXJlIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxVQUFVLFFBQVEsY0FBYztBQUN6QyxTQUFTQyxVQUFVLEVBQUVDLFlBQVksUUFBUSxVQUFVO0FBQ25ELFNBQVNDLElBQUksUUFBUSxZQUFZO0FBQ2pDLFNBQVNDLElBQUksUUFBUSx5QkFBeUI7QUFDOUMsU0FBU0MsZ0JBQWdCLFFBQVEsd0JBQXdCO0FBSXpELFNBQVNDLHlCQUF5QixRQUFRLDhCQUE4QjtBQUN4RSxTQUNDQyxvQkFBb0IsRUFDcEJDLGlDQUFpQyxRQUMzQiwyQkFBMkI7QUFDbEMsU0FFQ0MsdUJBQXVCLEVBQ3ZCQywwQkFBMEIsUUFDcEIsbUNBQW1DO0FBQzFDLFlBQVlDLGNBQWMsaUJBQWlCO0FBRTNDLHFFQUFxRSxHQUNyRSxNQUFNQyxvQkFBb0I7SUFDekI7SUFDQTtDQUNBO0FBRUQsOEVBQThFLEdBQzlFLE1BQU1DLGlC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
@@ -0,0 +1,55 @@
1
+ import { WELL_KNOWN_FILES } from "../../models/const.js";
2
+ import { sortStringMap } from "../../models/package-json.model.js";
3
+ import { CREATE_VERSION } from "../../version.js";
4
+ /**
5
+ * Builder for `projects/<api>/package.json`.
6
+ *
7
+ * Starts with the core cortex + crucible deps. Features can call
8
+ * `addDependency` / `addDevDependency` to extend.
9
+ */ export class ApiPackageJson {
10
+ workspaceName;
11
+ apiName;
12
+ key = WELL_KNOWN_FILES.API_PACKAGE_JSON;
13
+ _dependencies;
14
+ _devDependencies = {};
15
+ constructor(workspaceName, apiName = "api"){
16
+ this.workspaceName = workspaceName;
17
+ this.apiName = apiName;
18
+ this._dependencies = {
19
+ "@decohere/cortex": CREATE_VERSION,
20
+ "@decohere/crucible": CREATE_VERSION
21
+ };
22
+ }
23
+ addDependency(name, version) {
24
+ this._dependencies[name] = version;
25
+ return this;
26
+ }
27
+ addDevDependency(name, version) {
28
+ this._devDependencies[name] = version;
29
+ return this;
30
+ }
31
+ files() {
32
+ const pkg = {
33
+ name: `@${this.workspaceName}/${this.apiName}`,
34
+ version: "0.0.1",
35
+ private: true,
36
+ type: "module",
37
+ main: "src/main.ts",
38
+ scripts: {
39
+ lint: "biome check --write ."
40
+ },
41
+ dependencies: sortStringMap(this._dependencies)
42
+ };
43
+ if (Object.keys(this._devDependencies).length > 0) {
44
+ pkg.devDependencies = sortStringMap(this._devDependencies);
45
+ }
46
+ return [
47
+ {
48
+ filePath: "package.json",
49
+ content: JSON.stringify(pkg, null, 2)
50
+ }
51
+ ];
52
+ }
53
+ }
54
+
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvbW9kZWxzL2FwaS1wYWNrYWdlLWpzb24ubW9kZWwudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgV0VMTF9LTk9XTl9GSUxFUyB9IGZyb20gXCIuLi8uLi9tb2RlbHMvY29uc3QuanNcIjtcbmltcG9ydCB7IHNvcnRTdHJpbmdNYXAgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3BhY2thZ2UtanNvbi5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBLZXllZE1vZGVsLCBTb3VyY2VGaWxlIH0gZnJvbSBcIi4uLy4uL21vZGVscy9zb3VyY2UtZmlsZS5qc1wiO1xuaW1wb3J0IHsgQ1JFQVRFX1ZFUlNJT04gfSBmcm9tIFwiLi4vLi4vdmVyc2lvbi5qc1wiO1xuXG4vKipcbiAqIEJ1aWxkZXIgZm9yIGBwcm9qZWN0cy88YXBpPi9wYWNrYWdlLmpzb25gLlxuICpcbiAqIFN0YXJ0cyB3aXRoIHRoZSBjb3JlIGNvcnRleCArIGNydWNpYmxlIGRlcHMuIEZlYXR1cmVzIGNhbiBjYWxsXG4gKiBgYWRkRGVwZW5kZW5jeWAgLyBgYWRkRGV2RGVwZW5kZW5jeWAgdG8gZXh0ZW5kLlxuICovXG5leHBvcnQgY2xhc3MgQXBpUGFja2FnZUpzb24gaW1wbGVtZW50cyBLZXllZE1vZGVsIHtcblx0cHVibGljIHJlYWRvbmx5IGtleSA9IFdFTExfS05PV05fRklMRVMuQVBJX1BBQ0tBR0VfSlNPTjtcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9kZXBlbmRlbmNpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cdHByaXZhdGUgcmVhZG9ubHkgX2RldkRlcGVuZGVuY2llczogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuXG5cdHB1YmxpYyBjb25zdHJ1Y3Rvcihcblx0XHRwcml2YXRlIHJlYWRvbmx5IHdvcmtzcGFjZU5hbWU6IHN0cmluZyxcblx0XHRwcml2YXRlIHJlYWRvbmx5IGFwaU5hbWUgPSBcImFwaVwiLFxuXHQpIHtcblx0XHR0aGlzLl9kZXBlbmRlbmNpZXMgPSB7XG5cdFx0XHRcIkBkZWNvaGVyZS9jb3J0ZXhcIjogQ1JFQVRFX1ZFUlNJT04sXG5cdFx0XHRcIkBkZWNvaGVyZS9jcnVjaWJsZVwiOiBDUkVBVEVfVkVSU0lPTixcblx0XHR9O1xuXHR9XG5cblx0cHVibGljIGFkZERlcGVuZGVuY3kobmFtZTogc3RyaW5nLCB2ZXJzaW9uOiBzdHJpbmcpOiB0aGlzIHtcblx0XHR0aGlzLl9kZXBlbmRlbmNpZXNbbmFtZV0gPSB2ZXJzaW9uO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIGFkZERldkRlcGVuZGVuY3kobmFtZTogc3RyaW5nLCB2ZXJzaW9uOiBzdHJpbmcpOiB0aGlzIHtcblx0XHR0aGlzLl9kZXZEZXBlbmRlbmNpZXNbbmFtZV0gPSB2ZXJzaW9uO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIGZpbGVzKCk6IFNvdXJjZUZpbGVbXSB7XG5cdFx0Y29uc3QgcGtnOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHtcblx0XHRcdG5hbWU6IGBAJHt0aGlzLndvcmtzcGFjZU5hbWV9LyR7dGhpcy5hcGlOYW1lfWAsXG5cdFx0XHR2ZXJzaW9uOiBcIjAuMC4xXCIsXG5cdFx0XHRwcml2YXRlOiB0cnVlLFxuXHRcdFx0dHlwZTogXCJtb2R1bGVcIixcblx0XHRcdG1haW46IFwic3JjL21haW4udHNcIixcblx0XHRcdHNjcmlwdHM6IHtcblx0XHRcdFx0bGludDogXCJiaW9tZSBjaGVjayAtLXdyaXRlIC5cIixcblx0XHRcdH0sXG5cdFx0XHRkZXBlbmRlbmNpZXM6IHNvcnRTdHJpbmdNYXAodGhpcy5fZGVwZW5kZW5jaWVzKSxcblx0XHR9O1xuXHRcdGlmIChPYmplY3Qua2V5cyh0aGlzLl9kZXZEZXBlbmRlbmNpZXMpLmxlbmd0aCA+IDApIHtcblx0XHRcdHBrZy5kZXZEZXBlbmRlbmNpZXMgPSBzb3J0U3RyaW5nTWFwKHRoaXMuX2RldkRlcGVuZGVuY2llcyk7XG5cdFx0fVxuXHRcdHJldHVybiBbXG5cdFx0XHR7XG5cdFx0XHRcdGZpbGVQYXRoOiBcInBhY2thZ2UuanNvblwiLFxuXHRcdFx0XHRjb250ZW50OiBKU09OLnN0cmluZ2lmeShwa2csIG51bGwsIDIpLFxuXHRcdFx0fSxcblx0XHRdO1xuXHR9XG59XG4iXSwibmFtZXMiOlsiV0VMTF9LTk9XTl9GSUxFUyIsInNvcnRTdHJpbmdNYXAiLCJDUkVBVEVfVkVSU0lPTiIsIkFwaVBhY2thZ2VKc29uIiwia2V5IiwiQVBJX1BBQ0tBR0VfSlNPTiIsIl9kZXBlbmRlbmNpZXMiLCJfZGV2RGVwZW5kZW5jaWVzIiwid29ya3NwYWNlTmFtZSIsImFwaU5hbWUiLCJhZGREZXBlbmRlbmN5IiwibmFtZSIsInZlcnNpb24iLCJhZGREZXZEZXBlbmRlbmN5IiwiZmlsZXMiLCJwa2ciLCJwcml2YXRlIiwidHlwZSIsIm1haW4iLCJzY3JpcHRzIiwibGludCIsImRlcGVuZGVuY2llcyIsIk9iamVjdCIsImtleXMiLCJsZW5ndGgiLCJkZXZEZXBlbmRlbmNpZXMiLCJmaWxlUGF0aCIsImNvbnRlbnQiLCJKU09OIiwic3RyaW5naWZ5Il0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxnQkFBZ0IsUUFBUSx3QkFBd0I7QUFDekQsU0FBU0MsYUFBYSxRQUFRLHFDQUFxQztBQUVuRSxTQUFTQyxjQUFjLFFBQVEsbUJBQW1CO0FBRWxEOzs7OztDQUtDLEdBQ0QsT0FBTyxNQUFNQzs7O0lBQ0lDLE1BQU1KLGlCQUFpQkssZ0JBQWdCLENBQUM7SUFFdkNDLGNBQXNDO0lBQ3RDQyxtQkFBMkMsQ0FBQyxFQUFFO0lBRS9ELFlBQ0MsQUFBaUJDLGFBQXFCLEVBQ3RDLEFBQWlCQyxVQUFVLEtBQUssQ0FDL0I7YUFGZ0JELGdCQUFBQTthQUNBQyxVQUFBQTtRQUVqQixJQUFJLENBQUNILGFBQWEsR0FBRztZQUNwQixvQkFBb0JKO1lBQ3BCLHNCQUFzQkE7UUFDdkI7SUFDRDtJQUVPUSxjQUFjQyxJQUFZLEVBQUVDLE9BQWUsRUFBUTtRQUN6RCxJQUFJLENBQUNOLGFBQWEsQ0FBQ0ssS0FBSyxHQUFHQztRQUMzQixPQUFPLElBQUk7SUFDWjtJQUVPQyxpQkFBaUJGLElBQVksRUFBRUMsT0FBZSxFQUFRO1FBQzVELElBQUksQ0FBQ0wsZ0JBQWdCLENBQUNJLEtBQUssR0FBR0M7UUFDOUIsT0FBTyxJQUFJO0lBQ1o7SUFFT0UsUUFBc0I7UUFDNUIsTUFBTUMsTUFBK0I7WUFDcENKLE1BQU0sQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDSCxhQUFhLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQ0MsT0FBTyxFQUFFO1lBQzlDRyxTQUFTO1lBQ1RJLFNBQVM7WUFDVEMsTUFBTTtZQUNOQyxNQUFNO1lBQ05DLFNBQVM7Z0JBQ1JDLE1BQU07WUFDUDtZQUNBQyxjQUFjcEIsY0FBYyxJQUFJLENBQUNLLGFBQWE7UUFDL0M7UUFDQSxJQUFJZ0IsT0FBT0MsSUFBSSxDQUFDLElBQUksQ0FBQ2hCLGdCQUFnQixFQUFFaUIsTUFBTSxHQUFHLEdBQUc7WUFDbERULElBQUlVLGVBQWUsR0FBR3hCLGNBQWMsSUFBSSxDQUFDTSxnQkFBZ0I7UUFDMUQ7UUFDQSxPQUFPO1lBQ047Z0JBQ0NtQixVQUFVO2dCQUNWQyxTQUFTQyxLQUFLQyxTQUFTLENBQUNkLEtBQUssTUFBTTtZQUNwQztTQUNBO0lBQ0Y7QUFDRCJ9
@@ -0,0 +1,22 @@
1
+ import { WELL_KNOWN_FILES } from "../../models/const.js";
2
+ /**
3
+ * Data-carrier model for auth configuration.
4
+ *
5
+ * Registered by AuthFeature when auth0 is configured. Other features (e.g.
6
+ * PostmanFeature) retrieve it via workspace.getModel(WELL_KNOWN_FILES.AUTH_CONFIG).
7
+ * Produces no files — exists solely so features can communicate auth details.
8
+ */ export class AuthConfigModel {
9
+ config;
10
+ key = WELL_KNOWN_FILES.AUTH_CONFIG;
11
+ constructor(config){
12
+ this.config = config;
13
+ }
14
+ setAdminUser(adminUser) {
15
+ this.config.adminUser = adminUser;
16
+ }
17
+ files() {
18
+ return [];
19
+ }
20
+ }
21
+
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvbW9kZWxzL2F1dGgtY29uZmlnLm1vZGVsLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFdFTExfS05PV05fRklMRVMgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL2NvbnN0LmpzXCI7XG5pbXBvcnQgdHlwZSB7IEtleWVkTW9kZWwsIFNvdXJjZUZpbGUgfSBmcm9tIFwiLi4vLi4vbW9kZWxzL3NvdXJjZS1maWxlLmpzXCI7XG5cbmV4cG9ydCB0eXBlIEFkbWluVXNlckNvbmZpZyA9IHtcblx0c3ViOiBzdHJpbmc7XG5cdGVtYWlsOiBzdHJpbmc7XG5cdHBhc3N3b3JkOiBzdHJpbmc7XG5cdHVzZXJuYW1lOiBzdHJpbmc7XG59O1xuXG5leHBvcnQgdHlwZSBBdXRoQ29uZmlnID0ge1xuXHRpc3N1ZXJCYXNlVXJsOiBzdHJpbmc7XG5cdGF1ZGllbmNlOiBzdHJpbmc7XG5cdGFkbWluVXNlcj86IEFkbWluVXNlckNvbmZpZztcbn07XG5cbi8qKlxuICogRGF0YS1jYXJyaWVyIG1vZGVsIGZvciBhdXRoIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogUmVnaXN0ZXJlZCBieSBBdXRoRmVhdHVyZSB3aGVuIGF1dGgwIGlzIGNvbmZpZ3VyZWQuIE90aGVyIGZlYXR1cmVzIChlLmcuXG4gKiBQb3N0bWFuRmVhdHVyZSkgcmV0cmlldmUgaXQgdmlhIHdvcmtzcGFjZS5nZXRNb2RlbChXRUxMX0tOT1dOX0ZJTEVTLkFVVEhfQ09ORklHKS5cbiAqIFByb2R1Y2VzIG5vIGZpbGVzIOKAlCBleGlzdHMgc29sZWx5IHNvIGZlYXR1cmVzIGNhbiBjb21tdW5pY2F0ZSBhdXRoIGRldGFpbHMuXG4gKi9cbmV4cG9ydCBjbGFzcyBBdXRoQ29uZmlnTW9kZWwgaW1wbGVtZW50cyBLZXllZE1vZGVsIHtcblx0cHVibGljIHJlYWRvbmx5IGtleSA9IFdFTExfS05PV05fRklMRVMuQVVUSF9DT05GSUc7XG5cblx0cHVibGljIGNvbnN0cnVjdG9yKHB1YmxpYyByZWFkb25seSBjb25maWc6IEF1dGhDb25maWcpIHt9XG5cblx0cHVibGljIHNldEFkbWluVXNlcihhZG1pblVzZXI6IEFkbWluVXNlckNvbmZpZyk6IHZvaWQge1xuXHRcdHRoaXMuY29uZmlnLmFkbWluVXNlciA9IGFkbWluVXNlcjtcblx0fVxuXG5cdHB1YmxpYyBmaWxlcygpOiBTb3VyY2VGaWxlW10ge1xuXHRcdHJldHVybiBbXTtcblx0fVxufVxuIl0sIm5hbWVzIjpbIldFTExfS05PV05fRklMRVMiLCJBdXRoQ29uZmlnTW9kZWwiLCJrZXkiLCJBVVRIX0NPTkZJRyIsImNvbmZpZyIsInNldEFkbWluVXNlciIsImFkbWluVXNlciIsImZpbGVzIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxnQkFBZ0IsUUFBUSx3QkFBd0I7QUFnQnpEOzs7Ozs7Q0FNQyxHQUNELE9BQU8sTUFBTUM7O0lBQ0lDLE1BQU1GLGlCQUFpQkcsV0FBVyxDQUFDO0lBRW5ELFlBQW1CLEFBQWdCQyxNQUFrQixDQUFFO2FBQXBCQSxTQUFBQTtJQUFxQjtJQUVqREMsYUFBYUMsU0FBMEIsRUFBUTtRQUNyRCxJQUFJLENBQUNGLE1BQU0sQ0FBQ0UsU0FBUyxHQUFHQTtJQUN6QjtJQUVPQyxRQUFzQjtRQUM1QixPQUFPLEVBQUU7SUFDVjtBQUNEIn0=
@@ -0,0 +1,184 @@
1
+ import { WELL_KNOWN_FILES } from "../../models/const.js";
2
+ /** Tracks named imports from a single module path, split into values and types. */ class ImportGroup {
3
+ _values = [];
4
+ _types = [];
5
+ add(name, typeOnly = false) {
6
+ if (typeOnly) {
7
+ // Value import already present — value wins, skip
8
+ if (!this._values.includes(name) && !this._types.includes(name)) {
9
+ this._types.push(name);
10
+ }
11
+ } else {
12
+ // Promote: remove from types if it was previously type-only
13
+ const typeIdx = this._types.indexOf(name);
14
+ if (typeIdx !== -1) this._types.splice(typeIdx, 1);
15
+ if (!this._values.includes(name)) this._values.push(name);
16
+ }
17
+ return this;
18
+ }
19
+ render(from) {
20
+ const values = [
21
+ ...this._values
22
+ ].sort();
23
+ const types = [
24
+ ...this._types
25
+ ].sort().map((n)=>`type ${n}`);
26
+ return `import { ${[
27
+ ...values,
28
+ ...types
29
+ ].join(", ")} } from "${from}";`;
30
+ }
31
+ }
32
+ /**
33
+ * A controller method. Features call `addDecorator()` to prepend decorators
34
+ * before the HTTP verb decorator (e.g. `@AllowAnonymous` before `@Get()`).
35
+ */ export class ControllerMethod {
36
+ name;
37
+ _httpDecorator;
38
+ _params;
39
+ _extraDecorators = [];
40
+ _body;
41
+ _isAsync;
42
+ constructor(name, _httpDecorator, _params, isAsync, body){
43
+ this.name = name;
44
+ this._httpDecorator = _httpDecorator;
45
+ this._params = _params;
46
+ this._isAsync = isAsync;
47
+ this._body = body;
48
+ }
49
+ addDecorator(decorator) {
50
+ this._extraDecorators.push(decorator);
51
+ return this;
52
+ }
53
+ /** Replace the method body lines (used by features that extend generated behaviour). */ setBody(body) {
54
+ this._body = body;
55
+ return this;
56
+ }
57
+ setAsync(isAsync = true) {
58
+ this._isAsync = isAsync;
59
+ return this;
60
+ }
61
+ render() {
62
+ const lines = [];
63
+ for (const d of this._extraDecorators){
64
+ lines.push(`\t${d}`);
65
+ }
66
+ lines.push(`\t${this._httpDecorator}`);
67
+ const asyncKw = this._isAsync ? "async " : "";
68
+ lines.push(`\tpublic ${asyncKw}${this.name}(${this._params}) {`);
69
+ for (const line of this._body){
70
+ lines.push(`\t\t${line}`);
71
+ }
72
+ lines.push("\t}");
73
+ return lines;
74
+ }
75
+ }
76
+ /**
77
+ * Model for `projects/api/src/controllers/hello.controller.ts`.
78
+ *
79
+ * Pre-initialised with all routes and their HTTP decorators. Features mutate
80
+ * the model via `getMethod(name).addDecorator(...)`, `addDecorator(...)` (class
81
+ * level), `addCortexImport(...)`, `addImport(...)`, and `addConstructorParam(...)`.
82
+ */ export class ControllerSourceFile {
83
+ key = WELL_KNOWN_FILES.CONTROLLER_TS;
84
+ _cortexImports = new ImportGroup().add("Controller").add("Delete").add("Field").add("Get").add("Param").add("Post").add("Put").add("Query");
85
+ _extraImportGroups = new Map([
86
+ [
87
+ "@decohere/crucible/decorators",
88
+ new ImportGroup().add("inject")
89
+ ]
90
+ ]);
91
+ _classDecorators = [];
92
+ /** Explicit @inject — design:paramtypes can collapse to Object under SWC when the class is still undefined at decorate time. */ _ctorParams = [
93
+ '@inject("SampleService") private readonly sample: SampleService'
94
+ ];
95
+ _methods = new Map([
96
+ [
97
+ "getAll",
98
+ new ControllerMethod("getAll", "@Get()", '@Query("filter") filter: string', true, [
99
+ "const greeting = await this.sample.getGreeting();",
100
+ "return { filter, message: greeting };"
101
+ ])
102
+ ],
103
+ [
104
+ "getOne",
105
+ new ControllerMethod("getOne", '@Get("/:id")', '@Param("id") id: string', false, // biome-ignore lint/suspicious/noTemplateCurlyInString: template literal in generated code
106
+ [
107
+ "return { id, message: `Hello ${id}!` };"
108
+ ])
109
+ ],
110
+ [
111
+ "create",
112
+ new ControllerMethod("create", "@Post()", "body: HelloBody", false, [
113
+ "return { message: body.message };"
114
+ ])
115
+ ],
116
+ [
117
+ "update",
118
+ new ControllerMethod("update", '@Put("/:id")', '@Param("id") id: string, body: HelloBody', false, [
119
+ "return { id, message: body.message };"
120
+ ])
121
+ ],
122
+ [
123
+ "remove",
124
+ new ControllerMethod("remove", '@Delete("/:id")', '@Param("id") id: string', false, [
125
+ "return { id, deleted: true };"
126
+ ])
127
+ ]
128
+ ]);
129
+ /** Retrieve a method by name to mutate its decorators. */ getMethod(name) {
130
+ const m = this._methods.get(name);
131
+ if (m == null) throw new Error(`No method '${name}' on ControllerSourceFile`);
132
+ return m;
133
+ }
134
+ /** Add a class-level decorator (e.g. `@Authorize`). */ addDecorator(decorator) {
135
+ this._classDecorators.push(decorator);
136
+ return this;
137
+ }
138
+ /** Add a named import from `@decohere/cortex`. */ addCortexImport(name, typeOnly = false) {
139
+ this._cortexImports.add(name, typeOnly);
140
+ return this;
141
+ }
142
+ /** Add a named import from any other module. */ addImport(name, from, typeOnly = false) {
143
+ const group = this._extraImportGroups.get(from) ?? new ImportGroup();
144
+ group.add(name, typeOnly);
145
+ this._extraImportGroups.set(from, group);
146
+ return this;
147
+ }
148
+ /** Add a constructor parameter (e.g. an injected dependency). */ addConstructorParam(param) {
149
+ this._ctorParams.push(param);
150
+ return this;
151
+ }
152
+ files() {
153
+ const lines = [
154
+ this._cortexImports.render("@decohere/cortex"),
155
+ 'import { SampleService } from "../services/sample.service.js";'
156
+ ];
157
+ for (const [from, group] of this._extraImportGroups){
158
+ lines.push(group.render(from));
159
+ }
160
+ lines.push("", "class HelloBody {", '\t@Field("body", "message")', "\tpublic message!: string;", "}", "");
161
+ for (const d of this._classDecorators){
162
+ lines.push(d);
163
+ }
164
+ lines.push('@Controller({ prefix: "/hello" })', "export class HelloController {", "");
165
+ lines.push("\tpublic constructor(");
166
+ for (const p of this._ctorParams){
167
+ lines.push(`\t\t${p},`);
168
+ }
169
+ lines.push("\t) {}");
170
+ lines.push("");
171
+ for (const method of this._methods.values()){
172
+ lines.push(...method.render(), "");
173
+ }
174
+ lines.push("}", "");
175
+ return [
176
+ {
177
+ filePath: "src/controllers/hello.controller.ts",
178
+ content: lines.join("\n")
179
+ }
180
+ ];
181
+ }
182
+ }
183
+
184
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL3NjYWZmb2xkL3NyYy93ZWJhcGkvbW9kZWxzL2NvbnRyb2xsZXItc291cmNlLWZpbGUubW9kZWwudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgV0VMTF9LTk9XTl9GSUxFUyB9IGZyb20gXCIuLi8uLi9tb2RlbHMvY29uc3QuanNcIjtcbmltcG9ydCB0eXBlIHsgS2V5ZWRNb2RlbCwgU291cmNlRmlsZSB9IGZyb20gXCIuLi8uLi9tb2RlbHMvc291cmNlLWZpbGUuanNcIjtcblxuLyoqIFRyYWNrcyBuYW1lZCBpbXBvcnRzIGZyb20gYSBzaW5nbGUgbW9kdWxlIHBhdGgsIHNwbGl0IGludG8gdmFsdWVzIGFuZCB0eXBlcy4gKi9cbmNsYXNzIEltcG9ydEdyb3VwIHtcblx0cHJpdmF0ZSByZWFkb25seSBfdmFsdWVzOiBzdHJpbmdbXSA9IFtdO1xuXHRwcml2YXRlIHJlYWRvbmx5IF90eXBlczogc3RyaW5nW10gPSBbXTtcblxuXHRwdWJsaWMgYWRkKG5hbWU6IHN0cmluZywgdHlwZU9ubHkgPSBmYWxzZSk6IHRoaXMge1xuXHRcdGlmICh0eXBlT25seSkge1xuXHRcdFx0Ly8gVmFsdWUgaW1wb3J0IGFscmVhZHkgcHJlc2VudCDigJQgdmFsdWUgd2lucywgc2tpcFxuXHRcdFx0aWYgKCF0aGlzLl92YWx1ZXMuaW5jbHVkZXMobmFtZSkgJiYgIXRoaXMuX3R5cGVzLmluY2x1ZGVzKG5hbWUpKSB7XG5cdFx0XHRcdHRoaXMuX3R5cGVzLnB1c2gobmFtZSk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIFByb21vdGU6IHJlbW92ZSBmcm9tIHR5cGVzIGlmIGl0IHdhcyBwcmV2aW91c2x5IHR5cGUtb25seVxuXHRcdFx0Y29uc3QgdHlwZUlkeCA9IHRoaXMuX3R5cGVzLmluZGV4T2YobmFtZSk7XG5cdFx0XHRpZiAodHlwZUlkeCAhPT0gLTEpIHRoaXMuX3R5cGVzLnNwbGljZSh0eXBlSWR4LCAxKTtcblx0XHRcdGlmICghdGhpcy5fdmFsdWVzLmluY2x1ZGVzKG5hbWUpKSB0aGlzLl92YWx1ZXMucHVzaChuYW1lKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRwdWJsaWMgcmVuZGVyKGZyb206IHN0cmluZyk6IHN0cmluZyB7XG5cdFx0Y29uc3QgdmFsdWVzID0gWy4uLnRoaXMuX3ZhbHVlc10uc29ydCgpO1xuXHRcdGNvbnN0IHR5cGVzID0gWy4uLnRoaXMuX3R5cGVzXS5zb3J0KCkubWFwKChuKSA9PiBgdHlwZSAke259YCk7XG5cdFx0cmV0dXJuIGBpbXBvcnQgeyAke1suLi52YWx1ZXMsIC4uLnR5cGVzXS5qb2luKFwiLCBcIil9IH0gZnJvbSBcIiR7ZnJvbX1cIjtgO1xuXHR9XG59XG5cbi8qKlxuICogQSBjb250cm9sbGVyIG1ldGhvZC4gRmVhdHVyZXMgY2FsbCBgYWRkRGVjb3JhdG9yKClgIHRvIHByZXBlbmQgZGVjb3JhdG9yc1xuICogYmVmb3JlIHRoZSBIVFRQIHZlcmIgZGVjb3JhdG9yIChlLmcuIGBAQWxsb3dBbm9ueW1vdXNgIGJlZm9yZSBgQEdldCgpYCkuXG4gKi9cbmV4cG9ydCBjbGFzcyBDb250cm9sbGVyTWV0aG9kIHtcblx0cHJpdmF0ZSByZWFkb25seSBfZXh0cmFEZWNvcmF0b3JzOiBzdHJpbmdbXSA9IFtdO1xuXHRwcml2YXRlIF9ib2R5OiBzdHJpbmdbXTtcblx0cHJpdmF0ZSBfaXNBc3luYzogYm9vbGVhbjtcblxuXHRwdWJsaWMgY29uc3RydWN0b3IoXG5cdFx0cHVibGljIHJlYWRvbmx5IG5hbWU6IHN0cmluZyxcblx0XHRwcml2YXRlIHJlYWRvbmx5IF9odHRwRGVjb3JhdG9yOiBzdHJpbmcsXG5cdFx0cHJpdmF0ZSByZWFkb25seSBfcGFyYW1zOiBzdHJpbmcsXG5cdFx0aXNBc3luYzogYm9vbGVhbixcblx0XHRib2R5OiBzdHJpbmdbXSxcblx0KSB7XG5cdFx0dGhpcy5faXNBc3luYyA9IGlzQXN5bmM7XG5cdFx0dGhpcy5fYm9keSA9IGJvZHk7XG5cdH1cblxuXHRwdWJsaWMgYWRkRGVjb3JhdG9yKGRlY29yYXRvcjogc3RyaW5nKTogdGhpcyB7XG5cdFx0dGhpcy5fZXh0cmFEZWNvcmF0b3JzLnB1c2goZGVjb3JhdG9yKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKiBSZXBsYWNlIHRoZSBtZXRob2QgYm9keSBsaW5lcyAodXNlZCBieSBmZWF0dXJlcyB0aGF0IGV4dGVuZCBnZW5lcmF0ZWQgYmVoYXZpb3VyKS4gKi9cblx0cHVibGljIHNldEJvZHkoYm9keTogc3RyaW5nW10pOiB0aGlzIHtcblx0XHR0aGlzLl9ib2R5ID0gYm9keTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHB1YmxpYyBzZXRBc3luYyhpc0FzeW5jID0gdHJ1ZSk6IHRoaXMge1xuXHRcdHRoaXMuX2lzQXN5bmMgPSBpc0FzeW5jO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0cHVibGljIHJlbmRlcigpOiBzdHJpbmdbXSB7XG5cdFx0Y29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cdFx0Zm9yIChjb25zdCBkIG9mIHRoaXMuX2V4dHJhRGVjb3JhdG9ycykge1xuXHRcdFx0bGluZXMucHVzaChgXFx0JHtkfWApO1xuXHRcdH1cblx0XHRsaW5lcy5wdXNoKGBcXHQke3RoaXMuX2h0dHBEZWNvcmF0b3J9YCk7XG5cdFx0Y29uc3QgYXN5bmNLdyA9IHRoaXMuX2lzQXN5bmMgPyBcImFzeW5jIFwiIDogXCJcIjtcblx0XHRsaW5lcy5wdXNoKGBcXHRwdWJsaWMgJHthc3luY0t3fSR7dGhpcy5uYW1lfSgke3RoaXMuX3BhcmFtc30pIHtgKTtcblx0XHRmb3IgKGNvbnN0IGxpbmUgb2YgdGhpcy5fYm9keSkge1xuXHRcdFx0bGluZXMucHVzaChgXFx0XFx0JHtsaW5lfWApO1xuXHRcdH1cblx0XHRsaW5lcy5wdXNoKFwiXFx0fVwiKTtcblx0XHRyZXR1cm4gbGluZXM7XG5cdH1cbn1cblxuLyoqXG4gKiBNb2RlbCBmb3IgYHByb2plY3RzL2FwaS9zcmMvY29udHJvbGxlcnMvaGVsbG8uY29udHJvbGxlci50c2AuXG4gKlxuICogUHJlLWluaXRpYWxpc2VkIHdpdGggYWxsIHJvdXRlcyBhbmQgdGhlaXIgSFRUUCBkZWNvcmF0b3JzLiBGZWF0dXJlcyBtdXRhdGVcbiAqIHRoZSBtb2RlbCB2aWEgYGdldE1ldGhvZChuYW1lKS5hZGREZWNvcmF0b3IoLi4uKWAsIGBhZGREZWNvcmF0b3IoLi4uKWAgKGNsYXNzXG4gKiBsZXZlbCksIGBhZGRDb3J0ZXhJbXBvcnQoLi4uKWAsIGBhZGRJbXBvcnQoLi4uKWAsIGFuZCBgYWRkQ29uc3RydWN0b3JQYXJhbSguLi4pYC5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbnRyb2xsZXJTb3VyY2VGaWxlIGltcGxlbWVudHMgS2V5ZWRNb2RlbCB7XG5cdHB1YmxpYyByZWFkb25seSBrZXkgPSBXRUxMX0tOT1dOX0ZJTEVTLkNPTlRST0xMRVJfVFM7XG5cblx0cHJpdmF0ZSByZWFkb25seSBfY29ydGV4SW1wb3J0cyA9IG5ldyBJbXBvcnRHcm91cCgpXG5cdFx0LmFkZChcIkNvbnRyb2xsZXJcIilcblx0XHQuYWRkKFwiRGVsZXRlXCIpXG5cdFx0LmFkZChcIkZpZWxkXCIpXG5cdFx0LmFkZChcIkdldFwiKVxuXHRcdC5hZGQoXCJQYXJhbVwiKVxuXHRcdC5hZGQoXCJQb3N0XCIpXG5cdFx0LmFkZChcIlB1dFwiKVxuXHRcdC5hZGQoXCJRdWVyeVwiKTtcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9leHRyYUltcG9ydEdyb3VwcyA9IG5ldyBNYXA8c3RyaW5nLCBJbXBvcnRHcm91cD4oW1xuXHRcdFtcIkBkZWNvaGVyZS9jcnVjaWJsZS9kZWNvcmF0b3JzXCIsIG5ldyBJbXBvcnRHcm91cCgpLmFkZChcImluamVjdFwiKV0sXG5cdF0pO1xuXHRwcml2YXRlIHJlYWRvbmx5IF9jbGFzc0RlY29yYXRvcnM6IHN0cmluZ1tdID0gW107XG5cdC8qKiBFeHBsaWNpdCBAaW5qZWN0IOKAlCBkZXNpZ246cGFyYW10eXBlcyBjYW4gY29sbGFwc2UgdG8gT2JqZWN0IHVuZGVyIFNXQyB3aGVuIHRoZSBjbGFzcyBpcyBzdGlsbCB1bmRlZmluZWQgYXQgZGVjb3JhdGUgdGltZS4gKi9cblx0cHJpdmF0ZSByZWFkb25seSBfY3RvclBhcmFtczogc3RyaW5nW10gPSBbXG5cdFx0J0BpbmplY3QoXCJTYW1wbGVTZXJ2aWNlXCIpIHByaXZhdGUgcmVhZG9ubHkgc2FtcGxlOiBTYW1wbGVTZXJ2aWNlJyxcblx0XTtcblxuXHRwcml2YXRlIHJlYWRvbmx5IF9tZXRob2RzID0gbmV3IE1hcDxzdHJpbmcsIENvbnRyb2xsZXJNZXRob2Q+KFtcblx0XHRbXG5cdFx0XHRcImdldEFsbFwiLFxuXHRcdFx0bmV3IENvbnRyb2xsZXJNZXRob2QoXCJnZXRBbGxcIiwgXCJAR2V0KClcIiwgJ0BRdWVyeShcImZpbHRlclwiKSBmaWx0ZXI6IHN0cmluZycsIHRydWUsIFtcblx0XHRcdFx0XCJjb25zdCBncmVldGluZyA9IGF3YWl0IHRoaXMuc2FtcGxlLmdldEdyZWV0aW5nKCk7XCIsXG5cdFx0XHRcdFwicmV0dXJuIHsgZmlsdGVyLCBtZXNzYWdlOiBncmVldGluZyB9O1wiLFxuXHRcdFx0XSksXG5cdFx0XSxcblx0XHRbXG5cdFx0XHRcImdldE9uZVwiLFxuXHRcdFx0bmV3IENvbnRyb2xsZXJNZXRob2QoXG5cdFx0XHRcdFwiZ2V0T25lXCIsXG5cdFx0XHRcdCdAR2V0KFwiLzppZFwiKScsXG5cdFx0XHRcdCdAUGFyYW0oXCJpZFwiKSBpZDogc3RyaW5nJyxcblx0XHRcdFx0ZmFsc2UsXG5cdFx0XHRcdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IHRlbXBsYXRlIGxpdGVyYWwgaW4gZ2VuZXJhdGVkIGNvZGVcblx0XHRcdFx0W1wicmV0dXJuIHsgaWQsIG1lc3NhZ2U6IGBIZWxsbyAke2lkfSFgIH07XCJdLFxuXHRcdFx0KSxcblx0XHRdLFxuXHRcdFtcblx0XHRcdFwiY3JlYXRlXCIsXG5cdFx0XHRuZXcgQ29udHJvbGxlck1ldGhvZChcImNyZWF0ZVwiLCBcIkBQb3N0KClcIiwgXCJib2R5OiBIZWxsb0JvZHlcIiwgZmFsc2UsIFtcblx0XHRcdFx0XCJyZXR1cm4geyBtZXNzYWdlOiBib2R5Lm1lc3NhZ2UgfTtcIixcblx0XHRcdF0pLFxuXHRcdF0sXG5cdFx0W1xuXHRcdFx0XCJ1cGRhdGVcIixcblx0XHRcdG5ldyBDb250cm9sbGVyTWV0aG9kKFxuXHRcdFx0XHRcInVwZGF0ZVwiLFxuXHRcdFx0XHQnQFB1dChcIi86aWRcIiknLFxuXHRcdFx0XHQnQFBhcmFtKFwiaWRcIikgaWQ6IHN0cmluZywgYm9keTogSGVsbG9Cb2R5Jyxcblx0XHRcdFx0ZmFsc2UsXG5cdFx0XHRcdFtcInJldHVybiB7IGlkLCBtZXNzYWdlOiBib2R5Lm1lc3NhZ2UgfTtcIl0sXG5cdFx0XHQpLFxuXHRcdF0sXG5cdFx0W1xuXHRcdFx0XCJyZW1vdmVcIixcblx0XHRcdG5ldyBDb250cm9sbGVyTWV0aG9kKFwicmVtb3ZlXCIsICdARGVsZXRlKFwiLzppZFwiKScsICdAUGFyYW0oXCJpZFwiKSBpZDogc3RyaW5nJywgZmFsc2UsIFtcblx0XHRcdFx0XCJyZXR1cm4geyBpZCwgZGVsZXRlZDogdHJ1ZSB9O1wiLFxuXHRcdFx0XSksXG5cdFx0XSxcblx0XSk7XG5cblx0LyoqIFJldHJpZXZlIGEgbWV0aG9kIGJ5IG5hbWUgdG8gbXV0YXRlIGl0cyBkZWNvcmF0b3JzLiAqL1xuXHRwdWJsaWMgZ2V0TWV0aG9kKG5hbWU6IHN0cmluZyk6IENvbnRyb2xsZXJNZXRob2Qge1xuXHRcdGNvbnN0IG0gPSB0aGlzLl9tZXRob2RzLmdldChuYW1lKTtcblx0XHRpZiAobSA9PSBudWxsKSB0aHJvdyBuZXcgRXJyb3IoYE5vIG1ldGhvZCAnJHtuYW1lfScgb24gQ29udHJvbGxlclNvdXJjZUZpbGVgKTtcblx0XHRyZXR1cm4gbTtcblx0fVxuXG5cdC8qKiBBZGQgYSBjbGFzcy1sZXZlbCBkZWNvcmF0b3IgKGUuZy4gYEBBdXRob3JpemVgKS4gKi9cblx0cHVibGljIGFkZERlY29yYXRvcihkZWNvcmF0b3I6IHN0cmluZyk6IHRoaXMge1xuXHRcdHRoaXMuX2NsYXNzRGVjb3JhdG9ycy5wdXNoKGRlY29yYXRvcik7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKiogQWRkIGEgbmFtZWQgaW1wb3J0IGZyb20gYEBkZWNvaGVyZS9jb3J0ZXhgLiAqL1xuXHRwdWJsaWMgYWRkQ29ydGV4SW1wb3J0KG5hbWU6IHN0cmluZywgdHlwZU9ubHkgPSBmYWxzZSk6IHRoaXMge1xuXHRcdHRoaXMuX2NvcnRleEltcG9ydHMuYWRkKG5hbWUsIHR5cGVPbmx5KTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKiBBZGQgYSBuYW1lZCBpbXBvcnQgZnJvbSBhbnkgb3RoZXIgbW9kdWxlLiAqL1xuXHRwdWJsaWMgYWRkSW1wb3J0KG5hbWU6IHN0cmluZywgZnJvbTogc3RyaW5nLCB0eXBlT25seSA9IGZhbHNlKTogdGhpcyB7XG5cdFx0Y29uc3QgZ3JvdXAgPSB0aGlzLl9leHRyYUltcG9ydEdyb3Vwcy5nZXQoZnJvbSkgPz8gbmV3IEltcG9ydEdyb3VwKCk7XG5cdFx0Z3JvdXAuYWRkKG5hbWUsIHR5cGVPbmx5KTtcblx0XHR0aGlzLl9leHRyYUltcG9ydEdyb3Vwcy5zZXQoZnJvbSwgZ3JvdXApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqIEFkZCBhIGNvbnN0cnVjdG9yIHBhcmFtZXRlciAoZS5nLiBhbiBpbmplY3RlZCBkZXBlbmRlbmN5KS4gKi9cblx0cHVibGljIGFkZENvbnN0cnVjdG9yUGFyYW0ocGFyYW06IHN0cmluZyk6IHRoaXMge1xuXHRcdHRoaXMuX2N0b3JQYXJhbXMucHVzaChwYXJhbSk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRwdWJsaWMgZmlsZXMoKTogU291cmNlRmlsZVtdIHtcblx0XHRjb25zdCBsaW5lczogc3RyaW5nW10gPSBbXG5cdFx0XHR0aGlzLl9jb3J0ZXhJbXBvcnRzLnJlbmRlcihcIkBkZWNvaGVyZS9jb3J0ZXhcIiksXG5cdFx0XHQnaW1wb3J0IHsgU2FtcGxlU2VydmljZSB9IGZyb20gXCIuLi9zZXJ2aWNlcy9zYW1wbGUuc2VydmljZS5qc1wiOycsXG5cdFx0XTtcblxuXHRcdGZvciAoY29uc3QgW2Zyb20sIGdyb3VwXSBvZiB0aGlzLl9leHRyYUltcG9ydEdyb3Vwcykge1xuXHRcdFx0bGluZXMucHVzaChncm91cC5yZW5kZXIoZnJvbSkpO1xuXHRcdH1cblxuXHRcdGxpbmVzLnB1c2goXG5cdFx0XHRcIlwiLFxuXHRcdFx0XCJjbGFzcyBIZWxsb0JvZHkge1wiLFxuXHRcdFx0J1xcdEBGaWVsZChcImJvZHlcIiwgXCJtZXNzYWdlXCIpJyxcblx0XHRcdFwiXFx0cHVibGljIG1lc3NhZ2UhOiBzdHJpbmc7XCIsXG5cdFx0XHRcIn1cIixcblx0XHRcdFwiXCIsXG5cdFx0KTtcblxuXHRcdGZvciAoY29uc3QgZCBvZiB0aGlzLl9jbGFzc0RlY29yYXRvcnMpIHtcblx0XHRcdGxpbmVzLnB1c2goZCk7XG5cdFx0fVxuXHRcdGxpbmVzLnB1c2goJ0BDb250cm9sbGVyKHsgcHJlZml4OiBcIi9oZWxsb1wiIH0pJywgXCJleHBvcnQgY2xhc3MgSGVsbG9Db250cm9sbGVyIHtcIiwgXCJcIik7XG5cblx0XHRsaW5lcy5wdXNoKFwiXFx0cHVibGljIGNvbnN0cnVjdG9yKFwiKTtcblx0XHRmb3IgKGNvbnN0IHAgb2YgdGhpcy5fY3RvclBhcmFtcykge1xuXHRcdFx0bGluZXMucHVzaChgXFx0XFx0JHtwfSxgKTtcblx0XHR9XG5cdFx0bGluZXMucHVzaChcIlxcdCkge31cIik7XG5cdFx0bGluZXMucHVzaChcIlwiKTtcblxuXHRcdGZvciAoY29uc3QgbWV0aG9kIG9mIHRoaXMuX21ldGhvZHMudmFsdWVzKCkpIHtcblx0XHRcdGxpbmVzLnB1c2goLi4ubWV0aG9kLnJlbmRlcigpLCBcIlwiKTtcblx0XHR9XG5cblx0XHRsaW5lcy5wdXNoKFwifVwiLCBcIlwiKTtcblxuXHRcdHJldHVybiBbXG5cdFx0XHR7XG5cdFx0XHRcdGZpbGVQYXRoOiBcInNyYy9jb250cm9sbGVycy9oZWxsby5jb250cm9sbGVyLnRzXCIsXG5cdFx0XHRcdGNvbnRlbnQ6IGxpbmVzLmpvaW4oXCJcXG5cIiksXG5cdFx0XHR9LFxuXHRcdF07XG5cdH1cbn1cbiJdLCJuYW1lcyI6WyJXRUxMX0tOT1dOX0ZJTEVTIiwiSW1wb3J0R3JvdXAiLCJfdmFsdWVzIiwiX3R5cGVzIiwiYWRkIiwibmFtZSIsInR5cGVPbmx5IiwiaW5jbHVkZXMiLCJwdXNoIiwidHlwZUlkeCIsImluZGV4T2YiLCJzcGxpY2UiLCJyZW5kZXIiLCJmcm9tIiwidmFsdWVzIiwic29ydCIsInR5cGVzIiwibWFwIiwibiIsImpvaW4iLCJDb250cm9sbGVyTWV0aG9kIiwiX2V4dHJhRGVjb3JhdG9ycyIsIl9ib2R5IiwiX2lzQXN5bmMiLCJfaHR0cERlY29yYXRvciIsIl9wYXJhbXMiLCJpc0FzeW5jIiwiYm9keSIsImFkZERlY29yYXRvciIsImRlY29yYXRvciIsInNldEJvZHkiLCJzZXRBc3luYyIsImxpbmVzIiwiZCIsImFzeW5jS3ciLCJsaW5lIiwiQ29udHJvbGxlclNvdXJjZUZpbGUiLCJrZXkiLCJDT05UUk9MTEVSX1RTIiwiX2NvcnRleEltcG9ydHMiLCJfZXh0cmFJbXBvcnRHcm91cHMiLCJNYXAiLCJfY2xhc3NEZWNvcmF0b3JzIiwiX2N0b3JQYXJhbXMiLCJfbWV0aG9kcyIsImdldE1ldGhvZCIsIm0iLCJnZXQiLCJFcnJvciIsImFkZENvcnRleEltcG9ydCIsImFkZEltcG9ydCIsImdyb3VwIiwic2V0IiwiYWRkQ29uc3RydWN0b3JQYXJhbSIsInBhcmFtIiwiZmlsZXMiLCJwIiwibWV0aG9kIiwiZmlsZVBhdGgiLCJjb250ZW50Il0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxnQkFBZ0IsUUFBUSx3QkFBd0I7QUFHekQsaUZBQWlGLEdBQ2pGLE1BQU1DO0lBQ1lDLFVBQW9C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