@decohere/create 0.0.1-dev.16 → 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 (186) hide show
  1. package/commonjs/src/cli.js +26 -5
  2. package/commonjs/src/models/compose.model.js +82 -0
  3. package/commonjs/src/models/config-yaml.model.js +34 -0
  4. package/commonjs/src/models/const.js +29 -0
  5. package/commonjs/src/models/container-image.model.js +88 -0
  6. package/commonjs/src/models/dev-container.model.js +73 -0
  7. package/commonjs/src/models/env-file.model.js +33 -0
  8. package/commonjs/src/models/gitignore.model.js +32 -0
  9. package/commonjs/src/models/launch-json.model.js +52 -0
  10. package/commonjs/src/models/package-json.model.js +64 -0
  11. package/commonjs/src/models/project.model.js +126 -0
  12. package/commonjs/src/models/source-file.js +6 -0
  13. package/commonjs/src/models/tsconfig.model.js +34 -0
  14. package/commonjs/src/models/vscode-settings.model.js +31 -0
  15. package/commonjs/src/services/scaffold.service.js +62 -0
  16. package/commonjs/src/webapi/create-api.js +169 -0
  17. package/commonjs/src/webapi/features/auth.feature.js +166 -0
  18. package/commonjs/src/webapi/features/auth0-cli.js +151 -0
  19. package/commonjs/src/webapi/features/database.feature.js +151 -0
  20. package/commonjs/src/webapi/features/finalize.feature.js +46 -0
  21. package/commonjs/src/webapi/features/postman.feature.js +309 -0
  22. package/commonjs/src/webapi/models/api-package-json.model.js +57 -0
  23. package/commonjs/src/webapi/models/auth-config.model.js +23 -0
  24. package/commonjs/src/webapi/models/controller-source-file.model.js +180 -0
  25. package/commonjs/src/webapi/models/main-source-file.model.js +132 -0
  26. package/commonjs/src/webapi/models/sample-files.model.js +60 -0
  27. package/commonjs/v1/cli.js +15 -0
  28. package/commonjs/v1/domain/class-model.js +106 -0
  29. package/commonjs/v1/domain/compose.model.js +74 -0
  30. package/commonjs/v1/domain/context.js +53 -0
  31. package/commonjs/v1/domain/devcontainer.model.js +116 -0
  32. package/commonjs/v1/domain/dockerfile.model.js +62 -0
  33. package/commonjs/v1/domain/feature.js +19 -0
  34. package/commonjs/v1/domain/import-map.js +74 -0
  35. package/commonjs/v1/domain/index.js +68 -0
  36. package/commonjs/v1/domain/prompt.js +45 -0
  37. package/commonjs/v1/domain/workflow.js +37 -0
  38. package/commonjs/v1/features/api-core/feature.js +103 -0
  39. package/commonjs/v1/features/api-core/hello-controller.model.js +100 -0
  40. package/commonjs/v1/features/api-core/main-ts.model.js +85 -0
  41. package/commonjs/v1/features/api-core/scaffold-files.template.js +158 -0
  42. package/commonjs/v1/features/auth0/auth0-cli.js +151 -0
  43. package/commonjs/v1/features/auth0/feature.js +187 -0
  44. package/commonjs/v1/features/auth0/models.js +14 -0
  45. package/commonjs/v1/features/auth0/prod-config.template.js +19 -0
  46. package/commonjs/v1/features/cli-core/feature.js +37 -0
  47. package/commonjs/v1/features/cli-core/scaffold-files.template.js +103 -0
  48. package/commonjs/v1/features/devcontainer/feature.js +38 -0
  49. package/commonjs/v1/features/finalize/feature.js +48 -0
  50. package/commonjs/v1/features/postgresql/feature.js +81 -0
  51. package/commonjs/v1/features/postgresql/models.js +14 -0
  52. package/commonjs/v1/features/postman/collection.template.js +80 -0
  53. package/commonjs/v1/features/postman/environment.template.js +24 -0
  54. package/commonjs/v1/features/postman/feature.js +192 -0
  55. package/commonjs/v1/features/typeorm/feature.js +66 -0
  56. package/commonjs/v1/features/typeorm/scaffold-files.template.js +80 -0
  57. package/commonjs/v1/scaffold.js +50 -0
  58. package/commonjs/v1/version.js +32 -0
  59. package/commonjs/v1/workflows/api.js +29 -0
  60. package/commonjs/v1/workflows/cli.js +19 -0
  61. package/es6/src/cli.js +26 -5
  62. package/es6/src/models/compose.model.js +77 -0
  63. package/es6/src/models/config-yaml.model.js +30 -0
  64. package/es6/src/models/const.js +19 -0
  65. package/es6/src/models/container-image.model.js +84 -0
  66. package/es6/src/models/dev-container.model.js +68 -0
  67. package/es6/src/models/env-file.model.js +29 -0
  68. package/es6/src/models/gitignore.model.js +22 -0
  69. package/es6/src/models/launch-json.model.js +42 -0
  70. package/es6/src/models/package-json.model.js +60 -0
  71. package/es6/src/models/project.model.js +111 -0
  72. package/es6/src/models/source-file.js +3 -0
  73. package/es6/src/models/tsconfig.model.js +24 -0
  74. package/es6/src/models/vscode-settings.model.js +21 -0
  75. package/es6/src/services/scaffold.service.js +52 -0
  76. package/es6/src/webapi/create-api.js +151 -0
  77. package/es6/src/webapi/features/auth.feature.js +115 -0
  78. package/es6/src/webapi/features/auth0-cli.js +116 -0
  79. package/es6/src/webapi/features/database.feature.js +141 -0
  80. package/es6/src/webapi/features/finalize.feature.js +36 -0
  81. package/es6/src/webapi/features/postman.feature.js +258 -0
  82. package/es6/src/webapi/models/api-package-json.model.js +52 -0
  83. package/es6/src/webapi/models/auth-config.model.js +19 -0
  84. package/es6/src/webapi/models/controller-source-file.model.js +171 -0
  85. package/es6/src/webapi/models/main-source-file.model.js +128 -0
  86. package/es6/src/webapi/models/sample-files.model.js +42 -0
  87. package/es6/v1/cli.js +11 -0
  88. package/es6/v1/domain/class-model.js +104 -0
  89. package/es6/v1/domain/compose.model.js +61 -0
  90. package/es6/v1/domain/context.js +37 -0
  91. package/es6/v1/domain/devcontainer.model.js +104 -0
  92. package/es6/v1/domain/dockerfile.model.js +52 -0
  93. package/es6/v1/domain/feature.js +9 -0
  94. package/es6/v1/domain/import-map.js +64 -0
  95. package/es6/v1/domain/index.js +11 -0
  96. package/es6/v1/domain/prompt.js +27 -0
  97. package/es6/v1/domain/workflow.js +24 -0
  98. package/es6/v1/features/api-core/feature.js +93 -0
  99. package/es6/v1/features/api-core/hello-controller.model.js +96 -0
  100. package/es6/v1/features/api-core/main-ts.model.js +74 -0
  101. package/es6/v1/features/api-core/scaffold-files.template.js +116 -0
  102. package/es6/v1/features/auth0/auth0-cli.js +116 -0
  103. package/es6/v1/features/auth0/feature.js +136 -0
  104. package/es6/v1/features/auth0/models.js +4 -0
  105. package/es6/v1/features/auth0/prod-config.template.js +9 -0
  106. package/es6/v1/features/cli-core/feature.js +27 -0
  107. package/es6/v1/features/cli-core/scaffold-files.template.js +73 -0
  108. package/es6/v1/features/devcontainer/feature.js +28 -0
  109. package/es6/v1/features/finalize/feature.js +38 -0
  110. package/es6/v1/features/postgresql/feature.js +71 -0
  111. package/es6/v1/features/postgresql/models.js +4 -0
  112. package/es6/v1/features/postman/collection.template.js +70 -0
  113. package/es6/v1/features/postman/environment.template.js +14 -0
  114. package/es6/v1/features/postman/feature.js +141 -0
  115. package/es6/v1/features/typeorm/feature.js +56 -0
  116. package/es6/v1/features/typeorm/scaffold-files.template.js +56 -0
  117. package/es6/v1/scaffold.js +40 -0
  118. package/es6/v1/version.js +22 -0
  119. package/es6/v1/workflows/api.js +25 -0
  120. package/es6/v1/workflows/cli.js +9 -0
  121. package/package.json +2 -2
  122. package/types/src/models/compose.model.d.ts +32 -0
  123. package/types/src/models/config-yaml.model.d.ts +16 -0
  124. package/types/src/models/const.d.ts +17 -0
  125. package/types/src/models/container-image.model.d.ts +15 -0
  126. package/types/src/models/dev-container.model.d.ts +21 -0
  127. package/types/src/models/env-file.model.d.ts +14 -0
  128. package/types/src/models/gitignore.model.d.ts +6 -0
  129. package/types/src/models/launch-json.model.d.ts +5 -0
  130. package/types/src/models/package-json.model.d.ts +18 -0
  131. package/types/src/models/project.model.d.ts +55 -0
  132. package/types/src/models/source-file.d.ts +11 -0
  133. package/types/src/models/tsconfig.model.d.ts +5 -0
  134. package/types/src/models/vscode-settings.model.d.ts +7 -0
  135. package/types/src/services/scaffold.service.d.ts +22 -0
  136. package/types/src/webapi/create-api.d.ts +7 -0
  137. package/types/src/webapi/features/auth.feature.d.ts +7 -0
  138. package/types/src/webapi/features/auth0-cli.d.ts +22 -0
  139. package/types/src/webapi/features/database.feature.d.ts +5 -0
  140. package/types/src/webapi/features/finalize.feature.d.ts +2 -0
  141. package/types/src/webapi/features/postman.feature.d.ts +7 -0
  142. package/types/src/webapi/models/api-package-json.model.d.ts +17 -0
  143. package/types/src/webapi/models/auth-config.model.d.ts +18 -0
  144. package/types/src/webapi/models/controller-source-file.model.d.ts +42 -0
  145. package/types/src/webapi/models/main-source-file.model.d.ts +36 -0
  146. package/types/src/webapi/models/sample-files.model.d.ts +7 -0
  147. package/types/v1/cli.d.ts +2 -0
  148. package/types/v1/domain/class-model.d.ts +70 -0
  149. package/types/v1/domain/compose.model.d.ts +25 -0
  150. package/types/v1/domain/context.d.ts +36 -0
  151. package/types/v1/domain/devcontainer.model.d.ts +35 -0
  152. package/types/v1/domain/dockerfile.model.d.ts +11 -0
  153. package/types/v1/domain/feature.d.ts +29 -0
  154. package/types/v1/domain/import-map.d.ts +24 -0
  155. package/types/v1/domain/index.d.ts +12 -0
  156. package/types/v1/domain/prompt.d.ts +2 -0
  157. package/types/v1/domain/workflow.d.ts +14 -0
  158. package/types/v1/features/api-core/feature.d.ts +2 -0
  159. package/types/v1/features/api-core/hello-controller.model.d.ts +9 -0
  160. package/types/v1/features/api-core/main-ts.model.d.ts +31 -0
  161. package/types/v1/features/api-core/scaffold-files.template.d.ts +10 -0
  162. package/types/v1/features/auth0/auth0-cli.d.ts +22 -0
  163. package/types/v1/features/auth0/feature.d.ts +2 -0
  164. package/types/v1/features/auth0/models.d.ts +5 -0
  165. package/types/v1/features/auth0/prod-config.template.d.ts +1 -0
  166. package/types/v1/features/cli-core/feature.d.ts +2 -0
  167. package/types/v1/features/cli-core/scaffold-files.template.d.ts +6 -0
  168. package/types/v1/features/devcontainer/feature.d.ts +2 -0
  169. package/types/v1/features/finalize/feature.d.ts +2 -0
  170. package/types/v1/features/postgresql/feature.d.ts +2 -0
  171. package/types/v1/features/postgresql/models.d.ts +6 -0
  172. package/types/v1/features/postman/collection.template.d.ts +1 -0
  173. package/types/v1/features/postman/environment.template.d.ts +6 -0
  174. package/types/v1/features/postman/feature.d.ts +2 -0
  175. package/types/v1/features/typeorm/feature.d.ts +2 -0
  176. package/types/v1/features/typeorm/scaffold-files.template.d.ts +9 -0
  177. package/types/v1/scaffold.d.ts +3 -0
  178. package/types/v1/version.d.ts +2 -0
  179. package/types/v1/workflows/api.d.ts +8 -0
  180. package/types/v1/workflows/cli.d.ts +1 -0
  181. package/commonjs/src/scaffold.js +0 -89
  182. package/commonjs/src/templates.js +0 -305
  183. package/es6/src/scaffold.js +0 -79
  184. package/es6/src/templates.js +0 -245
  185. package/types/src/scaffold.d.ts +0 -6
  186. package/types/src/templates.d.ts +0 -20
@@ -0,0 +1,28 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { COMPOSE_KEY } from "../../domain/compose.model.js";
4
+ import { DEVCONTAINER_KEY } from "../../domain/devcontainer.model.js";
5
+ async function render(ctx) {
6
+ const model = ctx.models.get(DEVCONTAINER_KEY);
7
+ if (!model) return ctx;
8
+ const dir = join(ctx.targetDir, ".devcontainer");
9
+ await mkdir(dir, {
10
+ recursive: true
11
+ });
12
+ await writeFile(join(dir, "devcontainer.json"), model.render());
13
+ const compose = ctx.models.get(COMPOSE_KEY);
14
+ if (compose) {
15
+ await writeFile(join(dir, "docker-compose.yml"), compose.render());
16
+ const dockerfile = model.dockerfile;
17
+ if (dockerfile) {
18
+ await writeFile(join(dir, "Dockerfile"), dockerfile.render());
19
+ }
20
+ }
21
+ return ctx;
22
+ }
23
+ export const devcontainerFeature = {
24
+ name: "devcontainer",
25
+ render
26
+ };
27
+
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9kZXZjb250YWluZXIvZmVhdHVyZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBta2Rpciwgd3JpdGVGaWxlIH0gZnJvbSBcIm5vZGU6ZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBDT01QT1NFX0tFWSB9IGZyb20gXCIuLi8uLi9kb21haW4vY29tcG9zZS5tb2RlbC5qc1wiO1xuaW1wb3J0IHsgREVWQ09OVEFJTkVSX0tFWSB9IGZyb20gXCIuLi8uLi9kb21haW4vZGV2Y29udGFpbmVyLm1vZGVsLmpzXCI7XG5pbXBvcnQgdHlwZSB7IEZlYXR1cmUsIFNjYWZmb2xkQ29udGV4dCB9IGZyb20gXCIuLi8uLi9kb21haW4vaW5kZXguanNcIjtcblxuYXN5bmMgZnVuY3Rpb24gcmVuZGVyKGN0eDogU2NhZmZvbGRDb250ZXh0KTogUHJvbWlzZTxTY2FmZm9sZENvbnRleHQ+IHtcblx0Y29uc3QgbW9kZWwgPSBjdHgubW9kZWxzLmdldChERVZDT05UQUlORVJfS0VZKTtcblx0aWYgKCFtb2RlbCkgcmV0dXJuIGN0eDtcblxuXHRjb25zdCBkaXIgPSBqb2luKGN0eC50YXJnZXREaXIsIFwiLmRldmNvbnRhaW5lclwiKTtcblx0YXdhaXQgbWtkaXIoZGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblx0YXdhaXQgd3JpdGVGaWxlKGpvaW4oZGlyLCBcImRldmNvbnRhaW5lci5qc29uXCIpLCBtb2RlbC5yZW5kZXIoKSk7XG5cblx0Y29uc3QgY29tcG9zZSA9IGN0eC5tb2RlbHMuZ2V0KENPTVBPU0VfS0VZKTtcblx0aWYgKGNvbXBvc2UpIHtcblx0XHRhd2FpdCB3cml0ZUZpbGUoam9pbihkaXIsIFwiZG9ja2VyLWNvbXBvc2UueW1sXCIpLCBjb21wb3NlLnJlbmRlcigpKTtcblx0XHRjb25zdCBkb2NrZXJmaWxlID0gbW9kZWwuZG9ja2VyZmlsZTtcblx0XHRpZiAoZG9ja2VyZmlsZSkge1xuXHRcdFx0YXdhaXQgd3JpdGVGaWxlKGpvaW4oZGlyLCBcIkRvY2tlcmZpbGVcIiksIGRvY2tlcmZpbGUucmVuZGVyKCkpO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBjdHg7XG59XG5cbmV4cG9ydCBjb25zdCBkZXZjb250YWluZXJGZWF0dXJlOiBGZWF0dXJlID0ge1xuXHRuYW1lOiBcImRldmNvbnRhaW5lclwiLFxuXHRyZW5kZXIsXG59O1xuIl0sIm5hbWVzIjpbIm1rZGlyIiwid3JpdGVGaWxlIiwiam9pbiIsIkNPTVBPU0VfS0VZIiwiREVWQ09OVEFJTkVSX0tFWSIsInJlbmRlciIsImN0eCIsIm1vZGVsIiwibW9kZWxzIiwiZ2V0IiwiZGlyIiwidGFyZ2V0RGlyIiwicmVjdXJzaXZlIiwiY29tcG9zZSIsImRvY2tlcmZpbGUiLCJkZXZjb250YWluZXJGZWF0dXJlIiwibmFtZSJdLCJtYXBwaW5ncyI6IkFBQUEsU0FBU0EsS0FBSyxFQUFFQyxTQUFTLFFBQVEsbUJBQW1CO0FBQ3BELFNBQVNDLElBQUksUUFBUSxZQUFZO0FBQ2pDLFNBQVNDLFdBQVcsUUFBUSxnQ0FBZ0M7QUFDNUQsU0FBU0MsZ0JBQWdCLFFBQVEscUNBQXFDO0FBR3RFLGVBQWVDLE9BQU9DLEdBQW9CO0lBQ3pDLE1BQU1DLFFBQVFELElBQUlFLE1BQU0sQ0FBQ0MsR0FBRyxDQUFDTDtJQUM3QixJQUFJLENBQUNHLE9BQU8sT0FBT0Q7SUFFbkIsTUFBTUksTUFBTVIsS0FBS0ksSUFBSUssU0FBUyxFQUFFO0lBQ2hDLE1BQU1YLE1BQU1VLEtBQUs7UUFBRUUsV0FBVztJQUFLO0lBQ25DLE1BQU1YLFVBQVVDLEtBQUtRLEtBQUssc0JBQXNCSCxNQUFNRixNQUFNO0lBRTVELE1BQU1RLFVBQVVQLElBQUlFLE1BQU0sQ0FBQ0MsR0FBRyxDQUFDTjtJQUMvQixJQUFJVSxTQUFTO1FBQ1osTUFBTVosVUFBVUMsS0FBS1EsS0FBSyx1QkFBdUJHLFFBQVFSLE1BQU07UUFDL0QsTUFBTVMsYUFBYVAsTUFBTU8sVUFBVTtRQUNuQyxJQUFJQSxZQUFZO1lBQ2YsTUFBTWIsVUFBVUMsS0FBS1EsS0FBSyxlQUFlSSxXQUFXVCxNQUFNO1FBQzNEO0lBQ0Q7SUFFQSxPQUFPQztBQUNSO0FBRUEsT0FBTyxNQUFNUyxzQkFBK0I7SUFDM0NDLE1BQU07SUFDTlg7QUFDRCxFQUFFIn0=
@@ -0,0 +1,38 @@
1
+ import { basename } from "node:path";
2
+ import { detectPackageManager, promptForPackageManager } from "@decohere/nexus/interop";
3
+ import { ask } from "../../domain/index.js";
4
+ async function finalize(ctx) {
5
+ let pm = detectPackageManager(ctx.targetDir);
6
+ if (pm == null) {
7
+ pm = await promptForPackageManager();
8
+ }
9
+ let shouldInstall;
10
+ if (ctx.opts.yes) {
11
+ shouldInstall = true;
12
+ } else {
13
+ const answer = await ask("\nInstall dependencies now? [yes/no] (yes): ", "yes");
14
+ shouldInstall = answer.toLowerCase() !== "no";
15
+ }
16
+ if (shouldInstall) {
17
+ console.log(`\nScaffolded ${ctx.projectName}. Installing dependencies...\n`);
18
+ await pm.install({
19
+ cwd: ctx.targetDir
20
+ });
21
+ }
22
+ console.log(`\nDone! ${shouldInstall ? "Next" : "To get started:"} steps:\n`);
23
+ if (basename(ctx.targetDir) !== ctx.targetDir) {
24
+ console.log(` cd ${ctx.projectName}`);
25
+ }
26
+ if (!shouldInstall) {
27
+ console.log(` ${pm.name} install`);
28
+ }
29
+ console.log(" pnpm build # forge build");
30
+ console.log(" pnpm dev # flux serve\n");
31
+ return ctx;
32
+ }
33
+ export const finalizeFeature = {
34
+ name: "finalize",
35
+ finalize
36
+ };
37
+
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9maW5hbGl6ZS9mZWF0dXJlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGJhc2VuYW1lIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgZGV0ZWN0UGFja2FnZU1hbmFnZXIsIHByb21wdEZvclBhY2thZ2VNYW5hZ2VyIH0gZnJvbSBcIkBkZWNvaGVyZS9uZXh1cy9pbnRlcm9wXCI7XG5pbXBvcnQgeyBhc2ssIHR5cGUgRmVhdHVyZSwgdHlwZSBTY2FmZm9sZENvbnRleHQgfSBmcm9tIFwiLi4vLi4vZG9tYWluL2luZGV4LmpzXCI7XG5cbmFzeW5jIGZ1bmN0aW9uIGZpbmFsaXplKGN0eDogU2NhZmZvbGRDb250ZXh0KTogUHJvbWlzZTxTY2FmZm9sZENvbnRleHQ+IHtcblx0bGV0IHBtID0gZGV0ZWN0UGFja2FnZU1hbmFnZXIoY3R4LnRhcmdldERpcik7XG5cdGlmIChwbSA9PSBudWxsKSB7XG5cdFx0cG0gPSBhd2FpdCBwcm9tcHRGb3JQYWNrYWdlTWFuYWdlcigpO1xuXHR9XG5cblx0bGV0IHNob3VsZEluc3RhbGw6IGJvb2xlYW47XG5cdGlmIChjdHgub3B0cy55ZXMpIHtcblx0XHRzaG91bGRJbnN0YWxsID0gdHJ1ZTtcblx0fSBlbHNlIHtcblx0XHRjb25zdCBhbnN3ZXIgPSBhd2FpdCBhc2soXCJcXG5JbnN0YWxsIGRlcGVuZGVuY2llcyBub3c/IFt5ZXMvbm9dICh5ZXMpOiBcIiwgXCJ5ZXNcIik7XG5cdFx0c2hvdWxkSW5zdGFsbCA9IGFuc3dlci50b0xvd2VyQ2FzZSgpICE9PSBcIm5vXCI7XG5cdH1cblxuXHRpZiAoc2hvdWxkSW5zdGFsbCkge1xuXHRcdGNvbnNvbGUubG9nKGBcXG5TY2FmZm9sZGVkICR7Y3R4LnByb2plY3ROYW1lfS4gSW5zdGFsbGluZyBkZXBlbmRlbmNpZXMuLi5cXG5gKTtcblx0XHRhd2FpdCBwbS5pbnN0YWxsKHsgY3dkOiBjdHgudGFyZ2V0RGlyIH0pO1xuXHR9XG5cblx0Y29uc29sZS5sb2coYFxcbkRvbmUhICR7c2hvdWxkSW5zdGFsbCA/IFwiTmV4dFwiIDogXCJUbyBnZXQgc3RhcnRlZDpcIn0gc3RlcHM6XFxuYCk7XG5cdGlmIChiYXNlbmFtZShjdHgudGFyZ2V0RGlyKSAhPT0gY3R4LnRhcmdldERpcikge1xuXHRcdGNvbnNvbGUubG9nKGAgIGNkICR7Y3R4LnByb2plY3ROYW1lfWApO1xuXHR9XG5cdGlmICghc2hvdWxkSW5zdGFsbCkge1xuXHRcdGNvbnNvbGUubG9nKGAgICR7cG0ubmFtZX0gaW5zdGFsbGApO1xuXHR9XG5cdGNvbnNvbGUubG9nKFwiICBwbnBtIGJ1aWxkICAgICAjIGZvcmdlIGJ1aWxkXCIpO1xuXHRjb25zb2xlLmxvZyhcIiAgcG5wbSBkZXYgICAgICAgIyBmbHV4IHNlcnZlXFxuXCIpO1xuXHRyZXR1cm4gY3R4O1xufVxuXG5leHBvcnQgY29uc3QgZmluYWxpemVGZWF0dXJlOiBGZWF0dXJlID0ge1xuXHRuYW1lOiBcImZpbmFsaXplXCIsXG5cdGZpbmFsaXplLFxufTtcbiJdLCJuYW1lcyI6WyJiYXNlbmFtZSIsImRldGVjdFBhY2thZ2VNYW5hZ2VyIiwicHJvbXB0Rm9yUGFja2FnZU1hbmFnZXIiLCJhc2siLCJmaW5hbGl6ZSIsImN0eCIsInBtIiwidGFyZ2V0RGlyIiwic2hvdWxkSW5zdGFsbCIsIm9wdHMiLCJ5ZXMiLCJhbnN3ZXIiLCJ0b0xvd2VyQ2FzZSIsImNvbnNvbGUiLCJsb2ciLCJwcm9qZWN0TmFtZSIsImluc3RhbGwiLCJjd2QiLCJuYW1lIiwiZmluYWxpemVGZWF0dXJlIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxRQUFRLFFBQVEsWUFBWTtBQUNyQyxTQUFTQyxvQkFBb0IsRUFBRUMsdUJBQXVCLFFBQVEsMEJBQTBCO0FBQ3hGLFNBQVNDLEdBQUcsUUFBNEMsd0JBQXdCO0FBRWhGLGVBQWVDLFNBQVNDLEdBQW9CO0lBQzNDLElBQUlDLEtBQUtMLHFCQUFxQkksSUFBSUUsU0FBUztJQUMzQyxJQUFJRCxNQUFNLE1BQU07UUFDZkEsS0FBSyxNQUFNSjtJQUNaO0lBRUEsSUFBSU07SUFDSixJQUFJSCxJQUFJSSxJQUFJLENBQUNDLEdBQUcsRUFBRTtRQUNqQkYsZ0JBQWdCO0lBQ2pCLE9BQU87UUFDTixNQUFNRyxTQUFTLE1BQU1SLElBQUksZ0RBQWdEO1FBQ3pFSyxnQkFBZ0JHLE9BQU9DLFdBQVcsT0FBTztJQUMxQztJQUVBLElBQUlKLGVBQWU7UUFDbEJLLFFBQVFDLEdBQUcsQ0FBQyxDQUFDLGFBQWEsRUFBRVQsSUFBSVUsV0FBVyxDQUFDLDhCQUE4QixDQUFDO1FBQzNFLE1BQU1ULEdBQUdVLE9BQU8sQ0FBQztZQUFFQyxLQUFLWixJQUFJRSxTQUFTO1FBQUM7SUFDdkM7SUFFQU0sUUFBUUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFTixnQkFBZ0IsU0FBUyxrQkFBa0IsU0FBUyxDQUFDO0lBQzVFLElBQUlSLFNBQVNLLElBQUlFLFNBQVMsTUFBTUYsSUFBSUUsU0FBUyxFQUFFO1FBQzlDTSxRQUFRQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUVULElBQUlVLFdBQVcsRUFBRTtJQUN0QztJQUNBLElBQUksQ0FBQ1AsZUFBZTtRQUNuQkssUUFBUUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFUixHQUFHWSxJQUFJLENBQUMsUUFBUSxDQUFDO0lBQ25DO0lBQ0FMLFFBQVFDLEdBQUcsQ0FBQztJQUNaRCxRQUFRQyxHQUFHLENBQUM7SUFDWixPQUFPVDtBQUNSO0FBRUEsT0FBTyxNQUFNYyxrQkFBMkI7SUFDdkNELE1BQU07SUFDTmQ7QUFDRCxFQUFFIn0=
@@ -0,0 +1,71 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { COMPOSE_KEY, ComposeModel } from "../../domain/compose.model.js";
5
+ import { DEVCONTAINER_KEY } from "../../domain/devcontainer.model.js";
6
+ import { POSTGRES_CREDS_KEY } from "./models.js";
7
+ const enabled = (ctx)=>ctx.opts.database === "typeorm";
8
+ async function configure(ctx) {
9
+ const devcontainer = ctx.models.get(DEVCONTAINER_KEY);
10
+ const nodeModulesVolume = `${ctx.projectName}-node-modules`;
11
+ const db = `${ctx.projectName}_dev`;
12
+ const user = "postgres";
13
+ const password = randomBytes(16).toString("hex");
14
+ const compose = new ComposeModel().addService("devcontainer", {
15
+ build: ".",
16
+ volumes: [
17
+ `\${HOME}/.npm/${ctx.projectName}:/home/node/.npm`,
18
+ `${nodeModulesVolume}:/workspace/node_modules`
19
+ ],
20
+ environment: {
21
+ NPM_CONFIG_USERCONFIG: "/home/node/.npm/.npmrc"
22
+ },
23
+ command: "sleep infinity"
24
+ }).addService("postgres", {
25
+ image: "postgres:16",
26
+ restart: "unless-stopped",
27
+ environment: {
28
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Docker Compose reads these from .env
29
+ POSTGRES_DB: "${POSTGRES_DB}",
30
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Docker Compose reads these from .env
31
+ POSTGRES_USER: "${POSTGRES_USER}",
32
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Docker Compose reads these from .env
33
+ POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}"
34
+ },
35
+ ports: [
36
+ "5432:5432"
37
+ ],
38
+ volumes: [
39
+ "postgres-data:/var/lib/postgresql/data"
40
+ ]
41
+ }).addVolume(nodeModulesVolume).addVolume("postgres-data");
42
+ devcontainer?.useCompose();
43
+ const creds = {
44
+ db,
45
+ user,
46
+ password
47
+ };
48
+ return {
49
+ ...ctx,
50
+ models: ctx.models.set(COMPOSE_KEY, compose).set(POSTGRES_CREDS_KEY, creds)
51
+ };
52
+ }
53
+ async function render(ctx) {
54
+ const creds = ctx.models.get(POSTGRES_CREDS_KEY);
55
+ if (!creds) return ctx;
56
+ const devcontainerDir = join(ctx.targetDir, ".devcontainer");
57
+ await mkdir(devcontainerDir, {
58
+ recursive: true
59
+ });
60
+ const envContent = `POSTGRES_DB=${creds.db}\nPOSTGRES_USER=${creds.user}\nPOSTGRES_PASSWORD=${creds.password}\n`;
61
+ await writeFile(join(devcontainerDir, ".env"), envContent);
62
+ return ctx;
63
+ }
64
+ export const postgresqlFeature = {
65
+ name: "postgresql",
66
+ enabled,
67
+ configure,
68
+ render
69
+ };
70
+
71
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9wb3N0Z3Jlc3FsL2ZlYXR1cmUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmFuZG9tQnl0ZXMgfSBmcm9tIFwibm9kZTpjcnlwdG9cIjtcbmltcG9ydCB7IG1rZGlyLCB3cml0ZUZpbGUgfSBmcm9tIFwibm9kZTpmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IENPTVBPU0VfS0VZLCBDb21wb3NlTW9kZWwgfSBmcm9tIFwiLi4vLi4vZG9tYWluL2NvbXBvc2UubW9kZWwuanNcIjtcbmltcG9ydCB7IERFVkNPTlRBSU5FUl9LRVkgfSBmcm9tIFwiLi4vLi4vZG9tYWluL2RldmNvbnRhaW5lci5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBGZWF0dXJlLCBTY2FmZm9sZENvbnRleHQgfSBmcm9tIFwiLi4vLi4vZG9tYWluL2luZGV4LmpzXCI7XG5pbXBvcnQgeyBQT1NUR1JFU19DUkVEU19LRVkgfSBmcm9tIFwiLi9tb2RlbHMuanNcIjtcblxuY29uc3QgZW5hYmxlZCA9IChjdHg6IFNjYWZmb2xkQ29udGV4dCkgPT4gY3R4Lm9wdHMuZGF0YWJhc2UgPT09IFwidHlwZW9ybVwiO1xuXG5hc3luYyBmdW5jdGlvbiBjb25maWd1cmUoY3R4OiBTY2FmZm9sZENvbnRleHQpOiBQcm9taXNlPFNjYWZmb2xkQ29udGV4dD4ge1xuXHRjb25zdCBkZXZjb250YWluZXIgPSBjdHgubW9kZWxzLmdldChERVZDT05UQUlORVJfS0VZKTtcblx0Y29uc3Qgbm9kZU1vZHVsZXNWb2x1bWUgPSBgJHtjdHgucHJvamVjdE5hbWV9LW5vZGUtbW9kdWxlc2A7XG5cblx0Y29uc3QgZGIgPSBgJHtjdHgucHJvamVjdE5hbWV9X2RldmA7XG5cdGNvbnN0IHVzZXIgPSBcInBvc3RncmVzXCI7XG5cdGNvbnN0IHBhc3N3b3JkID0gcmFuZG9tQnl0ZXMoMTYpLnRvU3RyaW5nKFwiaGV4XCIpO1xuXG5cdGNvbnN0IGNvbXBvc2UgPSBuZXcgQ29tcG9zZU1vZGVsKClcblx0XHQuYWRkU2VydmljZShcImRldmNvbnRhaW5lclwiLCB7XG5cdFx0XHRidWlsZDogXCIuXCIsXG5cdFx0XHR2b2x1bWVzOiBbXG5cdFx0XHRcdGBcXCR7SE9NRX0vLm5wbS8ke2N0eC5wcm9qZWN0TmFtZX06L2hvbWUvbm9kZS8ubnBtYCxcblx0XHRcdFx0YCR7bm9kZU1vZHVsZXNWb2x1bWV9Oi93b3Jrc3BhY2Uvbm9kZV9tb2R1bGVzYCxcblx0XHRcdF0sXG5cdFx0XHRlbnZpcm9ubWVudDoge1xuXHRcdFx0XHROUE1fQ09ORklHX1VTRVJDT05GSUc6IFwiL2hvbWUvbm9kZS8ubnBtLy5ucG1yY1wiLFxuXHRcdFx0fSxcblx0XHRcdGNvbW1hbmQ6IFwic2xlZXAgaW5maW5pdHlcIixcblx0XHR9KVxuXHRcdC5hZGRTZXJ2aWNlKFwicG9zdGdyZXNcIiwge1xuXHRcdFx0aW1hZ2U6IFwicG9zdGdyZXM6MTZcIixcblx0XHRcdHJlc3RhcnQ6IFwidW5sZXNzLXN0b3BwZWRcIixcblx0XHRcdGVudmlyb25tZW50OiB7XG5cdFx0XHRcdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IERvY2tlciBDb21wb3NlIHJlYWRzIHRoZXNlIGZyb20gLmVudlxuXHRcdFx0XHRQT1NUR1JFU19EQjogXCIke1BPU1RHUkVTX0RCfVwiLFxuXHRcdFx0XHQvLyBiaW9tZS1pZ25vcmUgbGludC9zdXNwaWNpb3VzL25vVGVtcGxhdGVDdXJseUluU3RyaW5nOiBEb2NrZXIgQ29tcG9zZSByZWFkcyB0aGVzZSBmcm9tIC5lbnZcblx0XHRcdFx0UE9TVEdSRVNfVVNFUjogXCIke1BPU1RHUkVTX1VTRVJ9XCIsXG5cdFx0XHRcdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9UZW1wbGF0ZUN1cmx5SW5TdHJpbmc6IERvY2tlciBDb21wb3NlIHJlYWRzIHRoZXNlIGZyb20gLmVudlxuXHRcdFx0XHRQT1NUR1JFU19QQVNTV09SRDogXCIke1BPU1RHUkVTX1BBU1NXT1JEfVwiLFxuXHRcdFx0fSxcblx0XHRcdHBvcnRzOiBbXCI1NDMyOjU0MzJcIl0sXG5cdFx0XHR2b2x1bWVzOiBbXCJwb3N0Z3Jlcy1kYXRhOi92YXIvbGliL3Bvc3RncmVzcWwvZGF0YVwiXSxcblx0XHR9KVxuXHRcdC5hZGRWb2x1bWUobm9kZU1vZHVsZXNWb2x1bWUpXG5cdFx0LmFkZFZvbHVtZShcInBvc3RncmVzLWRhdGFcIik7XG5cblx0ZGV2Y29udGFpbmVyPy51c2VDb21wb3NlKCk7XG5cblx0Y29uc3QgY3JlZHMgPSB7IGRiLCB1c2VyLCBwYXNzd29yZCB9O1xuXHRyZXR1cm4ge1xuXHRcdC4uLmN0eCxcblx0XHRtb2RlbHM6IGN0eC5tb2RlbHMuc2V0KENPTVBPU0VfS0VZLCBjb21wb3NlKS5zZXQoUE9TVEdSRVNfQ1JFRFNfS0VZLCBjcmVkcyksXG5cdH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlbmRlcihjdHg6IFNjYWZmb2xkQ29udGV4dCk6IFByb21pc2U8U2NhZmZvbGRDb250ZXh0PiB7XG5cdGNvbnN0IGNyZWRzID0gY3R4Lm1vZGVscy5nZXQoUE9TVEdSRVNfQ1JFRFNfS0VZKTtcblx0aWYgKCFjcmVkcykgcmV0dXJuIGN0eDtcblxuXHRjb25zdCBkZXZjb250YWluZXJEaXIgPSBqb2luKGN0eC50YXJnZXREaXIsIFwiLmRldmNvbnRhaW5lclwiKTtcblx0YXdhaXQgbWtkaXIoZGV2Y29udGFpbmVyRGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblx0Y29uc3QgZW52Q29udGVudCA9IGBQT1NUR1JFU19EQj0ke2NyZWRzLmRifVxcblBPU1RHUkVTX1VTRVI9JHtjcmVkcy51c2VyfVxcblBPU1RHUkVTX1BBU1NXT1JEPSR7Y3JlZHMucGFzc3dvcmR9XFxuYDtcblx0YXdhaXQgd3JpdGVGaWxlKGpvaW4oZGV2Y29udGFpbmVyRGlyLCBcIi5lbnZcIiksIGVudkNvbnRlbnQpO1xuXG5cdHJldHVybiBjdHg7XG59XG5cbmV4cG9ydCBjb25zdCBwb3N0Z3Jlc3FsRmVhdHVyZTogRmVhdHVyZSA9IHtcblx0bmFtZTogXCJwb3N0Z3Jlc3FsXCIsXG5cdGVuYWJsZWQsXG5cdGNvbmZpZ3VyZSxcblx0cmVuZGVyLFxufTtcbiJdLCJuYW1lcyI6WyJyYW5kb21CeXRlcyIsIm1rZGlyIiwid3JpdGVGaWxlIiwiam9pbiIsIkNPTVBPU0VfS0VZIiwiQ29tcG9zZU1vZGVsIiwiREVWQ09OVEFJTkVSX0tFWSIsIlBPU1RHUkVTX0NSRURTX0tFWSIsImVuYWJsZWQiLCJjdHgiLCJvcHRzIiwiZGF0YWJhc2UiLCJjb25maWd1cmUiLCJkZXZjb250YWluZXIiLCJtb2RlbHMiLCJnZXQiLCJub2RlTW9kdWxlc1ZvbHVtZSIsInByb2plY3ROYW1lIiwiZGIiLCJ1c2VyIiwicGFzc3dvcmQiLCJ0b1N0cmluZyIsImNvbXBvc2UiLCJhZGRTZXJ2aWNlIiwiYnVpbGQiLCJ2b2x1bWVzIiwiZW52aXJvbm1lbnQiLCJOUE1fQ09ORklHX1VTRVJDT05GSUciLCJjb21tYW5kIiwiaW1hZ2UiLCJyZXN0YXJ0IiwiUE9TVEdSRVNfREIiLCJQT1NUR1JFU19VU0VSIiwiUE9TVEdSRVNfUEFTU1dPUkQiLCJwb3J0cyIsImFkZFZvbHVtZSIsInVzZUNvbXBvc2UiLCJjcmVkcyIsInNldCIsInJlbmRlciIsImRldmNvbnRhaW5lckRpciIsInRhcmdldERpciIsInJlY3Vyc2l2ZSIsImVudkNvbnRlbnQiLCJwb3N0Z3Jlc3FsRmVhdHVyZSIsIm5hbWUiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLFdBQVcsUUFBUSxjQUFjO0FBQzFDLFNBQVNDLEtBQUssRUFBRUMsU0FBUyxRQUFRLG1CQUFtQjtBQUNwRCxTQUFTQyxJQUFJLFFBQVEsWUFBWTtBQUNqQyxTQUFTQyxXQUFXLEVBQUVDLFlBQVksUUFBUSxnQ0FBZ0M7QUFDMUUsU0FBU0MsZ0JBQWdCLFFBQVEscUNBQXFDO0FBRXRFLFNBQVNDLGtCQUFrQixRQUFRLGNBQWM7QUFFakQsTUFBTUMsVUFBVSxDQUFDQyxNQUF5QkEsSUFBSUMsSUFBSSxDQUFDQyxRQUFRLEtBQUs7QUFFaEUsZUFBZUMsVUFBVUgsR0FBb0I7SUFDNUMsTUFBTUksZUFBZUosSUFBSUssTUFBTSxDQUFDQyxHQUFHLENBQUNUO0lBQ3BDLE1BQU1VLG9CQUFvQixHQUFHUCxJQUFJUSxXQUFXLENBQUMsYUFBYSxDQUFDO0lBRTNELE1BQU1DLEtBQUssR0FBR1QsSUFBSVEsV0FBVyxDQUFDLElBQUksQ0FBQztJQUNuQyxNQUFNRSxPQUFPO0lBQ2IsTUFBTUMsV0FBV3BCLFlBQVksSUFBSXFCLFFBQVEsQ0FBQztJQUUxQyxNQUFNQyxVQUFVLElBQUlqQixlQUNsQmtCLFVBQVUsQ0FBQyxnQkFBZ0I7UUFDM0JDLE9BQU87UUFDUEMsU0FBUztZQUNSLENBQUMsY0FBYyxFQUFFaEIsSUFBSVEsV0FBVyxDQUFDLGdCQUFnQixDQUFDO1lBQ2xELEdBQUdELGtCQUFrQix3QkFBd0IsQ0FBQztTQUM5QztRQUNEVSxhQUFhO1lBQ1pDLHVCQUF1QjtRQUN4QjtRQUNBQyxTQUFTO0lBQ1YsR0FDQ0wsVUFBVSxDQUFDLFlBQVk7UUFDdkJNLE9BQU87UUFDUEMsU0FBUztRQUNUSixhQUFhO1lBQ1osNkZBQTZGO1lBQzdGSyxhQUFhO1lBQ2IsNkZBQTZGO1lBQzdGQyxlQUFlO1lBQ2YsNkZBQTZGO1lBQzdGQyxtQkFBbUI7UUFDcEI7UUFDQUMsT0FBTztZQUFDO1NBQVk7UUFDcEJULFNBQVM7WUFBQztTQUF5QztJQUNwRCxHQUNDVSxTQUFTLENBQUNuQixtQkFDVm1CLFNBQVMsQ0FBQztJQUVadEIsY0FBY3VCO0lBRWQsTUFBTUMsUUFBUTtRQUFFbkI7UUFBSUM7UUFBTUM7SUFBUztJQUNuQyxPQUFPO1FBQ04sR0FBR1gsR0FBRztRQUNOSyxRQUFRTCxJQUFJSyxNQUFNLENBQUN3QixHQUFHLENBQUNsQyxhQUFha0IsU0FBU2dCLEdBQUcsQ0FBQy9CLG9CQUFvQjhCO0lBQ3RFO0FBQ0Q7QUFFQSxlQUFlRSxPQUFPOUIsR0FBb0I7SUFDekMsTUFBTTRCLFFBQVE1QixJQUFJSyxNQUFNLENBQUNDLEdBQUcsQ0FBQ1I7SUFDN0IsSUFBSSxDQUFDOEIsT0FBTyxPQUFPNUI7SUFFbkIsTUFBTStCLGtCQUFrQnJDLEtBQUtNLElBQUlnQyxTQUFTLEVBQUU7SUFDNUMsTUFBTXhDLE1BQU11QyxpQkFBaUI7UUFBRUUsV0FBVztJQUFLO0lBQy9DLE1BQU1DLGFBQWEsQ0FBQyxZQUFZLEVBQUVOLE1BQU1uQixFQUFFLENBQUMsZ0JBQWdCLEVBQUVtQixNQUFNbEIsSUFBSSxDQUFDLG9CQUFvQixFQUFFa0IsTUFBTWpCLFFBQVEsQ0FBQyxFQUFFLENBQUM7SUFDaEgsTUFBTWxCLFVBQVVDLEtBQUtxQyxpQkFBaUIsU0FBU0c7SUFFL0MsT0FBT2xDO0FBQ1I7QUFFQSxPQUFPLE1BQU1tQyxvQkFBNkI7SUFDekNDLE1BQU07SUFDTnJDO0lBQ0FJO0lBQ0EyQjtBQUNELEVBQUUifQ==
@@ -0,0 +1,4 @@
1
+ import { modelKey } from "../../domain/context.js";
2
+ export const POSTGRES_CREDS_KEY = modelKey("postgres-creds");
3
+
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9wb3N0Z3Jlc3FsL21vZGVscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBtb2RlbEtleSB9IGZyb20gXCIuLi8uLi9kb21haW4vY29udGV4dC5qc1wiO1xuXG5leHBvcnQgaW50ZXJmYWNlIFBvc3RncmVzQ3JlZHMge1xuXHRkYjogc3RyaW5nO1xuXHR1c2VyOiBzdHJpbmc7XG5cdHBhc3N3b3JkOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjb25zdCBQT1NUR1JFU19DUkVEU19LRVkgPSBtb2RlbEtleTxQb3N0Z3Jlc0NyZWRzPihcInBvc3RncmVzLWNyZWRzXCIpO1xuIl0sIm5hbWVzIjpbIm1vZGVsS2V5IiwiUE9TVEdSRVNfQ1JFRFNfS0VZIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxRQUFRLFFBQVEsMEJBQTBCO0FBUW5ELE9BQU8sTUFBTUMscUJBQXFCRCxTQUF3QixrQkFBa0IifQ==
@@ -0,0 +1,70 @@
1
+ export function buildPostmanCollection(projectName, withAuth0) {
2
+ const auth = withAuth0 ? {
3
+ type: "oauth2",
4
+ oauth2: [
5
+ {
6
+ key: "grant_type",
7
+ value: "authorization_code_with_pkce",
8
+ type: "string"
9
+ },
10
+ {
11
+ key: "authUrl",
12
+ value: "https://{{auth0Domain}}/authorize?audience={{auth0Audience}}",
13
+ type: "string"
14
+ },
15
+ {
16
+ key: "accessTokenUrl",
17
+ value: "https://{{auth0Domain}}/oauth/token",
18
+ type: "string"
19
+ },
20
+ {
21
+ key: "clientId",
22
+ value: "{{auth0ClientId}}",
23
+ type: "string"
24
+ },
25
+ {
26
+ key: "scope",
27
+ value: "openid profile email",
28
+ type: "string"
29
+ },
30
+ {
31
+ key: "addTokenTo",
32
+ value: "header",
33
+ type: "string"
34
+ },
35
+ {
36
+ key: "challengeAlgorithm",
37
+ value: "S256",
38
+ type: "string"
39
+ }
40
+ ]
41
+ } : undefined;
42
+ return {
43
+ info: {
44
+ name: `${projectName} WebAPI`,
45
+ schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
46
+ },
47
+ ...auth ? {
48
+ auth
49
+ } : {},
50
+ item: [
51
+ {
52
+ name: "Hello",
53
+ request: {
54
+ method: "GET",
55
+ url: {
56
+ raw: "{{baseUrl}}/hello",
57
+ host: [
58
+ "{{baseUrl}}"
59
+ ],
60
+ path: [
61
+ "hello"
62
+ ]
63
+ }
64
+ }
65
+ }
66
+ ]
67
+ };
68
+ }
69
+
70
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9wb3N0bWFuL2NvbGxlY3Rpb24udGVtcGxhdGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkUG9zdG1hbkNvbGxlY3Rpb24ocHJvamVjdE5hbWU6IHN0cmluZywgd2l0aEF1dGgwOiBib29sZWFuKTogdW5rbm93biB7XG5cdGNvbnN0IGF1dGggPSB3aXRoQXV0aDBcblx0XHQ/IHtcblx0XHRcdFx0dHlwZTogXCJvYXV0aDJcIixcblx0XHRcdFx0b2F1dGgyOiBbXG5cdFx0XHRcdFx0eyBrZXk6IFwiZ3JhbnRfdHlwZVwiLCB2YWx1ZTogXCJhdXRob3JpemF0aW9uX2NvZGVfd2l0aF9wa2NlXCIsIHR5cGU6IFwic3RyaW5nXCIgfSxcblx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRrZXk6IFwiYXV0aFVybFwiLFxuXHRcdFx0XHRcdFx0dmFsdWU6IFwiaHR0cHM6Ly97e2F1dGgwRG9tYWlufX0vYXV0aG9yaXplP2F1ZGllbmNlPXt7YXV0aDBBdWRpZW5jZX19XCIsXG5cdFx0XHRcdFx0XHR0eXBlOiBcInN0cmluZ1wiLFxuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0a2V5OiBcImFjY2Vzc1Rva2VuVXJsXCIsXG5cdFx0XHRcdFx0XHR2YWx1ZTogXCJodHRwczovL3t7YXV0aDBEb21haW59fS9vYXV0aC90b2tlblwiLFxuXHRcdFx0XHRcdFx0dHlwZTogXCJzdHJpbmdcIixcblx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdHsga2V5OiBcImNsaWVudElkXCIsIHZhbHVlOiBcInt7YXV0aDBDbGllbnRJZH19XCIsIHR5cGU6IFwic3RyaW5nXCIgfSxcblx0XHRcdFx0XHR7IGtleTogXCJzY29wZVwiLCB2YWx1ZTogXCJvcGVuaWQgcHJvZmlsZSBlbWFpbFwiLCB0eXBlOiBcInN0cmluZ1wiIH0sXG5cdFx0XHRcdFx0eyBrZXk6IFwiYWRkVG9rZW5Ub1wiLCB2YWx1ZTogXCJoZWFkZXJcIiwgdHlwZTogXCJzdHJpbmdcIiB9LFxuXHRcdFx0XHRcdHsga2V5OiBcImNoYWxsZW5nZUFsZ29yaXRobVwiLCB2YWx1ZTogXCJTMjU2XCIsIHR5cGU6IFwic3RyaW5nXCIgfSxcblx0XHRcdFx0XSxcblx0XHRcdH1cblx0XHQ6IHVuZGVmaW5lZDtcblxuXHRyZXR1cm4ge1xuXHRcdGluZm86IHtcblx0XHRcdG5hbWU6IGAke3Byb2plY3ROYW1lfSBXZWJBUElgLFxuXHRcdFx0c2NoZW1hOiBcImh0dHBzOi8vc2NoZW1hLmdldHBvc3RtYW4uY29tL2pzb24vY29sbGVjdGlvbi92Mi4xLjAvY29sbGVjdGlvbi5qc29uXCIsXG5cdFx0fSxcblx0XHQuLi4oYXV0aCA/IHsgYXV0aCB9IDoge30pLFxuXHRcdGl0ZW06IFtcblx0XHRcdHtcblx0XHRcdFx0bmFtZTogXCJIZWxsb1wiLFxuXHRcdFx0XHRyZXF1ZXN0OiB7XG5cdFx0XHRcdFx0bWV0aG9kOiBcIkdFVFwiLFxuXHRcdFx0XHRcdHVybDogeyByYXc6IFwie3tiYXNlVXJsfX0vaGVsbG9cIiwgaG9zdDogW1wie3tiYXNlVXJsfX1cIl0sIHBhdGg6IFtcImhlbGxvXCJdIH0sXG5cdFx0XHRcdH0sXG5cdFx0XHR9LFxuXHRcdF0sXG5cdH07XG59XG4iXSwibmFtZXMiOlsiYnVpbGRQb3N0bWFuQ29sbGVjdGlvbiIsInByb2plY3ROYW1lIiwid2l0aEF1dGgwIiwiYXV0aCIsInR5cGUiLCJvYXV0aDIiLCJrZXkiLCJ2YWx1ZSIsInVuZGVmaW5lZCIsImluZm8iLCJuYW1lIiwic2NoZW1hIiwiaXRlbSIsInJlcXVlc3QiLCJtZXRob2QiLCJ1cmwiLCJyYXciLCJob3N0IiwicGF0aCJdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxTQUFTQSx1QkFBdUJDLFdBQW1CLEVBQUVDLFNBQWtCO0lBQzdFLE1BQU1DLE9BQU9ELFlBQ1Y7UUFDQUUsTUFBTTtRQUNOQyxRQUFRO1lBQ1A7Z0JBQUVDLEtBQUs7Z0JBQWNDLE9BQU87Z0JBQWdDSCxNQUFNO1lBQVM7WUFDM0U7Z0JBQ0NFLEtBQUs7Z0JBQ0xDLE9BQU87Z0JBQ1BILE1BQU07WUFDUDtZQUNBO2dCQUNDRSxLQUFLO2dCQUNMQyxPQUFPO2dCQUNQSCxNQUFNO1lBQ1A7WUFDQTtnQkFBRUUsS0FBSztnQkFBWUMsT0FBTztnQkFBcUJILE1BQU07WUFBUztZQUM5RDtnQkFBRUUsS0FBSztnQkFBU0MsT0FBTztnQkFBd0JILE1BQU07WUFBUztZQUM5RDtnQkFBRUUsS0FBSztnQkFBY0MsT0FBTztnQkFBVUgsTUFBTTtZQUFTO1lBQ3JEO2dCQUFFRSxLQUFLO2dCQUFzQkMsT0FBTztnQkFBUUgsTUFBTTtZQUFTO1NBQzNEO0lBQ0YsSUFDQ0k7SUFFSCxPQUFPO1FBQ05DLE1BQU07WUFDTEMsTUFBTSxHQUFHVCxZQUFZLE9BQU8sQ0FBQztZQUM3QlUsUUFBUTtRQUNUO1FBQ0EsR0FBSVIsT0FBTztZQUFFQTtRQUFLLElBQUksQ0FBQyxDQUFDO1FBQ3hCUyxNQUFNO1lBQ0w7Z0JBQ0NGLE1BQU07Z0JBQ05HLFNBQVM7b0JBQ1JDLFFBQVE7b0JBQ1JDLEtBQUs7d0JBQUVDLEtBQUs7d0JBQXFCQyxNQUFNOzRCQUFDO3lCQUFjO3dCQUFFQyxNQUFNOzRCQUFDO3lCQUFRO29CQUFDO2dCQUN6RTtZQUNEO1NBQ0E7SUFDRjtBQUNEIn0=
@@ -0,0 +1,14 @@
1
+ export function postmanEnvironmentYaml(name, opts) {
2
+ const auth0Section = opts?.auth0Domain ? `${[
3
+ " - key: auth0Domain",
4
+ ` value: ${opts.auth0Domain}`,
5
+ " - key: auth0Audience",
6
+ ` value: '${opts.auth0Audience ?? ""}'`,
7
+ " - key: auth0ClientId",
8
+ ` value: '${opts.auth0ClientId ?? ""}'`,
9
+ " description: Client ID of the Auth0 SPA application used by Postman for PKCE authentication"
10
+ ].join("\n")}\n` : "";
11
+ return `name: ${name}\nvalues:\n - key: baseUrl\n value: 'http://localhost:3000'\n${auth0Section}`;
12
+ }
13
+
14
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9wb3N0bWFuL2Vudmlyb25tZW50LnRlbXBsYXRlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBpbnRlcmZhY2UgUG9zdG1hbkVudk9wdGlvbnMge1xuXHRhdXRoMERvbWFpbj86IHN0cmluZztcblx0YXV0aDBBdWRpZW5jZT86IHN0cmluZztcblx0YXV0aDBDbGllbnRJZD86IHN0cmluZztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBvc3RtYW5FbnZpcm9ubWVudFlhbWwobmFtZTogc3RyaW5nLCBvcHRzPzogUG9zdG1hbkVudk9wdGlvbnMpOiBzdHJpbmcge1xuXHRjb25zdCBhdXRoMFNlY3Rpb24gPSBvcHRzPy5hdXRoMERvbWFpblxuXHRcdD8gYCR7W1xuXHRcdFx0XHRcIiAgLSBrZXk6IGF1dGgwRG9tYWluXCIsXG5cdFx0XHRcdGAgICAgdmFsdWU6ICR7b3B0cy5hdXRoMERvbWFpbn1gLFxuXHRcdFx0XHRcIiAgLSBrZXk6IGF1dGgwQXVkaWVuY2VcIixcblx0XHRcdFx0YCAgICB2YWx1ZTogJyR7b3B0cy5hdXRoMEF1ZGllbmNlID8/IFwiXCJ9J2AsXG5cdFx0XHRcdFwiICAtIGtleTogYXV0aDBDbGllbnRJZFwiLFxuXHRcdFx0XHRgICAgIHZhbHVlOiAnJHtvcHRzLmF1dGgwQ2xpZW50SWQgPz8gXCJcIn0nYCxcblx0XHRcdFx0XCIgICAgZGVzY3JpcHRpb246IENsaWVudCBJRCBvZiB0aGUgQXV0aDAgU1BBIGFwcGxpY2F0aW9uIHVzZWQgYnkgUG9zdG1hbiBmb3IgUEtDRSBhdXRoZW50aWNhdGlvblwiLFxuXHRcdFx0XS5qb2luKFwiXFxuXCIpfVxcbmBcblx0XHQ6IFwiXCI7XG5cdHJldHVybiBgbmFtZTogJHtuYW1lfVxcbnZhbHVlczpcXG4gIC0ga2V5OiBiYXNlVXJsXFxuICAgIHZhbHVlOiAnaHR0cDovL2xvY2FsaG9zdDozMDAwJ1xcbiR7YXV0aDBTZWN0aW9ufWA7XG59XG4iXSwibmFtZXMiOlsicG9zdG1hbkVudmlyb25tZW50WWFtbCIsIm5hbWUiLCJvcHRzIiwiYXV0aDBTZWN0aW9uIiwiYXV0aDBEb21haW4iLCJhdXRoMEF1ZGllbmNlIiwiYXV0aDBDbGllbnRJZCIsImpvaW4iXSwibWFwcGluZ3MiOiJBQU1BLE9BQU8sU0FBU0EsdUJBQXVCQyxJQUFZLEVBQUVDLElBQXdCO0lBQzVFLE1BQU1DLGVBQWVELE1BQU1FLGNBQ3hCLEdBQUc7UUFDSDtRQUNBLENBQUMsV0FBVyxFQUFFRixLQUFLRSxXQUFXLEVBQUU7UUFDaEM7UUFDQSxDQUFDLFlBQVksRUFBRUYsS0FBS0csYUFBYSxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQzFDO1FBQ0EsQ0FBQyxZQUFZLEVBQUVILEtBQUtJLGFBQWEsSUFBSSxHQUFHLENBQUMsQ0FBQztRQUMxQztLQUNBLENBQUNDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUNmO0lBQ0gsT0FBTyxDQUFDLE1BQU0sRUFBRU4sS0FBSyxpRUFBaUUsRUFBRUUsY0FBYztBQUN2RyJ9
@@ -0,0 +1,141 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { ask } from "../../domain/index.js";
4
+ import * as auth0 from "../auth0/auth0-cli.js";
5
+ import { AUTH0_CONFIG_KEY } from "../auth0/models.js";
6
+ import { buildPostmanCollection } from "./collection.template.js";
7
+ import { postmanEnvironmentYaml } from "./environment.template.js";
8
+ const enabled = (ctx)=>!!ctx.opts.postman && !ctx.opts.yes;
9
+ /**
10
+ * Integrate phase: drives the Postman REST API (and optionally the auth0 CLI
11
+ * to create a SPA app for PKCE auth). Also writes a local environment yaml
12
+ * for the VS Code Postman extension.
13
+ */ async function integrate(ctx) {
14
+ const { projectName, targetDir } = ctx;
15
+ const auth0Config = ctx.models.get(AUTH0_CONFIG_KEY);
16
+ const apiKey = process.env.POSTMAN_API_KEY ?? await ask("\n Postman API key (from app.getpostman.com/settings/me/api-keys): ");
17
+ const headers = {
18
+ "X-Api-Key": apiKey,
19
+ "Content-Type": "application/json"
20
+ };
21
+ const wsRes = await fetch("https://api.getpostman.com/workspaces", {
22
+ headers
23
+ });
24
+ if (!wsRes.ok) {
25
+ console.error("\n Postman API key is invalid or request failed. Skipping Postman setup.");
26
+ return ctx;
27
+ }
28
+ const { workspaces } = await wsRes.json();
29
+ console.log("\n Postman workspaces:");
30
+ for (const [i, w] of workspaces.entries()){
31
+ console.log(` ${i + 1}. ${w.name} (${w.type})`);
32
+ }
33
+ console.log(" 0. Create new workspace");
34
+ const wsInput = await ask(" Select workspace [0]: ", "0");
35
+ const wsIdx = Number.parseInt(wsInput, 10);
36
+ let workspaceId;
37
+ if (Number.isNaN(wsIdx) || wsIdx === 0 || wsIdx > workspaces.length) {
38
+ const wsName = await ask(` New workspace name [${projectName}]: `, projectName);
39
+ const createRes = await fetch("https://api.getpostman.com/workspaces", {
40
+ method: "POST",
41
+ headers,
42
+ body: JSON.stringify({
43
+ workspace: {
44
+ name: wsName,
45
+ type: "personal"
46
+ }
47
+ })
48
+ });
49
+ const { workspace } = await createRes.json();
50
+ workspaceId = workspace.id;
51
+ console.log(` ✓ Workspace created: ${wsName}`);
52
+ } else {
53
+ workspaceId = workspaces[wsIdx - 1].id;
54
+ console.log(` ✓ Workspace selected: ${workspaces[wsIdx - 1].name}`);
55
+ }
56
+ // Create SPA app in Auth0 for Postman PKCE flow
57
+ let spaClientId;
58
+ if (auth0Config) {
59
+ console.log("\n Creating Auth0 SPA application for Postman...");
60
+ try {
61
+ spaClientId = auth0.createSpaApp(`${projectName} Postman`, "https://oauth.pstmn.io/v1/callback").client_id;
62
+ console.log(` ✓ SPA app created: ${spaClientId}`);
63
+ } catch {
64
+ console.error(` ✗ Failed to create SPA app. Re-login with required scopes:\n auth0 login --scopes ${auth0.REQUIRED_SCOPES}`);
65
+ }
66
+ }
67
+ // Create collection
68
+ const colRes = await fetch(`https://api.getpostman.com/collections?workspace=${workspaceId}`, {
69
+ method: "POST",
70
+ headers,
71
+ body: JSON.stringify({
72
+ collection: buildPostmanCollection(projectName, auth0Config != null)
73
+ })
74
+ });
75
+ if (colRes.ok) {
76
+ console.log(" ✓ Postman collection created");
77
+ } else {
78
+ console.error(" ✗ Failed to create Postman collection");
79
+ }
80
+ // Create environment
81
+ const envVars = [
82
+ {
83
+ key: "baseUrl",
84
+ value: "http://localhost:3000",
85
+ type: "default",
86
+ enabled: true
87
+ }
88
+ ];
89
+ if (auth0Config) {
90
+ envVars.push({
91
+ key: "auth0Domain",
92
+ value: auth0Config.issuerBaseUrl.replace("https://", ""),
93
+ type: "default",
94
+ enabled: true
95
+ }, {
96
+ key: "auth0Audience",
97
+ value: auth0Config.audience,
98
+ type: "default",
99
+ enabled: true
100
+ }, {
101
+ key: "auth0ClientId",
102
+ value: spaClientId ?? "",
103
+ type: "default",
104
+ enabled: true
105
+ });
106
+ }
107
+ const envRes = await fetch(`https://api.getpostman.com/environments?workspace=${workspaceId}`, {
108
+ method: "POST",
109
+ headers,
110
+ body: JSON.stringify({
111
+ environment: {
112
+ name: `${projectName} — Local`,
113
+ values: envVars
114
+ }
115
+ })
116
+ });
117
+ if (envRes.ok) {
118
+ console.log(" ✓ Postman environment created");
119
+ } else {
120
+ console.error(" ✗ Failed to create Postman environment");
121
+ }
122
+ // Write local environment YAML for VS Code Postman extension
123
+ const envDir = join(targetDir, "postman", "environments");
124
+ await mkdir(envDir, {
125
+ recursive: true
126
+ });
127
+ await writeFile(join(envDir, `${projectName} — Local.environment.yaml`), postmanEnvironmentYaml(`${projectName} — Local`, auth0Config ? {
128
+ auth0Domain: auth0Config.issuerBaseUrl.replace("https://", ""),
129
+ auth0Audience: auth0Config.audience,
130
+ auth0ClientId: spaClientId ?? ""
131
+ } : undefined));
132
+ console.log(" ✓ Local environment file written to postman/environments/");
133
+ return ctx;
134
+ }
135
+ export const postmanFeature = {
136
+ name: "postman",
137
+ enabled,
138
+ integrate
139
+ };
140
+
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy9wb3N0bWFuL2ZlYXR1cmUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbWtkaXIsIHdyaXRlRmlsZSB9IGZyb20gXCJub2RlOmZzL3Byb21pc2VzXCI7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcIm5vZGU6cGF0aFwiO1xuaW1wb3J0IHsgYXNrLCB0eXBlIEZlYXR1cmUsIHR5cGUgU2NhZmZvbGRDb250ZXh0IH0gZnJvbSBcIi4uLy4uL2RvbWFpbi9pbmRleC5qc1wiO1xuaW1wb3J0ICogYXMgYXV0aDAgZnJvbSBcIi4uL2F1dGgwL2F1dGgwLWNsaS5qc1wiO1xuaW1wb3J0IHsgQVVUSDBfQ09ORklHX0tFWSB9IGZyb20gXCIuLi9hdXRoMC9tb2RlbHMuanNcIjtcbmltcG9ydCB7IGJ1aWxkUG9zdG1hbkNvbGxlY3Rpb24gfSBmcm9tIFwiLi9jb2xsZWN0aW9uLnRlbXBsYXRlLmpzXCI7XG5pbXBvcnQgeyBwb3N0bWFuRW52aXJvbm1lbnRZYW1sIH0gZnJvbSBcIi4vZW52aXJvbm1lbnQudGVtcGxhdGUuanNcIjtcblxuY29uc3QgZW5hYmxlZCA9IChjdHg6IFNjYWZmb2xkQ29udGV4dCkgPT4gISFjdHgub3B0cy5wb3N0bWFuICYmICFjdHgub3B0cy55ZXM7XG5cbi8qKlxuICogSW50ZWdyYXRlIHBoYXNlOiBkcml2ZXMgdGhlIFBvc3RtYW4gUkVTVCBBUEkgKGFuZCBvcHRpb25hbGx5IHRoZSBhdXRoMCBDTElcbiAqIHRvIGNyZWF0ZSBhIFNQQSBhcHAgZm9yIFBLQ0UgYXV0aCkuIEFsc28gd3JpdGVzIGEgbG9jYWwgZW52aXJvbm1lbnQgeWFtbFxuICogZm9yIHRoZSBWUyBDb2RlIFBvc3RtYW4gZXh0ZW5zaW9uLlxuICovXG5hc3luYyBmdW5jdGlvbiBpbnRlZ3JhdGUoY3R4OiBTY2FmZm9sZENvbnRleHQpOiBQcm9taXNlPFNjYWZmb2xkQ29udGV4dD4ge1xuXHRjb25zdCB7IHByb2plY3ROYW1lLCB0YXJnZXREaXIgfSA9IGN0eDtcblx0Y29uc3QgYXV0aDBDb25maWcgPSBjdHgubW9kZWxzLmdldChBVVRIMF9DT05GSUdfS0VZKTtcblxuXHRjb25zdCBhcGlLZXkgPVxuXHRcdHByb2Nlc3MuZW52LlBPU1RNQU5fQVBJX0tFWSA/P1xuXHRcdChhd2FpdCBhc2soXCJcXG4gIFBvc3RtYW4gQVBJIGtleSAoZnJvbSBhcHAuZ2V0cG9zdG1hbi5jb20vc2V0dGluZ3MvbWUvYXBpLWtleXMpOiBcIikpO1xuXG5cdGNvbnN0IGhlYWRlcnMgPSB7IFwiWC1BcGktS2V5XCI6IGFwaUtleSwgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIgfTtcblxuXHRjb25zdCB3c1JlcyA9IGF3YWl0IGZldGNoKFwiaHR0cHM6Ly9hcGkuZ2V0cG9zdG1hbi5jb20vd29ya3NwYWNlc1wiLCB7IGhlYWRlcnMgfSk7XG5cdGlmICghd3NSZXMub2spIHtcblx0XHRjb25zb2xlLmVycm9yKFwiXFxuICBQb3N0bWFuIEFQSSBrZXkgaXMgaW52YWxpZCBvciByZXF1ZXN0IGZhaWxlZC4gU2tpcHBpbmcgUG9zdG1hbiBzZXR1cC5cIik7XG5cdFx0cmV0dXJuIGN0eDtcblx0fVxuXHRjb25zdCB7IHdvcmtzcGFjZXMgfSA9IChhd2FpdCB3c1Jlcy5qc29uKCkpIGFzIHtcblx0XHR3b3Jrc3BhY2VzOiBBcnJheTx7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZzsgdHlwZTogc3RyaW5nIH0+O1xuXHR9O1xuXG5cdGNvbnNvbGUubG9nKFwiXFxuICBQb3N0bWFuIHdvcmtzcGFjZXM6XCIpO1xuXHRmb3IgKGNvbnN0IFtpLCB3XSBvZiB3b3Jrc3BhY2VzLmVudHJpZXMoKSkge1xuXHRcdGNvbnNvbGUubG9nKGAgICAgJHtpICsgMX0uICR7dy5uYW1lfSAoJHt3LnR5cGV9KWApO1xuXHR9XG5cdGNvbnNvbGUubG9nKFwiICAgIDAuIENyZWF0ZSBuZXcgd29ya3NwYWNlXCIpO1xuXG5cdGNvbnN0IHdzSW5wdXQgPSBhd2FpdCBhc2soXCIgIFNlbGVjdCB3b3Jrc3BhY2UgWzBdOiBcIiwgXCIwXCIpO1xuXHRjb25zdCB3c0lkeCA9IE51bWJlci5wYXJzZUludCh3c0lucHV0LCAxMCk7XG5cblx0bGV0IHdvcmtzcGFjZUlkOiBzdHJpbmc7XG5cdGlmIChOdW1iZXIuaXNOYU4od3NJZHgpIHx8IHdzSWR4ID09PSAwIHx8IHdzSWR4ID4gd29ya3NwYWNlcy5sZW5ndGgpIHtcblx0XHRjb25zdCB3c05hbWUgPSBhd2FpdCBhc2soYCAgTmV3IHdvcmtzcGFjZSBuYW1lIFske3Byb2plY3ROYW1lfV06IGAsIHByb2plY3ROYW1lKTtcblx0XHRjb25zdCBjcmVhdGVSZXMgPSBhd2FpdCBmZXRjaChcImh0dHBzOi8vYXBpLmdldHBvc3RtYW4uY29tL3dvcmtzcGFjZXNcIiwge1xuXHRcdFx0bWV0aG9kOiBcIlBPU1RcIixcblx0XHRcdGhlYWRlcnMsXG5cdFx0XHRib2R5OiBKU09OLnN0cmluZ2lmeSh7IHdvcmtzcGFjZTogeyBuYW1lOiB3c05hbWUsIHR5cGU6IFwicGVyc29uYWxcIiB9IH0pLFxuXHRcdH0pO1xuXHRcdGNvbnN0IHsgd29ya3NwYWNlIH0gPSAoYXdhaXQgY3JlYXRlUmVzLmpzb24oKSkgYXMgeyB3b3Jrc3BhY2U6IHsgaWQ6IHN0cmluZyB9IH07XG5cdFx0d29ya3NwYWNlSWQgPSB3b3Jrc3BhY2UuaWQ7XG5cdFx0Y29uc29sZS5sb2coYCAg4pyTIFdvcmtzcGFjZSBjcmVhdGVkOiAke3dzTmFtZX1gKTtcblx0fSBlbHNlIHtcblx0XHR3b3Jrc3BhY2VJZCA9IHdvcmtzcGFjZXNbd3NJZHggLSAxXS5pZDtcblx0XHRjb25zb2xlLmxvZyhgICDinJMgV29ya3NwYWNlIHNlbGVjdGVkOiAke3dvcmtzcGFjZXNbd3NJZHggLSAxXS5uYW1lfWApO1xuXHR9XG5cblx0Ly8gQ3JlYXRlIFNQQSBhcHAgaW4gQXV0aDAgZm9yIFBvc3RtYW4gUEtDRSBmbG93XG5cdGxldCBzcGFDbGllbnRJZDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXHRpZiAoYXV0aDBDb25maWcpIHtcblx0XHRjb25zb2xlLmxvZyhcIlxcbiAgQ3JlYXRpbmcgQXV0aDAgU1BBIGFwcGxpY2F0aW9uIGZvciBQb3N0bWFuLi4uXCIpO1xuXHRcdHRyeSB7XG5cdFx0XHRzcGFDbGllbnRJZCA9IGF1dGgwLmNyZWF0ZVNwYUFwcChcblx0XHRcdFx0YCR7cHJvamVjdE5hbWV9IFBvc3RtYW5gLFxuXHRcdFx0XHRcImh0dHBzOi8vb2F1dGgucHN0bW4uaW8vdjEvY2FsbGJhY2tcIixcblx0XHRcdCkuY2xpZW50X2lkO1xuXHRcdFx0Y29uc29sZS5sb2coYCAg4pyTIFNQQSBhcHAgY3JlYXRlZDogJHtzcGFDbGllbnRJZH1gKTtcblx0XHR9IGNhdGNoIHtcblx0XHRcdGNvbnNvbGUuZXJyb3IoXG5cdFx0XHRcdGAgIOKclyBGYWlsZWQgdG8gY3JlYXRlIFNQQSBhcHAuIFJlLWxvZ2luIHdpdGggcmVxdWlyZWQgc2NvcGVzOlxcbiAgICBhdXRoMCBsb2dpbiAtLXNjb3BlcyAke2F1dGgwLlJFUVVJUkVEX1NDT1BFU31gLFxuXHRcdFx0KTtcblx0XHR9XG5cdH1cblxuXHQvLyBDcmVhdGUgY29sbGVjdGlvblxuXHRjb25zdCBjb2xSZXMgPSBhd2FpdCBmZXRjaChcblx0XHRgaHR0cHM6Ly9hcGkuZ2V0cG9zdG1hbi5jb20vY29sbGVjdGlvbnM/d29ya3NwYWNlPSR7d29ya3NwYWNlSWR9YCxcblx0XHR7XG5cdFx0XHRtZXRob2Q6IFwiUE9TVFwiLFxuXHRcdFx0aGVhZGVycyxcblx0XHRcdGJvZHk6IEpTT04uc3RyaW5naWZ5KHtcblx0XHRcdFx0Y29sbGVjdGlvbjogYnVpbGRQb3N0bWFuQ29sbGVjdGlvbihwcm9qZWN0TmFtZSwgYXV0aDBDb25maWcgIT0gbnVsbCksXG5cdFx0XHR9KSxcblx0XHR9LFxuXHQpO1xuXHRpZiAoY29sUmVzLm9rKSB7XG5cdFx0Y29uc29sZS5sb2coXCIgIOKckyBQb3N0bWFuIGNvbGxlY3Rpb24gY3JlYXRlZFwiKTtcblx0fSBlbHNlIHtcblx0XHRjb25zb2xlLmVycm9yKFwiICDinJcgRmFpbGVkIHRvIGNyZWF0ZSBQb3N0bWFuIGNvbGxlY3Rpb25cIik7XG5cdH1cblxuXHQvLyBDcmVhdGUgZW52aXJvbm1lbnRcblx0Y29uc3QgZW52VmFyczogQXJyYXk8eyBrZXk6IHN0cmluZzsgdmFsdWU6IHN0cmluZzsgdHlwZTogc3RyaW5nOyBlbmFibGVkOiBib29sZWFuIH0+ID0gW1xuXHRcdHsga2V5OiBcImJhc2VVcmxcIiwgdmFsdWU6IFwiaHR0cDovL2xvY2FsaG9zdDozMDAwXCIsIHR5cGU6IFwiZGVmYXVsdFwiLCBlbmFibGVkOiB0cnVlIH0sXG5cdF07XG5cdGlmIChhdXRoMENvbmZpZykge1xuXHRcdGVudlZhcnMucHVzaChcblx0XHRcdHtcblx0XHRcdFx0a2V5OiBcImF1dGgwRG9tYWluXCIsXG5cdFx0XHRcdHZhbHVlOiBhdXRoMENvbmZpZy5pc3N1ZXJCYXNlVXJsLnJlcGxhY2UoXCJodHRwczovL1wiLCBcIlwiKSxcblx0XHRcdFx0dHlwZTogXCJkZWZhdWx0XCIsXG5cdFx0XHRcdGVuYWJsZWQ6IHRydWUsXG5cdFx0XHR9LFxuXHRcdFx0eyBrZXk6IFwiYXV0aDBBdWRpZW5jZVwiLCB2YWx1ZTogYXV0aDBDb25maWcuYXVkaWVuY2UsIHR5cGU6IFwiZGVmYXVsdFwiLCBlbmFibGVkOiB0cnVlIH0sXG5cdFx0XHR7XG5cdFx0XHRcdGtleTogXCJhdXRoMENsaWVudElkXCIsXG5cdFx0XHRcdHZhbHVlOiBzcGFDbGllbnRJZCA/PyBcIlwiLFxuXHRcdFx0XHR0eXBlOiBcImRlZmF1bHRcIixcblx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcblx0XHRcdH0sXG5cdFx0KTtcblx0fVxuXHRjb25zdCBlbnZSZXMgPSBhd2FpdCBmZXRjaChcblx0XHRgaHR0cHM6Ly9hcGkuZ2V0cG9zdG1hbi5jb20vZW52aXJvbm1lbnRzP3dvcmtzcGFjZT0ke3dvcmtzcGFjZUlkfWAsXG5cdFx0e1xuXHRcdFx0bWV0aG9kOiBcIlBPU1RcIixcblx0XHRcdGhlYWRlcnMsXG5cdFx0XHRib2R5OiBKU09OLnN0cmluZ2lmeSh7XG5cdFx0XHRcdGVudmlyb25tZW50OiB7IG5hbWU6IGAke3Byb2plY3ROYW1lfSDigJQgTG9jYWxgLCB2YWx1ZXM6IGVudlZhcnMgfSxcblx0XHRcdH0pLFxuXHRcdH0sXG5cdCk7XG5cdGlmIChlbnZSZXMub2spIHtcblx0XHRjb25zb2xlLmxvZyhcIiAg4pyTIFBvc3RtYW4gZW52aXJvbm1lbnQgY3JlYXRlZFwiKTtcblx0fSBlbHNlIHtcblx0XHRjb25zb2xlLmVycm9yKFwiICDinJcgRmFpbGVkIHRvIGNyZWF0ZSBQb3N0bWFuIGVudmlyb25tZW50XCIpO1xuXHR9XG5cblx0Ly8gV3JpdGUgbG9jYWwgZW52aXJvbm1lbnQgWUFNTCBmb3IgVlMgQ29kZSBQb3N0bWFuIGV4dGVuc2lvblxuXHRjb25zdCBlbnZEaXIgPSBqb2luKHRhcmdldERpciwgXCJwb3N0bWFuXCIsIFwiZW52aXJvbm1lbnRzXCIpO1xuXHRhd2FpdCBta2RpcihlbnZEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXHRhd2FpdCB3cml0ZUZpbGUoXG5cdFx0am9pbihlbnZEaXIsIGAke3Byb2plY3ROYW1lfSDigJQgTG9jYWwuZW52aXJvbm1lbnQueWFtbGApLFxuXHRcdHBvc3RtYW5FbnZpcm9ubWVudFlhbWwoXG5cdFx0XHRgJHtwcm9qZWN0TmFtZX0g4oCUIExvY2FsYCxcblx0XHRcdGF1dGgwQ29uZmlnXG5cdFx0XHRcdD8ge1xuXHRcdFx0XHRcdFx0YXV0aDBEb21haW46IGF1dGgwQ29uZmlnLmlzc3VlckJhc2VVcmwucmVwbGFjZShcImh0dHBzOi8vXCIsIFwiXCIpLFxuXHRcdFx0XHRcdFx0YXV0aDBBdWRpZW5jZTogYXV0aDBDb25maWcuYXVkaWVuY2UsXG5cdFx0XHRcdFx0XHRhdXRoMENsaWVudElkOiBzcGFDbGllbnRJZCA/PyBcIlwiLFxuXHRcdFx0XHRcdH1cblx0XHRcdFx0OiB1bmRlZmluZWQsXG5cdFx0KSxcblx0KTtcblx0Y29uc29sZS5sb2coXCIgIOKckyBMb2NhbCBlbnZpcm9ubWVudCBmaWxlIHdyaXR0ZW4gdG8gcG9zdG1hbi9lbnZpcm9ubWVudHMvXCIpO1xuXG5cdHJldHVybiBjdHg7XG59XG5cbmV4cG9ydCBjb25zdCBwb3N0bWFuRmVhdHVyZTogRmVhdHVyZSA9IHtcblx0bmFtZTogXCJwb3N0bWFuXCIsXG5cdGVuYWJsZWQsXG5cdGludGVncmF0ZSxcbn07XG4iXSwibmFtZXMiOlsibWtkaXIiLCJ3cml0ZUZpbGUiLCJqb2luIiwiYXNrIiwiYXV0aDAiLCJBVVRIMF9DT05GSUdfS0VZIiwiYnVpbGRQb3N0bWFuQ29sbGVjdGlvbiIsInBvc3RtYW5FbnZpcm9ubWVudFlhbWwiLCJlbmFibGVkIiwiY3R4Iiwib3B0cyIsInBvc3RtYW4iLCJ5ZXMiLCJpbnRlZ3JhdGUiLCJwcm9qZWN0TmFtZSIsInRhcmdldERpciIsImF1dGgwQ29uZmlnIiwibW9kZWxzIiwiZ2V0IiwiYXBpS2V5IiwicHJvY2VzcyIsImVudiIsIlBPU1RNQU5fQVBJX0tFWSIsImhlYWRlcnMiLCJ3c1JlcyIsImZldGNoIiwib2siLCJjb25zb2xlIiwiZXJyb3IiLCJ3b3Jrc3BhY2VzIiwianNvbiIsImxvZyIsImkiLCJ3IiwiZW50cmllcyIsIm5hbWUiLCJ0eXBlIiwid3NJbnB1dCIsIndzSWR4IiwiTnVtYmVyIiwicGFyc2VJbnQiLCJ3b3Jrc3BhY2VJZCIsImlzTmFOIiwibGVuZ3RoIiwid3NOYW1lIiwiY3JlYXRlUmVzIiwibWV0aG9kIiwiYm9keSIsIkpTT04iLCJzdHJpbmdpZnkiLCJ3b3Jrc3BhY2UiLCJpZCIsInNwYUNsaWVudElkIiwiY3JlYXRlU3BhQXBwIiwiY2xpZW50X2lkIiwiUkVRVUlSRURfU0NPUEVTIiwiY29sUmVzIiwiY29sbGVjdGlvbiIsImVudlZhcnMiLCJrZXkiLCJ2YWx1ZSIsInB1c2giLCJpc3N1ZXJCYXNlVXJsIiwicmVwbGFjZSIsImF1ZGllbmNlIiwiZW52UmVzIiwiZW52aXJvbm1lbnQiLCJ2YWx1ZXMiLCJlbnZEaXIiLCJyZWN1cnNpdmUiLCJhdXRoMERvbWFpbiIsImF1dGgwQXVkaWVuY2UiLCJhdXRoMENsaWVudElkIiwidW5kZWZpbmVkIiwicG9zdG1hbkZlYXR1cmUiXSwibWFwcGluZ3MiOiJBQUFBLFNBQVNBLEtBQUssRUFBRUMsU0FBUyxRQUFRLG1CQUFtQjtBQUNwRCxTQUFTQyxJQUFJLFFBQVEsWUFBWTtBQUNqQyxTQUFTQyxHQUFHLFFBQTRDLHdCQUF3QjtBQUNoRixZQUFZQyxXQUFXLHdCQUF3QjtBQUMvQyxTQUFTQyxnQkFBZ0IsUUFBUSxxQkFBcUI7QUFDdEQsU0FBU0Msc0JBQXNCLFFBQVEsMkJBQTJCO0FBQ2xFLFNBQVNDLHNCQUFzQixRQUFRLDRCQUE0QjtBQUVuRSxNQUFNQyxVQUFVLENBQUNDLE1BQXlCLENBQUMsQ0FBQ0EsSUFBSUMsSUFBSSxDQUFDQyxPQUFPLElBQUksQ0FBQ0YsSUFBSUMsSUFBSSxDQUFDRSxHQUFHO0FBRTdFOzs7O0NBSUMsR0FDRCxlQUFlQyxVQUFVSixHQUFvQjtJQUM1QyxNQUFNLEVBQUVLLFdBQVcsRUFBRUMsU0FBUyxFQUFFLEdBQUdOO0lBQ25DLE1BQU1PLGNBQWNQLElBQUlRLE1BQU0sQ0FBQ0MsR0FBRyxDQUFDYjtJQUVuQyxNQUFNYyxTQUNMQyxRQUFRQyxHQUFHLENBQUNDLGVBQWUsSUFDMUIsTUFBTW5CLElBQUk7SUFFWixNQUFNb0IsVUFBVTtRQUFFLGFBQWFKO1FBQVEsZ0JBQWdCO0lBQW1CO0lBRTFFLE1BQU1LLFFBQVEsTUFBTUMsTUFBTSx5Q0FBeUM7UUFBRUY7SUFBUTtJQUM3RSxJQUFJLENBQUNDLE1BQU1FLEVBQUUsRUFBRTtRQUNkQyxRQUFRQyxLQUFLLENBQUM7UUFDZCxPQUFPbkI7SUFDUjtJQUNBLE1BQU0sRUFBRW9CLFVBQVUsRUFBRSxHQUFJLE1BQU1MLE1BQU1NLElBQUk7SUFJeENILFFBQVFJLEdBQUcsQ0FBQztJQUNaLEtBQUssTUFBTSxDQUFDQyxHQUFHQyxFQUFFLElBQUlKLFdBQVdLLE9BQU8sR0FBSTtRQUMxQ1AsUUFBUUksR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFQyxJQUFJLEVBQUUsRUFBRSxFQUFFQyxFQUFFRSxJQUFJLENBQUMsRUFBRSxFQUFFRixFQUFFRyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ2xEO0lBQ0FULFFBQVFJLEdBQUcsQ0FBQztJQUVaLE1BQU1NLFVBQVUsTUFBTWxDLElBQUksNEJBQTRCO0lBQ3RELE1BQU1tQyxRQUFRQyxPQUFPQyxRQUFRLENBQUNILFNBQVM7SUFFdkMsSUFBSUk7SUFDSixJQUFJRixPQUFPRyxLQUFLLENBQUNKLFVBQVVBLFVBQVUsS0FBS0EsUUFBUVQsV0FBV2MsTUFBTSxFQUFFO1FBQ3BFLE1BQU1DLFNBQVMsTUFBTXpDLElBQUksQ0FBQyxzQkFBc0IsRUFBRVcsWUFBWSxHQUFHLENBQUMsRUFBRUE7UUFDcEUsTUFBTStCLFlBQVksTUFBTXBCLE1BQU0seUNBQXlDO1lBQ3RFcUIsUUFBUTtZQUNSdkI7WUFDQXdCLE1BQU1DLEtBQUtDLFNBQVMsQ0FBQztnQkFBRUMsV0FBVztvQkFBRWYsTUFBTVM7b0JBQVFSLE1BQU07Z0JBQVc7WUFBRTtRQUN0RTtRQUNBLE1BQU0sRUFBRWMsU0FBUyxFQUFFLEdBQUksTUFBTUwsVUFBVWYsSUFBSTtRQUMzQ1csY0FBY1MsVUFBVUMsRUFBRTtRQUMxQnhCLFFBQVFJLEdBQUcsQ0FBQyxDQUFDLHVCQUF1QixFQUFFYSxRQUFRO0lBQy9DLE9BQU87UUFDTkgsY0FBY1osVUFBVSxDQUFDUyxRQUFRLEVBQUUsQ0FBQ2EsRUFBRTtRQUN0Q3hCLFFBQVFJLEdBQUcsQ0FBQyxDQUFDLHdCQUF3QixFQUFFRixVQUFVLENBQUNTLFFBQVEsRUFBRSxDQUFDSCxJQUFJLEVBQUU7SUFDcEU7SUFFQSxnREFBZ0Q7SUFDaEQsSUFBSWlCO0lBQ0osSUFBSXBDLGFBQWE7UUFDaEJXLFFBQVFJLEdBQUcsQ0FBQztRQUNaLElBQUk7WUFDSHFCLGNBQWNoRCxNQUFNaUQsWUFBWSxDQUMvQixHQUFHdkMsWUFBWSxRQUFRLENBQUMsRUFDeEIsc0NBQ0N3QyxTQUFTO1lBQ1gzQixRQUFRSSxHQUFHLENBQUMsQ0FBQyxxQkFBcUIsRUFBRXFCLGFBQWE7UUFDbEQsRUFBRSxPQUFNO1lBQ1B6QixRQUFRQyxLQUFLLENBQ1osQ0FBQyx1RkFBdUYsRUFBRXhCLE1BQU1tRCxlQUFlLEVBQUU7UUFFbkg7SUFDRDtJQUVBLG9CQUFvQjtJQUNwQixNQUFNQyxTQUFTLE1BQU0vQixNQUNwQixDQUFDLGlEQUFpRCxFQUFFZ0IsYUFBYSxFQUNqRTtRQUNDSyxRQUFRO1FBQ1J2QjtRQUNBd0IsTUFBTUMsS0FBS0MsU0FBUyxDQUFDO1lBQ3BCUSxZQUFZbkQsdUJBQXVCUSxhQUFhRSxlQUFlO1FBQ2hFO0lBQ0Q7SUFFRCxJQUFJd0MsT0FBTzlCLEVBQUUsRUFBRTtRQUNkQyxRQUFRSSxHQUFHLENBQUM7SUFDYixPQUFPO1FBQ05KLFFBQVFDLEtBQUssQ0FBQztJQUNmO0lBRUEscUJBQXFCO0lBQ3JCLE1BQU04QixVQUFpRjtRQUN0RjtZQUFFQyxLQUFLO1lBQVdDLE9BQU87WUFBeUJ4QixNQUFNO1lBQVc1QixTQUFTO1FBQUs7S0FDakY7SUFDRCxJQUFJUSxhQUFhO1FBQ2hCMEMsUUFBUUcsSUFBSSxDQUNYO1lBQ0NGLEtBQUs7WUFDTEMsT0FBTzVDLFlBQVk4QyxhQUFhLENBQUNDLE9BQU8sQ0FBQyxZQUFZO1lBQ3JEM0IsTUFBTTtZQUNONUIsU0FBUztRQUNWLEdBQ0E7WUFBRW1ELEtBQUs7WUFBaUJDLE9BQU81QyxZQUFZZ0QsUUFBUTtZQUFFNUIsTUFBTTtZQUFXNUIsU0FBUztRQUFLLEdBQ3BGO1lBQ0NtRCxLQUFLO1lBQ0xDLE9BQU9SLGVBQWU7WUFDdEJoQixNQUFNO1lBQ041QixTQUFTO1FBQ1Y7SUFFRjtJQUNBLE1BQU15RCxTQUFTLE1BQU14QyxNQUNwQixDQUFDLGtEQUFrRCxFQUFFZ0IsYUFBYSxFQUNsRTtRQUNDSyxRQUFRO1FBQ1J2QjtRQUNBd0IsTUFBTUMsS0FBS0MsU0FBUyxDQUFDO1lBQ3BCaUIsYUFBYTtnQkFBRS9CLE1BQU0sR0FBR3JCLFlBQVksUUFBUSxDQUFDO2dCQUFFcUQsUUFBUVQ7WUFBUTtRQUNoRTtJQUNEO0lBRUQsSUFBSU8sT0FBT3ZDLEVBQUUsRUFBRTtRQUNkQyxRQUFRSSxHQUFHLENBQUM7SUFDYixPQUFPO1FBQ05KLFFBQVFDLEtBQUssQ0FBQztJQUNmO0lBRUEsNkRBQTZEO0lBQzdELE1BQU13QyxTQUFTbEUsS0FBS2EsV0FBVyxXQUFXO0lBQzFDLE1BQU1mLE1BQU1vRSxRQUFRO1FBQUVDLFdBQVc7SUFBSztJQUN0QyxNQUFNcEUsVUFDTEMsS0FBS2tFLFFBQVEsR0FBR3RELFlBQVkseUJBQXlCLENBQUMsR0FDdERQLHVCQUNDLEdBQUdPLFlBQVksUUFBUSxDQUFDLEVBQ3hCRSxjQUNHO1FBQ0FzRCxhQUFhdEQsWUFBWThDLGFBQWEsQ0FBQ0MsT0FBTyxDQUFDLFlBQVk7UUFDM0RRLGVBQWV2RCxZQUFZZ0QsUUFBUTtRQUNuQ1EsZUFBZXBCLGVBQWU7SUFDL0IsSUFDQ3FCO0lBR0w5QyxRQUFRSSxHQUFHLENBQUM7SUFFWixPQUFPdEI7QUFDUjtBQUVBLE9BQU8sTUFBTWlFLGlCQUEwQjtJQUN0Q3ZDLE1BQU07SUFDTjNCO0lBQ0FLO0FBQ0QsRUFBRSJ9
@@ -0,0 +1,56 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { DEVCONTAINER_KEY } from "../../domain/devcontainer.model.js";
4
+ import { CREATE_VERSION } from "../../version.js";
5
+ import { MAIN_TS_KEY } from "../api-core/main-ts.model.js";
6
+ import { POSTGRES_CREDS_KEY } from "../postgresql/models.js";
7
+ import { DATABASE_BASE_CONFIG_YAML, databaseDevConfigYaml, SAMPLE_ENTITY_TS, SAMPLE_REPOSITORY_TS } from "./scaffold-files.template.js";
8
+ const enabled = (ctx)=>ctx.opts.database === "typeorm";
9
+ async function configure(ctx) {
10
+ const mainTs = ctx.models.get(MAIN_TS_KEY);
11
+ if (!mainTs) return ctx;
12
+ mainTs.addImport("@decohere/codex-typeorm").addImport("./entities/sample.entity.js", "SampleEntity").addImport("./repositories/sample.repository.js", "SampleEntityRepository").appendBuilderChain(`.withTypeOrm({ entities: [SampleEntity], repositories: [SampleEntityRepository] })`);
13
+ ctx.models.get(DEVCONTAINER_KEY)?.addExtension("mtxr.sqltools");
14
+ return ctx;
15
+ }
16
+ async function render(ctx) {
17
+ const { targetDir, projectName } = ctx;
18
+ await mkdir(join(targetDir, "projects", "api", "src", "entities"), {
19
+ recursive: true
20
+ });
21
+ await mkdir(join(targetDir, "projects", "api", "src", "repositories"), {
22
+ recursive: true
23
+ });
24
+ await Promise.all([
25
+ writeFile(join(targetDir, "projects", "api", "src", "entities", "sample.entity.ts"), SAMPLE_ENTITY_TS),
26
+ writeFile(join(targetDir, "projects", "api", "src", "repositories", "sample.repository.ts"), SAMPLE_REPOSITORY_TS)
27
+ ]);
28
+ // Patch root package.json — add codex dependencies
29
+ const pkgPath = join(targetDir, "package.json");
30
+ const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
31
+ pkg.dependencies["@decohere/codex"] = CREATE_VERSION;
32
+ pkg.dependencies.typeorm = "^0.3.28";
33
+ pkg.dependencies["@decohere/codex-typeorm"] = CREATE_VERSION;
34
+ await writeFile(pkgPath, JSON.stringify(pkg, null, 2));
35
+ // Append database base section (env-var refs) to config/config.yaml
36
+ const configPath = join(targetDir, "config", "config.yaml");
37
+ const existingConfig = await readFile(configPath, "utf8");
38
+ await writeFile(configPath, existingConfig + DATABASE_BASE_CONFIG_YAML);
39
+ // Append dev overrides (local creds + synchronize:true) to config/config.dev.yaml
40
+ const devConfigPath = join(targetDir, "config", "config.dev.yaml");
41
+ let existingDev = "";
42
+ try {
43
+ existingDev = await readFile(devConfigPath, "utf8");
44
+ } catch {}
45
+ const devFragment = databaseDevConfigYaml(projectName, ctx.models.get(POSTGRES_CREDS_KEY));
46
+ await writeFile(devConfigPath, existingDev ? `${existingDev}\n${devFragment}` : devFragment);
47
+ return ctx;
48
+ }
49
+ export const typeormFeature = {
50
+ name: "typeorm",
51
+ enabled,
52
+ configure,
53
+ render
54
+ };
55
+
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy90eXBlb3JtL2ZlYXR1cmUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgbWtkaXIsIHJlYWRGaWxlLCB3cml0ZUZpbGUgfSBmcm9tIFwibm9kZTpmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IERFVkNPTlRBSU5FUl9LRVkgfSBmcm9tIFwiLi4vLi4vZG9tYWluL2RldmNvbnRhaW5lci5tb2RlbC5qc1wiO1xuaW1wb3J0IHR5cGUgeyBGZWF0dXJlLCBTY2FmZm9sZENvbnRleHQgfSBmcm9tIFwiLi4vLi4vZG9tYWluL2luZGV4LmpzXCI7XG5pbXBvcnQgeyBDUkVBVEVfVkVSU0lPTiB9IGZyb20gXCIuLi8uLi92ZXJzaW9uLmpzXCI7XG5pbXBvcnQgeyBNQUlOX1RTX0tFWSB9IGZyb20gXCIuLi9hcGktY29yZS9tYWluLXRzLm1vZGVsLmpzXCI7XG5pbXBvcnQgeyBQT1NUR1JFU19DUkVEU19LRVkgfSBmcm9tIFwiLi4vcG9zdGdyZXNxbC9tb2RlbHMuanNcIjtcbmltcG9ydCB7XG5cdERBVEFCQVNFX0JBU0VfQ09ORklHX1lBTUwsXG5cdGRhdGFiYXNlRGV2Q29uZmlnWWFtbCxcblx0U0FNUExFX0VOVElUWV9UUyxcblx0U0FNUExFX1JFUE9TSVRPUllfVFMsXG59IGZyb20gXCIuL3NjYWZmb2xkLWZpbGVzLnRlbXBsYXRlLmpzXCI7XG5cbmNvbnN0IGVuYWJsZWQgPSAoY3R4OiBTY2FmZm9sZENvbnRleHQpID0+IGN0eC5vcHRzLmRhdGFiYXNlID09PSBcInR5cGVvcm1cIjtcblxuYXN5bmMgZnVuY3Rpb24gY29uZmlndXJlKGN0eDogU2NhZmZvbGRDb250ZXh0KTogUHJvbWlzZTxTY2FmZm9sZENvbnRleHQ+IHtcblx0Y29uc3QgbWFpblRzID0gY3R4Lm1vZGVscy5nZXQoTUFJTl9UU19LRVkpO1xuXHRpZiAoIW1haW5UcykgcmV0dXJuIGN0eDtcblx0bWFpblRzXG5cdFx0LmFkZEltcG9ydChcIkBkZWNvaGVyZS9jb2RleC10eXBlb3JtXCIpXG5cdFx0LmFkZEltcG9ydChcIi4vZW50aXRpZXMvc2FtcGxlLmVudGl0eS5qc1wiLCBcIlNhbXBsZUVudGl0eVwiKVxuXHRcdC5hZGRJbXBvcnQoXCIuL3JlcG9zaXRvcmllcy9zYW1wbGUucmVwb3NpdG9yeS5qc1wiLCBcIlNhbXBsZUVudGl0eVJlcG9zaXRvcnlcIilcblx0XHQuYXBwZW5kQnVpbGRlckNoYWluKFxuXHRcdFx0YC53aXRoVHlwZU9ybSh7IGVudGl0aWVzOiBbU2FtcGxlRW50aXR5XSwgcmVwb3NpdG9yaWVzOiBbU2FtcGxlRW50aXR5UmVwb3NpdG9yeV0gfSlgLFxuXHRcdCk7XG5cdGN0eC5tb2RlbHMuZ2V0KERFVkNPTlRBSU5FUl9LRVkpPy5hZGRFeHRlbnNpb24oXCJtdHhyLnNxbHRvb2xzXCIpO1xuXHRyZXR1cm4gY3R4O1xufVxuXG5hc3luYyBmdW5jdGlvbiByZW5kZXIoY3R4OiBTY2FmZm9sZENvbnRleHQpOiBQcm9taXNlPFNjYWZmb2xkQ29udGV4dD4ge1xuXHRjb25zdCB7IHRhcmdldERpciwgcHJvamVjdE5hbWUgfSA9IGN0eDtcblxuXHRhd2FpdCBta2Rpcihqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcImVudGl0aWVzXCIpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblx0YXdhaXQgbWtkaXIoam9pbih0YXJnZXREaXIsIFwicHJvamVjdHNcIiwgXCJhcGlcIiwgXCJzcmNcIiwgXCJyZXBvc2l0b3JpZXNcIiksIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuXG5cdGF3YWl0IFByb21pc2UuYWxsKFtcblx0XHR3cml0ZUZpbGUoXG5cdFx0XHRqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcImVudGl0aWVzXCIsIFwic2FtcGxlLmVudGl0eS50c1wiKSxcblx0XHRcdFNBTVBMRV9FTlRJVFlfVFMsXG5cdFx0KSxcblx0XHR3cml0ZUZpbGUoXG5cdFx0XHRqb2luKHRhcmdldERpciwgXCJwcm9qZWN0c1wiLCBcImFwaVwiLCBcInNyY1wiLCBcInJlcG9zaXRvcmllc1wiLCBcInNhbXBsZS5yZXBvc2l0b3J5LnRzXCIpLFxuXHRcdFx0U0FNUExFX1JFUE9TSVRPUllfVFMsXG5cdFx0KSxcblx0XSk7XG5cblx0Ly8gUGF0Y2ggcm9vdCBwYWNrYWdlLmpzb24g4oCUIGFkZCBjb2RleCBkZXBlbmRlbmNpZXNcblx0Y29uc3QgcGtnUGF0aCA9IGpvaW4odGFyZ2V0RGlyLCBcInBhY2thZ2UuanNvblwiKTtcblx0Y29uc3QgcGtnID0gSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZShwa2dQYXRoLCBcInV0ZjhcIikpIGFzIHtcblx0XHRkZXBlbmRlbmNpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cdH07XG5cdHBrZy5kZXBlbmRlbmNpZXNbXCJAZGVjb2hlcmUvY29kZXhcIl0gPSBDUkVBVEVfVkVSU0lPTjtcblx0cGtnLmRlcGVuZGVuY2llcy50eXBlb3JtID0gXCJeMC4zLjI4XCI7XG5cdHBrZy5kZXBlbmRlbmNpZXNbXCJAZGVjb2hlcmUvY29kZXgtdHlwZW9ybVwiXSA9IENSRUFURV9WRVJTSU9OO1xuXHRhd2FpdCB3cml0ZUZpbGUocGtnUGF0aCwgSlNPTi5zdHJpbmdpZnkocGtnLCBudWxsLCAyKSk7XG5cblx0Ly8gQXBwZW5kIGRhdGFiYXNlIGJhc2Ugc2VjdGlvbiAoZW52LXZhciByZWZzKSB0byBjb25maWcvY29uZmlnLnlhbWxcblx0Y29uc3QgY29uZmlnUGF0aCA9IGpvaW4odGFyZ2V0RGlyLCBcImNvbmZpZ1wiLCBcImNvbmZpZy55YW1sXCIpO1xuXHRjb25zdCBleGlzdGluZ0NvbmZpZyA9IGF3YWl0IHJlYWRGaWxlKGNvbmZpZ1BhdGgsIFwidXRmOFwiKTtcblx0YXdhaXQgd3JpdGVGaWxlKGNvbmZpZ1BhdGgsIGV4aXN0aW5nQ29uZmlnICsgREFUQUJBU0VfQkFTRV9DT05GSUdfWUFNTCk7XG5cblx0Ly8gQXBwZW5kIGRldiBvdmVycmlkZXMgKGxvY2FsIGNyZWRzICsgc3luY2hyb25pemU6dHJ1ZSkgdG8gY29uZmlnL2NvbmZpZy5kZXYueWFtbFxuXHRjb25zdCBkZXZDb25maWdQYXRoID0gam9pbih0YXJnZXREaXIsIFwiY29uZmlnXCIsIFwiY29uZmlnLmRldi55YW1sXCIpO1xuXHRsZXQgZXhpc3RpbmdEZXYgPSBcIlwiO1xuXHR0cnkge1xuXHRcdGV4aXN0aW5nRGV2ID0gYXdhaXQgcmVhZEZpbGUoZGV2Q29uZmlnUGF0aCwgXCJ1dGY4XCIpO1xuXHR9IGNhdGNoIHt9XG5cdGNvbnN0IGRldkZyYWdtZW50ID0gZGF0YWJhc2VEZXZDb25maWdZYW1sKHByb2plY3ROYW1lLCBjdHgubW9kZWxzLmdldChQT1NUR1JFU19DUkVEU19LRVkpKTtcblx0YXdhaXQgd3JpdGVGaWxlKGRldkNvbmZpZ1BhdGgsIGV4aXN0aW5nRGV2ID8gYCR7ZXhpc3RpbmdEZXZ9XFxuJHtkZXZGcmFnbWVudH1gIDogZGV2RnJhZ21lbnQpO1xuXG5cdHJldHVybiBjdHg7XG59XG5cbmV4cG9ydCBjb25zdCB0eXBlb3JtRmVhdHVyZTogRmVhdHVyZSA9IHtcblx0bmFtZTogXCJ0eXBlb3JtXCIsXG5cdGVuYWJsZWQsXG5cdGNvbmZpZ3VyZSxcblx0cmVuZGVyLFxufTtcbiJdLCJuYW1lcyI6WyJta2RpciIsInJlYWRGaWxlIiwid3JpdGVGaWxlIiwiam9pbiIsIkRFVkNPTlRBSU5FUl9LRVkiLCJDUkVBVEVfVkVSU0lPTiIsIk1BSU5fVFNfS0VZIiwiUE9TVEdSRVNfQ1JFRFNfS0VZIiwiREFUQUJBU0VfQkFTRV9DT05GSUdfWUFNTCIsImRhdGFiYXNlRGV2Q29uZmlnWWFtbCIsIlNBTVBMRV9FTlRJVFlfVFMiLCJTQU1QTEVfUkVQT1NJVE9SWV9UUyIsImVuYWJsZWQiLCJjdHgiLCJvcHRzIiwiZGF0YWJhc2UiLCJjb25maWd1cmUiLCJtYWluVHMiLCJtb2RlbHMiLCJnZXQiLCJhZGRJbXBvcnQiLCJhcHBlbmRCdWlsZGVyQ2hhaW4iLCJhZGRFeHRlbnNpb24iLCJyZW5kZXIiLCJ0YXJnZXREaXIiLCJwcm9qZWN0TmFtZSIsInJlY3Vyc2l2ZSIsIlByb21pc2UiLCJhbGwiLCJwa2dQYXRoIiwicGtnIiwiSlNPTiIsInBhcnNlIiwiZGVwZW5kZW5jaWVzIiwidHlwZW9ybSIsInN0cmluZ2lmeSIsImNvbmZpZ1BhdGgiLCJleGlzdGluZ0NvbmZpZyIsImRldkNvbmZpZ1BhdGgiLCJleGlzdGluZ0RldiIsImRldkZyYWdtZW50IiwidHlwZW9ybUZlYXR1cmUiLCJuYW1lIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxLQUFLLEVBQUVDLFFBQVEsRUFBRUMsU0FBUyxRQUFRLG1CQUFtQjtBQUM5RCxTQUFTQyxJQUFJLFFBQVEsWUFBWTtBQUNqQyxTQUFTQyxnQkFBZ0IsUUFBUSxxQ0FBcUM7QUFFdEUsU0FBU0MsY0FBYyxRQUFRLG1CQUFtQjtBQUNsRCxTQUFTQyxXQUFXLFFBQVEsK0JBQStCO0FBQzNELFNBQVNDLGtCQUFrQixRQUFRLDBCQUEwQjtBQUM3RCxTQUNDQyx5QkFBeUIsRUFDekJDLHFCQUFxQixFQUNyQkMsZ0JBQWdCLEVBQ2hCQyxvQkFBb0IsUUFDZCwrQkFBK0I7QUFFdEMsTUFBTUMsVUFBVSxDQUFDQyxNQUF5QkEsSUFBSUMsSUFBSSxDQUFDQyxRQUFRLEtBQUs7QUFFaEUsZUFBZUMsVUFBVUgsR0FBb0I7SUFDNUMsTUFBTUksU0FBU0osSUFBSUssTUFBTSxDQUFDQyxHQUFHLENBQUNiO0lBQzlCLElBQUksQ0FBQ1csUUFBUSxPQUFPSjtJQUNwQkksT0FDRUcsU0FBUyxDQUFDLDJCQUNWQSxTQUFTLENBQUMsK0JBQStCLGdCQUN6Q0EsU0FBUyxDQUFDLHVDQUF1QywwQkFDakRDLGtCQUFrQixDQUNsQixDQUFDLGtGQUFrRixDQUFDO0lBRXRGUixJQUFJSyxNQUFNLENBQUNDLEdBQUcsQ0FBQ2YsbUJBQW1Ca0IsYUFBYTtJQUMvQyxPQUFPVDtBQUNSO0FBRUEsZUFBZVUsT0FBT1YsR0FBb0I7SUFDekMsTUFBTSxFQUFFVyxTQUFTLEVBQUVDLFdBQVcsRUFBRSxHQUFHWjtJQUVuQyxNQUFNYixNQUFNRyxLQUFLcUIsV0FBVyxZQUFZLE9BQU8sT0FBTyxhQUFhO1FBQUVFLFdBQVc7SUFBSztJQUNyRixNQUFNMUIsTUFBTUcsS0FBS3FCLFdBQVcsWUFBWSxPQUFPLE9BQU8saUJBQWlCO1FBQUVFLFdBQVc7SUFBSztJQUV6RixNQUFNQyxRQUFRQyxHQUFHLENBQUM7UUFDakIxQixVQUNDQyxLQUFLcUIsV0FBVyxZQUFZLE9BQU8sT0FBTyxZQUFZLHFCQUN0RGQ7UUFFRFIsVUFDQ0MsS0FBS3FCLFdBQVcsWUFBWSxPQUFPLE9BQU8sZ0JBQWdCLHlCQUMxRGI7S0FFRDtJQUVELG1EQUFtRDtJQUNuRCxNQUFNa0IsVUFBVTFCLEtBQUtxQixXQUFXO0lBQ2hDLE1BQU1NLE1BQU1DLEtBQUtDLEtBQUssQ0FBQyxNQUFNL0IsU0FBUzRCLFNBQVM7SUFHL0NDLElBQUlHLFlBQVksQ0FBQyxrQkFBa0IsR0FBRzVCO0lBQ3RDeUIsSUFBSUcsWUFBWSxDQUFDQyxPQUFPLEdBQUc7SUFDM0JKLElBQUlHLFlBQVksQ0FBQywwQkFBMEIsR0FBRzVCO0lBQzlDLE1BQU1ILFVBQVUyQixTQUFTRSxLQUFLSSxTQUFTLENBQUNMLEtBQUssTUFBTTtJQUVuRCxvRUFBb0U7SUFDcEUsTUFBTU0sYUFBYWpDLEtBQUtxQixXQUFXLFVBQVU7SUFDN0MsTUFBTWEsaUJBQWlCLE1BQU1wQyxTQUFTbUMsWUFBWTtJQUNsRCxNQUFNbEMsVUFBVWtDLFlBQVlDLGlCQUFpQjdCO0lBRTdDLGtGQUFrRjtJQUNsRixNQUFNOEIsZ0JBQWdCbkMsS0FBS3FCLFdBQVcsVUFBVTtJQUNoRCxJQUFJZSxjQUFjO0lBQ2xCLElBQUk7UUFDSEEsY0FBYyxNQUFNdEMsU0FBU3FDLGVBQWU7SUFDN0MsRUFBRSxPQUFNLENBQUM7SUFDVCxNQUFNRSxjQUFjL0Isc0JBQXNCZ0IsYUFBYVosSUFBSUssTUFBTSxDQUFDQyxHQUFHLENBQUNaO0lBQ3RFLE1BQU1MLFVBQVVvQyxlQUFlQyxjQUFjLEdBQUdBLFlBQVksRUFBRSxFQUFFQyxhQUFhLEdBQUdBO0lBRWhGLE9BQU8zQjtBQUNSO0FBRUEsT0FBTyxNQUFNNEIsaUJBQTBCO0lBQ3RDQyxNQUFNO0lBQ045QjtJQUNBSTtJQUNBTztBQUNELEVBQUUifQ==
@@ -0,0 +1,56 @@
1
+ export const SAMPLE_ENTITY_TS = `import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
2
+ import type { Entity as IEntity } from "@decohere/codex";
3
+
4
+ @Entity()
5
+ export class SampleEntity implements IEntity {
6
+ \t@PrimaryGeneratedColumn()
7
+ \tpublic id!: number;
8
+
9
+ \t@Column()
10
+ \tpublic name!: string;
11
+ }
12
+ `;
13
+ export const SAMPLE_REPOSITORY_TS = `import { injectable } from "@decohere/crucible/decorators";
14
+ import { injectUnitOfWork } from "@decohere/codex";
15
+ import { TypeOrmRepository, TypeOrmUnitOfWork } from "@decohere/codex-typeorm";
16
+ import { SampleEntity } from "../entities/sample.entity.js";
17
+
18
+ @injectable()
19
+ export class SampleEntityRepository extends TypeOrmRepository<SampleEntity> {
20
+ \tpublic constructor(@injectUnitOfWork() unitOfWork: TypeOrmUnitOfWork) {
21
+ \t\tsuper(unitOfWork, SampleEntity);
22
+ \t}
23
+ }
24
+ `;
25
+ export function databaseDevConfigYaml(name, creds) {
26
+ const db = creds?.db ?? `${name}_dev`;
27
+ const user = creds?.user ?? "postgres";
28
+ const password = creds?.password ?? "postgres";
29
+ return `database:
30
+ dataSources:
31
+ - host: localhost
32
+ port: 5432
33
+ database: ${db}
34
+ username: ${user}
35
+ password: ${password}
36
+ synchronize: true
37
+ adminUser: ${user}
38
+ adminPassword: ${password}
39
+ `;
40
+ }
41
+ export const DATABASE_BASE_CONFIG_YAML = `database:
42
+ dataSources:
43
+ - name: default
44
+ provider: postgres
45
+ host: \${DB_HOST}
46
+ port: \${DB_PORT}
47
+ database: \${DB_NAME}
48
+ username: \${DB_USER}
49
+ password: \${DB_PASSWORD}
50
+ synchronize: false
51
+ seed: false
52
+ adminUser: \${DB_ADMIN_USER}
53
+ adminPassword: \${DB_ADMIN_PASSWORD}
54
+ `;
55
+
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9mZWF0dXJlcy90eXBlb3JtL3NjYWZmb2xkLWZpbGVzLnRlbXBsYXRlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBjb25zdCBTQU1QTEVfRU5USVRZX1RTID0gYGltcG9ydCB7IENvbHVtbiwgRW50aXR5LCBQcmltYXJ5R2VuZXJhdGVkQ29sdW1uIH0gZnJvbSBcInR5cGVvcm1cIjtcbmltcG9ydCB0eXBlIHsgRW50aXR5IGFzIElFbnRpdHkgfSBmcm9tIFwiQGRlY29oZXJlL2NvZGV4XCI7XG5cbkBFbnRpdHkoKVxuZXhwb3J0IGNsYXNzIFNhbXBsZUVudGl0eSBpbXBsZW1lbnRzIElFbnRpdHkge1xuXFx0QFByaW1hcnlHZW5lcmF0ZWRDb2x1bW4oKVxuXFx0cHVibGljIGlkITogbnVtYmVyO1xuXG5cXHRAQ29sdW1uKClcblxcdHB1YmxpYyBuYW1lITogc3RyaW5nO1xufVxuYDtcblxuZXhwb3J0IGNvbnN0IFNBTVBMRV9SRVBPU0lUT1JZX1RTID0gYGltcG9ydCB7IGluamVjdGFibGUgfSBmcm9tIFwiQGRlY29oZXJlL2NydWNpYmxlL2RlY29yYXRvcnNcIjtcbmltcG9ydCB7IGluamVjdFVuaXRPZldvcmsgfSBmcm9tIFwiQGRlY29oZXJlL2NvZGV4XCI7XG5pbXBvcnQgeyBUeXBlT3JtUmVwb3NpdG9yeSwgVHlwZU9ybVVuaXRPZldvcmsgfSBmcm9tIFwiQGRlY29oZXJlL2NvZGV4LXR5cGVvcm1cIjtcbmltcG9ydCB7IFNhbXBsZUVudGl0eSB9IGZyb20gXCIuLi9lbnRpdGllcy9zYW1wbGUuZW50aXR5LmpzXCI7XG5cbkBpbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBTYW1wbGVFbnRpdHlSZXBvc2l0b3J5IGV4dGVuZHMgVHlwZU9ybVJlcG9zaXRvcnk8U2FtcGxlRW50aXR5PiB7XG5cXHRwdWJsaWMgY29uc3RydWN0b3IoQGluamVjdFVuaXRPZldvcmsoKSB1bml0T2ZXb3JrOiBUeXBlT3JtVW5pdE9mV29yaykge1xuXFx0XFx0c3VwZXIodW5pdE9mV29yaywgU2FtcGxlRW50aXR5KTtcblxcdH1cbn1cbmA7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGJEZXZDcmVkcyB7XG5cdGRiPzogc3RyaW5nO1xuXHR1c2VyPzogc3RyaW5nO1xuXHRwYXNzd29yZD86IHN0cmluZztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRhdGFiYXNlRGV2Q29uZmlnWWFtbChuYW1lOiBzdHJpbmcsIGNyZWRzPzogRGJEZXZDcmVkcyk6IHN0cmluZyB7XG5cdGNvbnN0IGRiID0gY3JlZHM/LmRiID8/IGAke25hbWV9X2RldmA7XG5cdGNvbnN0IHVzZXIgPSBjcmVkcz8udXNlciA/PyBcInBvc3RncmVzXCI7XG5cdGNvbnN0IHBhc3N3b3JkID0gY3JlZHM/LnBhc3N3b3JkID8/IFwicG9zdGdyZXNcIjtcblx0cmV0dXJuIGBkYXRhYmFzZTpcbiAgZGF0YVNvdXJjZXM6XG4gICAgLSBob3N0OiBsb2NhbGhvc3RcbiAgICAgIHBvcnQ6IDU0MzJcbiAgICAgIGRhdGFiYXNlOiAke2RifVxuICAgICAgdXNlcm5hbWU6ICR7dXNlcn1cbiAgICAgIHBhc3N3b3JkOiAke3Bhc3N3b3JkfVxuICAgICAgc3luY2hyb25pemU6IHRydWVcbiAgICAgIGFkbWluVXNlcjogJHt1c2VyfVxuICAgICAgYWRtaW5QYXNzd29yZDogJHtwYXNzd29yZH1cbmA7XG59XG5cbmV4cG9ydCBjb25zdCBEQVRBQkFTRV9CQVNFX0NPTkZJR19ZQU1MID0gYGRhdGFiYXNlOlxuICBkYXRhU291cmNlczpcbiAgICAtIG5hbWU6IGRlZmF1bHRcbiAgICAgIHByb3ZpZGVyOiBwb3N0Z3Jlc1xuICAgICAgaG9zdDogXFwke0RCX0hPU1R9XG4gICAgICBwb3J0OiBcXCR7REJfUE9SVH1cbiAgICAgIGRhdGFiYXNlOiBcXCR7REJfTkFNRX1cbiAgICAgIHVzZXJuYW1lOiBcXCR7REJfVVNFUn1cbiAgICAgIHBhc3N3b3JkOiBcXCR7REJfUEFTU1dPUkR9XG4gICAgICBzeW5jaHJvbml6ZTogZmFsc2VcbiAgICAgIHNlZWQ6IGZhbHNlXG4gICAgICBhZG1pblVzZXI6IFxcJHtEQl9BRE1JTl9VU0VSfVxuICAgICAgYWRtaW5QYXNzd29yZDogXFwke0RCX0FETUlOX1BBU1NXT1JEfVxuYDtcbiJdLCJuYW1lcyI6WyJTQU1QTEVfRU5USVRZX1RTIiwiU0FNUExFX1JFUE9TSVRPUllfVFMiLCJkYXRhYmFzZURldkNvbmZpZ1lhbWwiLCJuYW1lIiwiY3JlZHMiLCJkYiIsInVzZXIiLCJwYXNzd29yZCIsIkRBVEFCQVNFX0JBU0VfQ09ORklHX1lBTUwiXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sTUFBTUEsbUJBQW1CLENBQUM7Ozs7Ozs7Ozs7O0FBV2pDLENBQUMsQ0FBQztBQUVGLE9BQU8sTUFBTUMsdUJBQXVCLENBQUM7Ozs7Ozs7Ozs7O0FBV3JDLENBQUMsQ0FBQztBQVFGLE9BQU8sU0FBU0Msc0JBQXNCQyxJQUFZLEVBQUVDLEtBQWtCO0lBQ3JFLE1BQU1DLEtBQUtELE9BQU9DLE1BQU0sR0FBR0YsS0FBSyxJQUFJLENBQUM7SUFDckMsTUFBTUcsT0FBT0YsT0FBT0UsUUFBUTtJQUM1QixNQUFNQyxXQUFXSCxPQUFPRyxZQUFZO0lBQ3BDLE9BQU8sQ0FBQzs7OztnQkFJTyxFQUFFRixHQUFHO2dCQUNMLEVBQUVDLEtBQUs7Z0JBQ1AsRUFBRUMsU0FBUzs7aUJBRVYsRUFBRUQsS0FBSztxQkFDSCxFQUFFQyxTQUFTO0FBQ2hDLENBQUM7QUFDRDtBQUVBLE9BQU8sTUFBTUMsNEJBQTRCLENBQUM7Ozs7Ozs7Ozs7Ozs7QUFhMUMsQ0FBQyxDQUFDIn0=
@@ -0,0 +1,40 @@
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { basename } from "node:path";
3
+ import { ask, createContext, runWorkflow } from "./domain/index.js";
4
+ import { apiWorkflow } from "./workflows/api.js";
5
+ import { cliWorkflow } from "./workflows/cli.js";
6
+ const WORKFLOWS = {
7
+ api: apiWorkflow,
8
+ cli: cliWorkflow
9
+ };
10
+ const TEMPLATE_ALIASES = {
11
+ webapi: "api"
12
+ };
13
+ async function resolveTemplate(_targetDir, opts) {
14
+ if (opts.yes || opts.template != null) {
15
+ const raw = opts.template ?? "api";
16
+ const key = TEMPLATE_ALIASES[raw] ?? raw;
17
+ if (!(key in WORKFLOWS)) {
18
+ console.error(`Unknown template "${raw}". Valid options: ${Object.keys(WORKFLOWS).join(", ")}.`);
19
+ process.exit(1);
20
+ }
21
+ return key;
22
+ }
23
+ const answer = await ask("Template? [api/cli] (api): ", "api");
24
+ return answer.toLowerCase() === "cli" ? "cli" : "api";
25
+ }
26
+ export async function scaffold(targetDir, opts) {
27
+ if (!opts.yes && existsSync(targetDir) && readdirSync(targetDir).length > 0) {
28
+ const name = basename(targetDir);
29
+ const answer = await ask(`Directory "${name}" is not empty. Continue? [y/N] `);
30
+ if (!answer.toLowerCase().startsWith("y")) {
31
+ console.log("Aborted.");
32
+ process.exit(0);
33
+ }
34
+ }
35
+ const template = await resolveTemplate(targetDir, opts);
36
+ const ctx = createContext(targetDir, opts, template);
37
+ await runWorkflow(WORKFLOWS[template], ctx);
38
+ }
39
+
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS9zY2FmZm9sZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkZGlyU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGFzaywgY3JlYXRlQ29udGV4dCwgcnVuV29ya2Zsb3csIHR5cGUgU2NhZmZvbGRPcHRpb25zIH0gZnJvbSBcIi4vZG9tYWluL2luZGV4LmpzXCI7XG5pbXBvcnQgeyBhcGlXb3JrZmxvdyB9IGZyb20gXCIuL3dvcmtmbG93cy9hcGkuanNcIjtcbmltcG9ydCB7IGNsaVdvcmtmbG93IH0gZnJvbSBcIi4vd29ya2Zsb3dzL2NsaS5qc1wiO1xuXG5leHBvcnQgdHlwZSB7IFNjYWZmb2xkT3B0aW9ucyB9O1xuXG5jb25zdCBXT1JLRkxPV1MgPSB7XG5cdGFwaTogYXBpV29ya2Zsb3csXG5cdGNsaTogY2xpV29ya2Zsb3csXG59IGFzIGNvbnN0O1xuXG50eXBlIFRlbXBsYXRlS2V5ID0ga2V5b2YgdHlwZW9mIFdPUktGTE9XUztcblxuY29uc3QgVEVNUExBVEVfQUxJQVNFUzogUmVjb3JkPHN0cmluZywgVGVtcGxhdGVLZXk+ID0ge1xuXHR3ZWJhcGk6IFwiYXBpXCIsXG59O1xuXG5hc3luYyBmdW5jdGlvbiByZXNvbHZlVGVtcGxhdGUoXG5cdF90YXJnZXREaXI6IHN0cmluZyxcblx0b3B0czogU2NhZmZvbGRPcHRpb25zLFxuKTogUHJvbWlzZTxUZW1wbGF0ZUtleT4ge1xuXHRpZiAob3B0cy55ZXMgfHwgb3B0cy50ZW1wbGF0ZSAhPSBudWxsKSB7XG5cdFx0Y29uc3QgcmF3ID0gb3B0cy50ZW1wbGF0ZSA/PyBcImFwaVwiO1xuXHRcdGNvbnN0IGtleSA9IChURU1QTEFURV9BTElBU0VTW3Jhd10gPz8gcmF3KSBhcyBUZW1wbGF0ZUtleTtcblx0XHRpZiAoIShrZXkgaW4gV09SS0ZMT1dTKSkge1xuXHRcdFx0Y29uc29sZS5lcnJvcihcblx0XHRcdFx0YFVua25vd24gdGVtcGxhdGUgXCIke3Jhd31cIi4gVmFsaWQgb3B0aW9uczogJHtPYmplY3Qua2V5cyhXT1JLRkxPV1MpLmpvaW4oXCIsIFwiKX0uYCxcblx0XHRcdCk7XG5cdFx0XHRwcm9jZXNzLmV4aXQoMSk7XG5cdFx0fVxuXHRcdHJldHVybiBrZXk7XG5cdH1cblxuXHRjb25zdCBhbnN3ZXIgPSBhd2FpdCBhc2soXCJUZW1wbGF0ZT8gW2FwaS9jbGldIChhcGkpOiBcIiwgXCJhcGlcIik7XG5cdHJldHVybiBhbnN3ZXIudG9Mb3dlckNhc2UoKSA9PT0gXCJjbGlcIiA/IFwiY2xpXCIgOiBcImFwaVwiO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2NhZmZvbGQodGFyZ2V0RGlyOiBzdHJpbmcsIG9wdHM6IFNjYWZmb2xkT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuXHRpZiAoIW9wdHMueWVzICYmIGV4aXN0c1N5bmModGFyZ2V0RGlyKSAmJiByZWFkZGlyU3luYyh0YXJnZXREaXIpLmxlbmd0aCA+IDApIHtcblx0XHRjb25zdCBuYW1lID0gYmFzZW5hbWUodGFyZ2V0RGlyKTtcblx0XHRjb25zdCBhbnN3ZXIgPSBhd2FpdCBhc2soYERpcmVjdG9yeSBcIiR7bmFtZX1cIiBpcyBub3QgZW1wdHkuIENvbnRpbnVlPyBbeS9OXSBgKTtcblx0XHRpZiAoIWFuc3dlci50b0xvd2VyQ2FzZSgpLnN0YXJ0c1dpdGgoXCJ5XCIpKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIkFib3J0ZWQuXCIpO1xuXHRcdFx0cHJvY2Vzcy5leGl0KDApO1xuXHRcdH1cblx0fVxuXG5cdGNvbnN0IHRlbXBsYXRlID0gYXdhaXQgcmVzb2x2ZVRlbXBsYXRlKHRhcmdldERpciwgb3B0cyk7XG5cdGNvbnN0IGN0eCA9IGNyZWF0ZUNvbnRleHQodGFyZ2V0RGlyLCBvcHRzLCB0ZW1wbGF0ZSk7XG5cdGF3YWl0IHJ1bldvcmtmbG93KFdPUktGTE9XU1t0ZW1wbGF0ZV0sIGN0eCk7XG59XG4iXSwibmFtZXMiOlsiZXhpc3RzU3luYyIsInJlYWRkaXJTeW5jIiwiYmFzZW5hbWUiLCJhc2siLCJjcmVhdGVDb250ZXh0IiwicnVuV29ya2Zsb3ciLCJhcGlXb3JrZmxvdyIsImNsaVdvcmtmbG93IiwiV09SS0ZMT1dTIiwiYXBpIiwiY2xpIiwiVEVNUExBVEVfQUxJQVNFUyIsIndlYmFwaSIsInJlc29sdmVUZW1wbGF0ZSIsIl90YXJnZXREaXIiLCJvcHRzIiwieWVzIiwidGVtcGxhdGUiLCJyYXciLCJrZXkiLCJjb25zb2xlIiwiZXJyb3IiLCJPYmplY3QiLCJrZXlzIiwiam9pbiIsInByb2Nlc3MiLCJleGl0IiwiYW5zd2VyIiwidG9Mb3dlckNhc2UiLCJzY2FmZm9sZCIsInRhcmdldERpciIsImxlbmd0aCIsIm5hbWUiLCJzdGFydHNXaXRoIiwibG9nIiwiY3R4Il0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxVQUFVLEVBQUVDLFdBQVcsUUFBUSxVQUFVO0FBQ2xELFNBQVNDLFFBQVEsUUFBUSxZQUFZO0FBQ3JDLFNBQVNDLEdBQUcsRUFBRUMsYUFBYSxFQUFFQyxXQUFXLFFBQThCLG9CQUFvQjtBQUMxRixTQUFTQyxXQUFXLFFBQVEscUJBQXFCO0FBQ2pELFNBQVNDLFdBQVcsUUFBUSxxQkFBcUI7QUFJakQsTUFBTUMsWUFBWTtJQUNqQkMsS0FBS0g7SUFDTEksS0FBS0g7QUFDTjtBQUlBLE1BQU1JLG1CQUFnRDtJQUNyREMsUUFBUTtBQUNUO0FBRUEsZUFBZUMsZ0JBQ2RDLFVBQWtCLEVBQ2xCQyxJQUFxQjtJQUVyQixJQUFJQSxLQUFLQyxHQUFHLElBQUlELEtBQUtFLFFBQVEsSUFBSSxNQUFNO1FBQ3RDLE1BQU1DLE1BQU1ILEtBQUtFLFFBQVEsSUFBSTtRQUM3QixNQUFNRSxNQUFPUixnQkFBZ0IsQ0FBQ08sSUFBSSxJQUFJQTtRQUN0QyxJQUFJLENBQUVDLENBQUFBLE9BQU9YLFNBQVEsR0FBSTtZQUN4QlksUUFBUUMsS0FBSyxDQUNaLENBQUMsa0JBQWtCLEVBQUVILElBQUksa0JBQWtCLEVBQUVJLE9BQU9DLElBQUksQ0FBQ2YsV0FBV2dCLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUVsRkMsUUFBUUMsSUFBSSxDQUFDO1FBQ2Q7UUFDQSxPQUFPUDtJQUNSO0lBRUEsTUFBTVEsU0FBUyxNQUFNeEIsSUFBSSwrQkFBK0I7SUFDeEQsT0FBT3dCLE9BQU9DLFdBQVcsT0FBTyxRQUFRLFFBQVE7QUFDakQ7QUFFQSxPQUFPLGVBQWVDLFNBQVNDLFNBQWlCLEVBQUVmLElBQXFCO0lBQ3RFLElBQUksQ0FBQ0EsS0FBS0MsR0FBRyxJQUFJaEIsV0FBVzhCLGNBQWM3QixZQUFZNkIsV0FBV0MsTUFBTSxHQUFHLEdBQUc7UUFDNUUsTUFBTUMsT0FBTzlCLFNBQVM0QjtRQUN0QixNQUFNSCxTQUFTLE1BQU14QixJQUFJLENBQUMsV0FBVyxFQUFFNkIsS0FBSyxnQ0FBZ0MsQ0FBQztRQUM3RSxJQUFJLENBQUNMLE9BQU9DLFdBQVcsR0FBR0ssVUFBVSxDQUFDLE1BQU07WUFDMUNiLFFBQVFjLEdBQUcsQ0FBQztZQUNaVCxRQUFRQyxJQUFJLENBQUM7UUFDZDtJQUNEO0lBRUEsTUFBTVQsV0FBVyxNQUFNSixnQkFBZ0JpQixXQUFXZjtJQUNsRCxNQUFNb0IsTUFBTS9CLGNBQWMwQixXQUFXZixNQUFNRTtJQUMzQyxNQUFNWixZQUFZRyxTQUFTLENBQUNTLFNBQVMsRUFBRWtCO0FBQ3hDIn0=
@@ -0,0 +1,22 @@
1
+ import { createRequire } from "node:module";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const _require = createRequire(import.meta.url);
5
+ function resolveCreateVersion() {
6
+ let dir = dirname(fileURLToPath(import.meta.url));
7
+ for(let i = 0; i < 5; i++){
8
+ try {
9
+ const pkg = _require(join(dir, "package.json"));
10
+ if (pkg.name === "@decohere/create") {
11
+ return pkg.version ?? "0.0.1-dev";
12
+ }
13
+ } catch {}
14
+ const parent = dirname(dir);
15
+ if (parent === dir) break;
16
+ dir = parent;
17
+ }
18
+ return "0.0.1-dev";
19
+ }
20
+ /** Version of @decohere/create, used to pin scaffolded @decohere/* dependencies. */ export const CREATE_VERSION = resolveCreateVersion();
21
+
22
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3J1bm5lci93b3JrL2RlY29oZXJlL2RlY29oZXJlL3Byb2plY3RzL2NyZWF0ZS92MS92ZXJzaW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZVJlcXVpcmUgfSBmcm9tIFwibm9kZTptb2R1bGVcIjtcbmltcG9ydCB7IGRpcm5hbWUsIGpvaW4gfSBmcm9tIFwibm9kZTpwYXRoXCI7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSBcIm5vZGU6dXJsXCI7XG5cbmNvbnN0IF9yZXF1aXJlID0gY3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpO1xuXG5mdW5jdGlvbiByZXNvbHZlQ3JlYXRlVmVyc2lvbigpOiBzdHJpbmcge1xuXHRsZXQgZGlyID0gZGlybmFtZShmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCkpO1xuXHRmb3IgKGxldCBpID0gMDsgaSA8IDU7IGkrKykge1xuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCBwa2cgPSBfcmVxdWlyZShqb2luKGRpciwgXCJwYWNrYWdlLmpzb25cIikpIGFzIHtcblx0XHRcdFx0bmFtZT86IHN0cmluZztcblx0XHRcdFx0dmVyc2lvbj86IHN0cmluZztcblx0XHRcdH07XG5cdFx0XHRpZiAocGtnLm5hbWUgPT09IFwiQGRlY29oZXJlL2NyZWF0ZVwiKSB7XG5cdFx0XHRcdHJldHVybiBwa2cudmVyc2lvbiA/PyBcIjAuMC4xLWRldlwiO1xuXHRcdFx0fVxuXHRcdH0gY2F0Y2gge31cblx0XHRjb25zdCBwYXJlbnQgPSBkaXJuYW1lKGRpcik7XG5cdFx0aWYgKHBhcmVudCA9PT0gZGlyKSBicmVhaztcblx0XHRkaXIgPSBwYXJlbnQ7XG5cdH1cblx0cmV0dXJuIFwiMC4wLjEtZGV2XCI7XG59XG5cbi8qKiBWZXJzaW9uIG9mIEBkZWNvaGVyZS9jcmVhdGUsIHVzZWQgdG8gcGluIHNjYWZmb2xkZWQgQGRlY29oZXJlLyogZGVwZW5kZW5jaWVzLiAqL1xuZXhwb3J0IGNvbnN0IENSRUFURV9WRVJTSU9OID0gcmVzb2x2ZUNyZWF0ZVZlcnNpb24oKTtcbiJdLCJuYW1lcyI6WyJjcmVhdGVSZXF1aXJlIiwiZGlybmFtZSIsImpvaW4iLCJmaWxlVVJMVG9QYXRoIiwiX3JlcXVpcmUiLCJ1cmwiLCJyZXNvbHZlQ3JlYXRlVmVyc2lvbiIsImRpciIsImkiLCJwa2ciLCJuYW1lIiwidmVyc2lvbiIsInBhcmVudCIsIkNSRUFURV9WRVJTSU9OIl0sIm1hcHBpbmdzIjoiQUFBQSxTQUFTQSxhQUFhLFFBQVEsY0FBYztBQUM1QyxTQUFTQyxPQUFPLEVBQUVDLElBQUksUUFBUSxZQUFZO0FBQzFDLFNBQVNDLGFBQWEsUUFBUSxXQUFXO0FBRXpDLE1BQU1DLFdBQVdKLGNBQWMsWUFBWUssR0FBRztBQUU5QyxTQUFTQztJQUNSLElBQUlDLE1BQU1OLFFBQVFFLGNBQWMsWUFBWUUsR0FBRztJQUMvQyxJQUFLLElBQUlHLElBQUksR0FBR0EsSUFBSSxHQUFHQSxJQUFLO1FBQzNCLElBQUk7WUFDSCxNQUFNQyxNQUFNTCxTQUFTRixLQUFLSyxLQUFLO1lBSS9CLElBQUlFLElBQUlDLElBQUksS0FBSyxvQkFBb0I7Z0JBQ3BDLE9BQU9ELElBQUlFLE9BQU8sSUFBSTtZQUN2QjtRQUNELEVBQUUsT0FBTSxDQUFDO1FBQ1QsTUFBTUMsU0FBU1gsUUFBUU07UUFDdkIsSUFBSUssV0FBV0wsS0FBSztRQUNwQkEsTUFBTUs7SUFDUDtJQUNBLE9BQU87QUFDUjtBQUVBLGtGQUFrRixHQUNsRixPQUFPLE1BQU1DLGlCQUFpQlAsdUJBQXVCIn0=