@quadnix/octo-build 0.0.17 → 0.2.0

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 (195) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +117 -8
  3. package/dist/commands/apply/apply.command.d.ts +25 -0
  4. package/dist/commands/apply/apply.command.js +130 -0
  5. package/dist/commands/apply/apply.command.js.map +1 -0
  6. package/dist/commands/apply/index.d.ts +1 -0
  7. package/dist/commands/apply/index.js +2 -0
  8. package/dist/commands/apply/index.js.map +1 -0
  9. package/dist/commands/build/build.command.d.ts +1 -1
  10. package/dist/commands/build/build.command.js +4 -4
  11. package/dist/commands/build/build.command.js.map +1 -1
  12. package/dist/commands/build/main.d.ts +22 -0
  13. package/dist/commands/build/main.js +22 -0
  14. package/dist/commands/build/main.js.map +1 -1
  15. package/dist/commands/build/parsers/build-file.parser.d.ts +6 -0
  16. package/dist/commands/build/parsers/build-file.parser.js +6 -0
  17. package/dist/commands/build/parsers/build-file.parser.js.map +1 -1
  18. package/dist/commands/build/streams/stream-manager.d.ts +6 -0
  19. package/dist/commands/build/streams/stream-manager.js +7 -1
  20. package/dist/commands/build/streams/stream-manager.js.map +1 -1
  21. package/dist/commands/commit/commit.command.d.ts +23 -0
  22. package/dist/commands/commit/commit.command.js +81 -0
  23. package/dist/commands/commit/commit.command.js.map +1 -0
  24. package/dist/commands/commit/index.d.ts +1 -0
  25. package/dist/commands/commit/index.js +2 -0
  26. package/dist/commands/commit/index.js.map +1 -0
  27. package/dist/commands/create-anchor/create-anchor.command.js +1 -1
  28. package/dist/commands/create-anchor/create-anchor.command.js.map +1 -1
  29. package/dist/commands/create-anchor/generator-octo-anchor-template/generators/app/index.d.ts +18 -3
  30. package/dist/commands/create-anchor/generator-octo-anchor-template/generators/app/index.js +29 -11
  31. package/dist/commands/create-anchor/generator-octo-anchor-template/generators/app/index.js.map +1 -1
  32. package/dist/commands/create-anchor/generator-octo-anchor-template/generators/app/templates/anchors/anchor/anchor.schema.ts.ejs +9 -1
  33. package/dist/commands/create-app/create-app.command.d.ts +1 -1
  34. package/dist/commands/create-app/create-app.command.js +7 -3
  35. package/dist/commands/create-app/create-app.command.js.map +1 -1
  36. package/dist/commands/create-app/generator-octo-app-template/generators/app/index.d.ts +17 -1
  37. package/dist/commands/create-app/generator-octo-app-template/generators/app/index.js +72 -16
  38. package/dist/commands/create-app/generator-octo-app-template/generators/app/index.js.map +1 -1
  39. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/README.md.ejs +73 -14
  40. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/gitignore.ejs +14 -0
  41. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/index.ts.ejs +19 -0
  42. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/package.json.ejs +9 -1
  43. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/src/aws-dynamodb-service/octo.yaml.ejs +111 -0
  44. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/src/aws-ecs-server/octo.yaml.ejs +28 -16
  45. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/src/aws-s3-website/octo.yaml.ejs +25 -3
  46. package/dist/commands/create-app/generator-octo-app-template/generators/app/templates/tsconfig.json.ejs +0 -3
  47. package/dist/commands/{create-resource/create-resource.command.d.ts → create-external-resource/create-external-resource.command.d.ts} +1 -1
  48. package/dist/commands/create-external-resource/create-external-resource.command.js +64 -0
  49. package/dist/commands/create-external-resource/create-external-resource.command.js.map +1 -0
  50. package/dist/commands/{create-resource/generator-octo-resource-template → create-external-resource/generator-octo-external-resource-template}/generators/app/index.d.ts +17 -2
  51. package/dist/commands/{create-resource/generator-octo-resource-template → create-external-resource/generator-octo-external-resource-template}/generators/app/index.js +36 -35
  52. package/dist/commands/create-external-resource/generator-octo-external-resource-template/generators/app/index.js.map +1 -0
  53. package/dist/commands/{create-resource/generator-octo-resource-template → create-external-resource/generator-octo-external-resource-template}/generators/app/templates/resources/resource/actions/add.resource.action.ts.ejs +7 -16
  54. package/dist/commands/{create-resource/generator-octo-resource-template → create-external-resource/generator-octo-external-resource-template}/generators/app/templates/resources/resource/actions/delete.resource.action.ts.ejs +21 -3
  55. package/dist/commands/create-external-resource/generator-octo-external-resource-template/generators/app/templates/resources/resource/actions/update.resource.action.ts.ejs +63 -0
  56. package/dist/commands/{create-resource/generator-octo-resource-template → create-external-resource/generator-octo-external-resource-template}/generators/app/templates/resources/resource/index.ts.ejs +1 -2
  57. package/dist/commands/create-external-resource/generator-octo-external-resource-template/generators/app/templates/resources/resource/resource.ts.ejs +28 -0
  58. package/dist/commands/create-external-resource/index.d.ts +1 -0
  59. package/dist/commands/create-external-resource/index.js +2 -0
  60. package/dist/commands/create-external-resource/index.js.map +1 -0
  61. package/dist/commands/create-model/create-model.command.js +1 -1
  62. package/dist/commands/create-model/create-model.command.js.map +1 -1
  63. package/dist/commands/create-model/generator-octo-model-template/generators/app/index.d.ts +17 -2
  64. package/dist/commands/create-model/generator-octo-model-template/generators/app/index.js +26 -9
  65. package/dist/commands/create-model/generator-octo-model-template/generators/app/index.js.map +1 -1
  66. package/dist/commands/create-model/generator-octo-model-template/generators/app/templates/models/model/model.ts.ejs +41 -1
  67. package/dist/commands/create-model/generator-octo-model-template/generators/app/templates/models/model/schema.ts.ejs +6 -1
  68. package/dist/commands/create-module/create-module.command.js +1 -1
  69. package/dist/commands/create-module/create-module.command.js.map +1 -1
  70. package/dist/commands/create-module/generator-octo-module-template/generators/app/index.d.ts +17 -2
  71. package/dist/commands/create-module/generator-octo-module-template/generators/app/index.js +27 -10
  72. package/dist/commands/create-module/generator-octo-module-template/generators/app/index.js.map +1 -1
  73. package/dist/commands/create-overlay/create-overlay.command.js +4 -3
  74. package/dist/commands/create-overlay/create-overlay.command.js.map +1 -1
  75. package/dist/commands/create-overlay/generator-octo-overlay-template/generators/app/index.d.ts +17 -2
  76. package/dist/commands/create-overlay/generator-octo-overlay-template/generators/app/index.js +26 -9
  77. package/dist/commands/create-overlay/generator-octo-overlay-template/generators/app/index.js.map +1 -1
  78. package/dist/commands/{create-cdk/create-cdk.command.d.ts → create-terraform-resource/create-terraform-resource.command.d.ts} +3 -3
  79. package/dist/commands/{create-resource/create-resource.command.js → create-terraform-resource/create-terraform-resource.command.js} +17 -11
  80. package/dist/commands/create-terraform-resource/create-terraform-resource.command.js.map +1 -0
  81. package/dist/commands/create-terraform-resource/generator-octo-terraform-resource-template/generators/app/index.d.ts +25 -0
  82. package/dist/commands/create-terraform-resource/generator-octo-terraform-resource-template/generators/app/index.js +71 -0
  83. package/dist/commands/create-terraform-resource/generator-octo-terraform-resource-template/generators/app/index.js.map +1 -0
  84. package/dist/commands/create-terraform-resource/generator-octo-terraform-resource-template/generators/app/templates/resources/resource/index.schema.ts.ejs +43 -0
  85. package/dist/commands/create-terraform-resource/generator-octo-terraform-resource-template/generators/app/templates/resources/resource/index.ts.ejs +1 -0
  86. package/dist/commands/create-terraform-resource/generator-octo-terraform-resource-template/generators/app/templates/resources/resource/resource.ts.ejs +83 -0
  87. package/dist/commands/create-terraform-resource/index.d.ts +1 -0
  88. package/dist/commands/create-terraform-resource/index.js +2 -0
  89. package/dist/commands/create-terraform-resource/index.js.map +1 -0
  90. package/dist/commands/generate/generate.command.d.ts +16 -0
  91. package/dist/commands/generate/generate.command.js +35 -0
  92. package/dist/commands/generate/generate.command.js.map +1 -0
  93. package/dist/commands/generate/index.d.ts +1 -0
  94. package/dist/commands/generate/index.js +2 -0
  95. package/dist/commands/generate/index.js.map +1 -0
  96. package/dist/commands/get-response/get-response.command.d.ts +18 -0
  97. package/dist/commands/get-response/get-response.command.js +39 -0
  98. package/dist/commands/get-response/get-response.command.js.map +1 -0
  99. package/dist/commands/get-response/index.d.ts +1 -0
  100. package/dist/commands/get-response/index.js +2 -0
  101. package/dist/commands/get-response/index.js.map +1 -0
  102. package/dist/commands/lock/index.d.ts +1 -0
  103. package/dist/commands/lock/index.js +2 -0
  104. package/dist/commands/lock/index.js.map +1 -0
  105. package/dist/commands/lock/lock.command.d.ts +18 -0
  106. package/dist/commands/lock/lock.command.js +31 -0
  107. package/dist/commands/lock/lock.command.js.map +1 -0
  108. package/dist/commands/run-action/index.d.ts +1 -0
  109. package/dist/commands/run-action/index.js +2 -0
  110. package/dist/commands/run-action/index.js.map +1 -0
  111. package/dist/commands/run-action/run-action.command.d.ts +12 -0
  112. package/dist/commands/run-action/run-action.command.js +40 -0
  113. package/dist/commands/run-action/run-action.command.js.map +1 -0
  114. package/dist/commands/unlock/index.d.ts +1 -0
  115. package/dist/commands/unlock/index.js +2 -0
  116. package/dist/commands/unlock/index.js.map +1 -0
  117. package/dist/commands/unlock/unlock.command.d.ts +18 -0
  118. package/dist/commands/unlock/unlock.command.js +35 -0
  119. package/dist/commands/unlock/unlock.command.js.map +1 -0
  120. package/dist/commands/validate/index.d.ts +1 -0
  121. package/dist/commands/validate/index.js +2 -0
  122. package/dist/commands/validate/index.js.map +1 -0
  123. package/dist/commands/validate/validate.command.d.ts +17 -0
  124. package/dist/commands/validate/validate.command.js +62 -0
  125. package/dist/commands/validate/validate.command.js.map +1 -0
  126. package/dist/index.js +20 -8
  127. package/dist/index.js.map +1 -1
  128. package/dist/resources/octo-v1.schema.json +108 -27
  129. package/dist/utilities/definition/yaml/yaml-definition.utility.d.ts +103 -13
  130. package/dist/utilities/definition/yaml/yaml-definition.utility.js +215 -68
  131. package/dist/utilities/definition/yaml/yaml-definition.utility.js.map +1 -1
  132. package/dist/utilities/octo/octo.utility.d.ts +65 -0
  133. package/dist/utilities/octo/octo.utility.js +178 -0
  134. package/dist/utilities/octo/octo.utility.js.map +1 -0
  135. package/dist/utilities/process/process.utility.d.ts +8 -0
  136. package/dist/utilities/process/process.utility.js +8 -0
  137. package/dist/utilities/process/process.utility.js.map +1 -1
  138. package/dist/utilities/project-index/project-index.utility.d.ts +27 -0
  139. package/dist/utilities/project-index/project-index.utility.js +71 -0
  140. package/dist/utilities/project-index/project-index.utility.js.map +1 -0
  141. package/dist/utilities/string/string.utility.d.ts +22 -0
  142. package/dist/utilities/string/string.utility.js +27 -0
  143. package/dist/utilities/string/string.utility.js.map +1 -1
  144. package/package.json +11 -8
  145. package/dist/commands/create-cdk/create-cdk.command.js +0 -70
  146. package/dist/commands/create-cdk/create-cdk.command.js.map +0 -1
  147. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/index.d.ts +0 -10
  148. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/index.js +0 -107
  149. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/index.js.map +0 -1
  150. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/README.md.ejs +0 -23
  151. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/eslint.config.js.ejs +0 -337
  152. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/gitignore.ejs +0 -82
  153. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/gitkeep.ejs +0 -0
  154. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/package.json.ejs +0 -57
  155. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/prettierrc.ejs +0 -5
  156. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/anchors/app/app.anchor.schema.ts.ejs +0 -19
  157. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/anchors/app/app.anchor.ts.ejs +0 -17
  158. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/factories/dummy-credentials.factory.ts.ejs +0 -28
  159. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/modules/app/dummy-app/dummy-app.module.spec.ts.ejs +0 -90
  160. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/modules/app/dummy-app/dummy-app.module.ts.ejs +0 -16
  161. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/modules/app/dummy-app/index.schema.ts.ejs +0 -10
  162. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/modules/app/dummy-app/index.ts.ejs +0 -3
  163. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/modules/app/dummy-app/models/app/actions/add-dummy-app.model.action.ts.ejs +0 -59
  164. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/modules/app/dummy-app/models/app/index.ts.ejs +0 -1
  165. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/resources/http-fetch/actions/add-http-fetch.resource.action.ts.ejs +0 -55
  166. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/resources/http-fetch/http-fetch.resource.ts.ejs +0 -12
  167. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/resources/http-fetch/index.schema.ts.ejs +0 -35
  168. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/resources/http-fetch/index.ts.ejs +0 -3
  169. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/src/utilities/dummy/dummy.utility.ts.ejs +0 -11
  170. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/tsconfig.build.json.ejs +0 -11
  171. package/dist/commands/create-cdk/generator-octo-cdk-template/generators/app/templates/tsconfig.json.ejs +0 -39
  172. package/dist/commands/create-cdk/index.d.ts +0 -1
  173. package/dist/commands/create-cdk/index.js +0 -2
  174. package/dist/commands/create-cdk/index.js.map +0 -1
  175. package/dist/commands/create-resource/create-resource.command.js.map +0 -1
  176. package/dist/commands/create-resource/generator-octo-resource-template/generators/app/index.js.map +0 -1
  177. package/dist/commands/create-resource/generator-octo-resource-template/generators/app/templates/resources/resource/actions/update-tags.resource.action.ts.ejs +0 -86
  178. package/dist/commands/create-resource/generator-octo-resource-template/generators/app/templates/resources/resource/actions/validate.resource.action.ts.ejs +0 -40
  179. package/dist/commands/create-resource/generator-octo-resource-template/generators/app/templates/resources/resource/resource.ts.ejs +0 -12
  180. package/dist/commands/create-resource/index.d.ts +0 -1
  181. package/dist/commands/create-resource/index.js +0 -2
  182. package/dist/commands/create-resource/index.js.map +0 -1
  183. package/dist/commands/run/index.d.ts +0 -1
  184. package/dist/commands/run/index.js +0 -2
  185. package/dist/commands/run/index.js.map +0 -1
  186. package/dist/commands/run/run.command.d.ts +0 -11
  187. package/dist/commands/run/run.command.js +0 -96
  188. package/dist/commands/run/run.command.js.map +0 -1
  189. package/dist/commands/state/index.d.ts +0 -1
  190. package/dist/commands/state/index.js +0 -2
  191. package/dist/commands/state/index.js.map +0 -1
  192. package/dist/commands/state/state.command.d.ts +0 -14
  193. package/dist/commands/state/state.command.js +0 -79
  194. package/dist/commands/state/state.command.js.map +0 -1
  195. /package/dist/commands/{create-resource/generator-octo-resource-template → create-external-resource/generator-octo-external-resource-template}/generators/app/templates/resources/resource/index.schema.ts.ejs +0 -0
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Custom Octo constructs for this app.
3
+ *
4
+ * The `create-*` commands maintain this file. Modules are exported because the definition file
5
+ * names them; everything else is imported for the registration side effect its decorator performs,
6
+ * which is what makes a construct known to Octo at boot.
7
+ *
8
+ * To use a module, `npm run build` and reference the built file from `octo.yaml`:
9
+ *
10
+ * ```yaml
11
+ * imports:
12
+ * - className: MyModule
13
+ * importPath: "./dist/index.js"
14
+ * ```
15
+ *
16
+ * An app that only composes the modules shipped by `@quadnix/octo-aws-cdk` needs nothing here.
17
+ */
18
+
19
+ export {};
@@ -18,6 +18,7 @@
18
18
  "moduleNameMapper": {
19
19
  "(.+)\\.js": "$1"
20
20
  },
21
+ "passWithNoTests": true,
21
22
  "preset": "ts-jest/presets/default-esm",
22
23
  "rootDir": ".",
23
24
  "testEnvironment": "node",
@@ -32,9 +33,10 @@
32
33
  }
33
34
  },
34
35
  "keywords": [
35
- "cdk",
36
36
  "infrastructure",
37
37
  "octo",
38
+ "terraform",
39
+ "terragrunt",
38
40
  "typescript"
39
41
  ],
40
42
  "name": "<%= name %>",
@@ -43,6 +45,12 @@
43
45
  "build": "rimraf dist && tsc -p tsconfig.build.json",
44
46
  "format": "prettier --write \"src/**/*.ts\"",
45
47
  "lint": "eslint .",
48
+ "octo:apply": "OCTO_DEFINITION_FILE_PATH=octo.yaml octo apply --terragruntDir .octo-tf",
49
+ "octo:commit": "OCTO_DEFINITION_FILE_PATH=octo.yaml octo commit --terragruntDir .octo-tf",
50
+ "octo:generate": "OCTO_DEFINITION_FILE_PATH=octo.yaml octo generate -o .octo-tf",
51
+ "octo:lock": "OCTO_DEFINITION_FILE_PATH=octo.yaml octo lock",
52
+ "octo:unlock": "OCTO_DEFINITION_FILE_PATH=octo.yaml octo unlock",
53
+ "octo:validate": "OCTO_DEFINITION_FILE_PATH=octo.yaml octo validate --terragruntDir .octo-tf",
46
54
  "test": "NODE_OPTIONS=--experimental-vm-modules jest --testRegex=\"\\.spec.ts$\"",
47
55
  "test:e2e": "NODE_OPTIONS=--experimental-vm-modules jest --testRegex=\"\\.e2e-spec.ts$\""
48
56
  },
@@ -0,0 +1,111 @@
1
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/quadnix/octo/refs/heads/main/packages/octo-build/src/resources/octo-v1.schema.json
2
+
3
+ version: 1
4
+
5
+ env:
6
+ - key: AWS_ACCOUNT_ID
7
+ kind: string
8
+ value: "123456789123"
9
+
10
+ terraform:
11
+ requiredVersion: "1.6.0"
12
+ requiredProviders:
13
+ aws:
14
+ source: hashicorp/aws
15
+ providers:
16
+ - providerType: aws
17
+ accountId: "${env.AWS_ACCOUNT_ID}"
18
+ # Optional. Puts a name in the generated provider alias in place of the account number.
19
+ # accountName: prod
20
+ regionId: us-east-1
21
+ spec:
22
+ profile: default
23
+
24
+ settings:
25
+ listeners:
26
+ - type: JournalEventListener
27
+ - type: LoggingEventListener
28
+
29
+ stateProvider:
30
+ type: LocalStateProvider
31
+ statePath: .octo
32
+
33
+ imports:
34
+ - className: SimpleAppModule
35
+ importPath: "@quadnix/octo-aws-cdk/modules/app/simple-app"
36
+ - className: AwsIniAccountModule
37
+ importPath: "@quadnix/octo-aws-cdk/modules/account/aws-ini-account"
38
+ - className: AwsSingleAzRegionModule
39
+ importPath: "@quadnix/octo-aws-cdk/modules/region/aws-single-az-region"
40
+ - className: AwsDynamoDBServiceModule
41
+ importPath: "@quadnix/octo-aws-cdk/modules/service/aws-dynamodb-service"
42
+
43
+ modules:
44
+ - moduleId: app-module
45
+ moduleClass: SimpleAppModule
46
+ moduleInputs:
47
+ name: aws-dynamodb-service
48
+
49
+ - moduleId: account-module
50
+ moduleClass: AwsIniAccountModule
51
+ moduleInputs:
52
+ accountId: "${env.AWS_ACCOUNT_ID}"
53
+ app: "${{app-module.model.app}}"
54
+ iniProfile: default
55
+
56
+ - moduleId: region-module
57
+ moduleClass: AwsSingleAzRegionModule
58
+ moduleInputs:
59
+ account: "${{account-module.model.account}}"
60
+ name: app-region-east
61
+ regionId: aws-us-east-1a
62
+ vpcCidrBlock: 10.0.0.0/16
63
+
64
+ - moduleId: dynamodb-service-module
65
+ moduleClass: AwsDynamoDBServiceModule
66
+ moduleInputs:
67
+ # Every attribute a key schema or an index refers to must be declared here. DynamoDB is
68
+ # schemaless otherwise - attributes that are neither keys nor indexed are not declared.
69
+ AttributeDefinitions:
70
+ - AttributeName: AccountId
71
+ AttributeType: S
72
+ - AttributeName: AccountType
73
+ AttributeType: S
74
+ - AttributeName: CreatedAt
75
+ AttributeType: N
76
+ - AttributeName: UserId
77
+ AttributeType: S
78
+ billingMode:
79
+ type: PROVISIONED
80
+ settings:
81
+ ProvisionedThroughput:
82
+ ReadCapacityUnits: 5
83
+ WriteCapacityUnits: 5
84
+ # A global secondary index can be added or removed on a live table.
85
+ GlobalSecondaryIndexes:
86
+ - IndexName: AccountUserIndex
87
+ KeySchema:
88
+ - AttributeName: UserId
89
+ KeyType: HASH
90
+ Projection:
91
+ ProjectionType: ALL
92
+ KeySchema:
93
+ - AttributeName: AccountId
94
+ KeyType: HASH
95
+ - AttributeName: AccountType
96
+ KeyType: RANGE
97
+ # A local secondary index is fixed at table creation; changing one recreates the table.
98
+ LocalSecondaryIndexes:
99
+ - IndexName: AccountCreatedAtIndex
100
+ KeySchema:
101
+ - AttributeName: AccountId
102
+ KeyType: HASH
103
+ - AttributeName: CreatedAt
104
+ KeyType: RANGE
105
+ Projection:
106
+ ProjectionType: ALL
107
+ region: "${{region-module.model.region}}"
108
+ StreamSpecification:
109
+ StreamViewType: NEW_AND_OLD_IMAGES
110
+ TableName: accounts
111
+ timeToLiveAttribute: ExpiresAt
@@ -7,9 +7,23 @@ env:
7
7
  kind: string
8
8
  value: "123456789123"
9
9
 
10
+ terraform:
11
+ requiredVersion: "1.6.0"
12
+ requiredProviders:
13
+ aws:
14
+ source: hashicorp/aws
15
+ providers:
16
+ - providerType: aws
17
+ accountId: "${env.AWS_ACCOUNT_ID}"
18
+ # Optional. Puts a name in the generated provider alias in place of the account number.
19
+ # accountName: prod
20
+ regionId: us-east-1
21
+ spec:
22
+ profile: default
23
+
10
24
  settings:
11
25
  listeners:
12
- - type: HtmlReportEventListener
26
+ - type: JournalEventListener
13
27
  - type: LoggingEventListener
14
28
 
15
29
  stateProvider:
@@ -21,16 +35,16 @@ imports:
21
35
  importPath: "@quadnix/octo-aws-cdk/modules/app/simple-app"
22
36
  - className: AwsIniAccountModule
23
37
  importPath: "@quadnix/octo-aws-cdk/modules/account/aws-ini-account"
24
- - className: AwsEcsDeploymentModule
25
- importPath: "@quadnix/octo-aws-cdk/modules/deployment/aws-ecs-deployment"
38
+ - className: AwsDeploymentModule
39
+ importPath: "@quadnix/octo-aws-cdk/modules/deployment/aws-deployment"
26
40
  - className: AwsEcsEnvironmentModule
27
41
  importPath: "@quadnix/octo-aws-cdk/modules/environment/aws-ecs-environment"
28
42
  - className: AwsEcsExecutionModule
29
43
  importPath: "@quadnix/octo-aws-cdk/modules/execution/aws-ecs-execution"
30
44
  - className: AwsMultiAzRegionModule
31
45
  importPath: "@quadnix/octo-aws-cdk/modules/region/aws-multi-az-region"
32
- - className: AwsEcsServerModule
33
- importPath: "@quadnix/octo-aws-cdk/modules/server/aws-ecs-server"
46
+ - className: AwsServerModule
47
+ importPath: "@quadnix/octo-aws-cdk/modules/server/aws-server"
34
48
  - className: AwsEcsAlbServiceModule
35
49
  importPath: "@quadnix/octo-aws-cdk/modules/service/aws-ecs-alb-service"
36
50
  - className: AwsSimpleSubnetModule
@@ -59,24 +73,22 @@ modules:
59
73
  vpcCidrBlock: 10.0.0.0/16
60
74
 
61
75
  - moduleId: backend-server-module
62
- moduleClass: AwsEcsServerModule
76
+ moduleClass: AwsServerModule
63
77
  moduleInputs:
64
78
  account: "${{account-module.model.account}}"
65
79
  serverKey: backend
66
80
 
67
81
  - moduleId: backend-deployment-v1-module
68
- moduleClass: AwsEcsDeploymentModule
82
+ moduleClass: AwsDeploymentModule
69
83
  moduleInputs:
70
- deploymentContainerProperties:
71
- cpu: 256
72
- image:
73
- command: node webserver
74
- ports:
75
- - containerPort: 80
76
- protocol: tcp
77
- uri: docker.io/ealen/echo-server:0.9.2
78
- memory: 512
84
+ command: [node, webserver]
85
+ cpu: 256
79
86
  deploymentTag: v1
87
+ imageUri: docker.io/ealen/echo-server:0.9.2
88
+ memory: 512
89
+ ports:
90
+ - containerPort: 80
91
+ protocol: tcp
80
92
  server: "${{backend-server-module.model.server}}"
81
93
 
82
94
  - moduleId: qa-environment-module
@@ -10,9 +10,23 @@ env:
10
10
  kind: string
11
11
  value: my-website-unique-bucket
12
12
 
13
+ terraform:
14
+ requiredVersion: "1.6.0"
15
+ requiredProviders:
16
+ aws:
17
+ source: hashicorp/aws
18
+ providers:
19
+ - providerType: aws
20
+ accountId: "${env.AWS_ACCOUNT_ID}"
21
+ # Optional. Puts a name in the generated provider alias in place of the account number.
22
+ # accountName: prod
23
+ regionId: us-east-1
24
+ spec:
25
+ profile: default
26
+
13
27
  settings:
14
28
  listeners:
15
- - type: HtmlReportEventListener
29
+ - type: JournalEventListener
16
30
  - type: LoggingEventListener
17
31
 
18
32
  stateProvider:
@@ -24,6 +38,8 @@ imports:
24
38
  importPath: "@quadnix/octo-aws-cdk/modules/app/simple-app"
25
39
  - className: AwsIniAccountModule
26
40
  importPath: "@quadnix/octo-aws-cdk/modules/account/aws-ini-account"
41
+ - className: AwsServerlessRegionModule
42
+ importPath: "@quadnix/octo-aws-cdk/modules/region/aws-serverless-region"
27
43
  - className: AwsS3StaticWebsiteServiceModule
28
44
  importPath: "@quadnix/octo-aws-cdk/modules/service/aws-s3-static-website-service"
29
45
 
@@ -39,10 +55,16 @@ modules:
39
55
  accountId: "${env.AWS_ACCOUNT_ID}"
40
56
  app: "${{app-module.model.app}}"
41
57
 
58
+ - moduleId: region-module
59
+ moduleClass: AwsServerlessRegionModule
60
+ moduleInputs:
61
+ account: "${{account-module.model.account}}"
62
+ name: aws-s3-website
63
+ regionId: aws-us-east-1
64
+
42
65
  - moduleId: s3-website-service-module
43
66
  moduleClass: AwsS3StaticWebsiteServiceModule
44
67
  moduleInputs:
45
- account: "${{account-module.model.account}}"
46
- awsRegionId: us-east-1
47
68
  bucketName: "${env.AWS_S3_WEBSITE_BUCKET_NAME}"
48
69
  directoryPath: website
70
+ region: "${{region-module.model.region}}"
@@ -20,9 +20,6 @@
20
20
  "strictBindCallApply": true,
21
21
  "strictNullChecks": true,
22
22
  "target": "ES2022",
23
- "typeRoots": [
24
- "node_modules/@types"
25
- ],
26
23
  "useDefineForClassFields": false,
27
24
  "verbatimModuleSyntax": true
28
25
  },
@@ -1,5 +1,5 @@
1
1
  import type { ArgumentsCamelCase, Argv } from 'yargs';
2
- export declare const createResourceCommand: {
2
+ export declare const createExternalResourceCommand: {
3
3
  builder: (yargs: Argv) => Argv;
4
4
  command: string;
5
5
  describe: string;
@@ -0,0 +1,64 @@
1
+ import { dirname, resolve } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import chalk from 'chalk';
4
+ import { createEnv } from 'yeoman-environment';
5
+ import { StringUtility } from '../../utilities/string/string.utility.js';
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ export const createExternalResourceCommand = {
8
+ builder: (yargs) => {
9
+ return yargs
10
+ .option('name', {
11
+ alias: 'n',
12
+ demandOption: true,
13
+ description: 'Name of the resource to create. Should be in kebab-case (e.g., my-awesome-resource).',
14
+ type: 'string',
15
+ })
16
+ .option('package', {
17
+ demandOption: true,
18
+ description: 'Package name for the resource.',
19
+ type: 'string',
20
+ })
21
+ .option('path', {
22
+ alias: 'p',
23
+ default: '.',
24
+ description: 'Root directory path of the project.',
25
+ type: 'string',
26
+ });
27
+ },
28
+ command: 'create-external-resource',
29
+ // Named for the lifecycle, not as the general case: a resource terraform manages is the common
30
+ // one, and that is `create-terraform-resource`. This generator emits the other kind - a resource
31
+ // whose add/delete run as SDK calls, which terraform drives by shelling back into `run-action`.
32
+ describe: 'Create a new Octo resource whose lifecycle runs outside Terraform.',
33
+ handler: async (argv) => {
34
+ const { name, package: packageName, path } = argv;
35
+ // Validate resource name format (should be kebab-case)
36
+ if (!StringUtility.isKebabCase(name)) {
37
+ console.error(chalk.red('Resource name must be in kebab-case format (e.g., my-vpc)'));
38
+ process.exit(1);
39
+ }
40
+ // Rejected here rather than at registration: the decorator runs this same check, but only once
41
+ // the generated resource is loaded, long after the files are on disk.
42
+ if (!StringUtility.isValidPackageName(packageName)) {
43
+ console.error(chalk.red(`Invalid package name "${packageName}"! Expected e.g. @octo or my-package.`));
44
+ process.exit(1);
45
+ }
46
+ console.log(chalk.blue(`Creating external resource "${name}" with package "${packageName}"...`));
47
+ const env = createEnv();
48
+ env.register(resolve(__dirname, 'generator-octo-external-resource-template/generators/app/index.js'), {
49
+ namespace: 'generator-octo-external-resource-template:app',
50
+ });
51
+ try {
52
+ await env.run(['generator-octo-external-resource-template:app', name, packageName, path], {
53
+ skipCache: true,
54
+ skipInstall: true,
55
+ });
56
+ console.log(chalk.green(`Successfully created external resource!`));
57
+ }
58
+ catch (error) {
59
+ console.error(chalk.red(`Failed to create external resource! ${error.message}`));
60
+ process.exit(1);
61
+ }
62
+ },
63
+ };
64
+ //# sourceMappingURL=create-external-resource.command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-external-resource.command.js","sourceRoot":"","sources":["../../../src/commands/create-external-resource/create-external-resource.command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAEzE,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,OAAO,EAAE,CAAC,KAAW,EAAQ,EAAE;QAC7B,OAAO,KAAK;aACT,MAAM,CAAC,MAAM,EAAE;YACd,KAAK,EAAE,GAAG;YACV,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,sFAAsF;YACnG,IAAI,EAAE,QAAQ;SACf,CAAC;aACD,MAAM,CAAC,SAAS,EAAE;YACjB,YAAY,EAAE,IAAI;YAClB,WAAW,EAAE,gCAAgC;YAC7C,IAAI,EAAE,QAAQ;SACf,CAAC;aACD,MAAM,CAAC,MAAM,EAAE;YACd,KAAK,EAAE,GAAG;YACV,OAAO,EAAE,GAAG;YACZ,WAAW,EAAE,qCAAqC;YAClD,IAAI,EAAE,QAAQ;SACf,CAAC,CAAC;IACP,CAAC;IACD,OAAO,EAAE,0BAA0B;IACnC,+FAA+F;IAC/F,iGAAiG;IACjG,gGAAgG;IAChG,QAAQ,EAAE,oEAAoE;IAC9E,OAAO,EAAE,KAAK,EAAE,IAAyE,EAAiB,EAAE;QAC1G,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QAElD,uDAAuD;QACvD,IAAI,CAAC,aAAa,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC,CAAC;YACtF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,+FAA+F;QAC/F,sEAAsE;QACtE,IAAI,CAAC,aAAa,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;YACnD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yBAAyB,WAAW,uCAAuC,CAAC,CAAC,CAAC;YACtG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,+BAA+B,IAAI,mBAAmB,WAAW,MAAM,CAAC,CAAC,CAAC;QAEjG,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;QACxB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,mEAAmE,CAAC,EAAE;YACpG,SAAS,EAAE,+CAA+C;SAC3D,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,+CAA+C,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;gBACxF,SAAS,EAAE,IAAI;gBACf,WAAW,EAAE,IAAI;aAClB,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC,CAAC;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,uCAAuC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -1,10 +1,25 @@
1
1
  import Generator, { type BaseOptions } from 'yeoman-generator';
2
+ /**
3
+ * @internal
4
+ */
2
5
  export default class extends Generator {
3
- private readonly cdkRootDir;
4
6
  private readonly packageName;
7
+ private readonly projectRootDir;
5
8
  private readonly resourceName;
9
+ /**
10
+ * @internal
11
+ */
6
12
  constructor(args: string[], opts: BaseOptions);
13
+ /**
14
+ * @internal
15
+ */
16
+ end(): void;
17
+ /**
18
+ * @internal
19
+ */
7
20
  initializing(): Promise<void>;
21
+ /**
22
+ * @internal
23
+ */
8
24
  writing(): Promise<void>;
9
- end(): void;
10
25
  }
@@ -1,16 +1,37 @@
1
1
  import { readdir, stat } from 'fs/promises';
2
2
  import { join, resolve } from 'path';
3
3
  import Generator, {} from 'yeoman-generator';
4
+ import { ProjectIndexUtility } from '../../../../../utilities/project-index/project-index.utility.js';
4
5
  import { StringUtility } from '../../../../../utilities/string/string.utility.js';
6
+ /**
7
+ * @internal
8
+ */
5
9
  export default class extends Generator {
10
+ /**
11
+ * @internal
12
+ */
6
13
  constructor(args, opts) {
7
14
  super(args, opts);
8
15
  this.resourceName = args[0];
9
16
  this.packageName = args[1];
10
- this.cdkRootDir = args[2];
17
+ this.projectRootDir = args[2];
11
18
  }
19
+ /**
20
+ * @internal
21
+ */
22
+ end() {
23
+ const targetPath = resolve(join(this.projectRootDir, 'src', 'resources', this.resourceName));
24
+ this.log('✅ Your external resource has been generated successfully!');
25
+ this.log(`📁 Resource created at: ${targetPath}`);
26
+ ProjectIndexUtility.addImport(this.projectRootDir, `./resources/${this.resourceName}/index.js`);
27
+ this.log('📦 Next steps:');
28
+ this.log(` Address all "Fix me" in generated files`);
29
+ }
30
+ /**
31
+ * @internal
32
+ */
12
33
  async initializing() {
13
- const targetPath = resolve(join(this.cdkRootDir, 'src', 'resources', this.resourceName));
34
+ const targetPath = resolve(join(this.projectRootDir, 'src', 'resources', this.resourceName));
14
35
  // Check if directory already exists and is not empty.
15
36
  let targetPathStat;
16
37
  try {
@@ -30,46 +51,26 @@ export default class extends Generator {
30
51
  // Set the destination root to the resource directory.
31
52
  this.destinationRoot(targetPath);
32
53
  }
54
+ /**
55
+ * @internal
56
+ */
33
57
  async writing() {
34
- // Create the resource file.
35
- this.fs.copyTpl(this.templatePath('resources/resource/resource.ts.ejs'), this.destinationPath(`${this.resourceName}.resource.ts`), {
58
+ const templateData = {
36
59
  packageName: this.packageName,
37
60
  resourceName: this.resourceName,
61
+ resourceNameCamel: StringUtility.toCamelCase(this.resourceName),
38
62
  resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
39
- });
63
+ };
64
+ // Create the resource file.
65
+ this.fs.copyTpl(this.templatePath('resources/resource/resource.ts.ejs'), this.destinationPath(`${this.resourceName}.resource.ts`), templateData);
40
66
  // Create schema file.
41
- this.fs.copyTpl(this.templatePath('resources/resource/index.schema.ts.ejs'), this.destinationPath('index.schema.ts'), {
42
- resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
43
- });
67
+ this.fs.copyTpl(this.templatePath('resources/resource/index.schema.ts.ejs'), this.destinationPath('index.schema.ts'), templateData);
44
68
  // Create index.ts
45
- this.fs.copyTpl(this.templatePath('resources/resource/index.ts.ejs'), this.destinationPath('index.ts'), {
46
- resourceName: this.resourceName,
47
- resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
48
- });
69
+ this.fs.copyTpl(this.templatePath('resources/resource/index.ts.ejs'), this.destinationPath('index.ts'), templateData);
49
70
  // Create actions directory and action files
50
- this.fs.copyTpl(this.templatePath('resources/resource/actions/add.resource.action.ts.ejs'), this.destinationPath('actions', `add-${this.resourceName}.resource.action.ts`), {
51
- resourceName: this.resourceName,
52
- resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
53
- });
54
- this.fs.copyTpl(this.templatePath('resources/resource/actions/delete.resource.action.ts.ejs'), this.destinationPath('actions', `delete-${this.resourceName}.resource.action.ts`), {
55
- resourceName: this.resourceName,
56
- resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
57
- });
58
- this.fs.copyTpl(this.templatePath('resources/resource/actions/update-tags.resource.action.ts.ejs'), this.destinationPath('actions', `update-${this.resourceName}-tags.resource.action.ts`), {
59
- resourceName: this.resourceName,
60
- resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
61
- });
62
- this.fs.copyTpl(this.templatePath('resources/resource/actions/validate.resource.action.ts.ejs'), this.destinationPath('actions', `validate-${this.resourceName}.resource.action.ts`), {
63
- resourceName: this.resourceName,
64
- resourceNamePascal: StringUtility.toPascalCase(this.resourceName),
65
- });
66
- }
67
- end() {
68
- const targetPath = resolve(join(this.cdkRootDir, 'src', 'resources', this.resourceName));
69
- this.log('✅ Your resource has been generated successfully!');
70
- this.log(`📁 Resource created at: ${targetPath}`);
71
- this.log('📦 Next steps:');
72
- this.log(` Address all "Fix me" in generated files`);
71
+ this.fs.copyTpl(this.templatePath('resources/resource/actions/add.resource.action.ts.ejs'), this.destinationPath('actions', `add-${this.resourceName}.resource.action.ts`), templateData);
72
+ this.fs.copyTpl(this.templatePath('resources/resource/actions/delete.resource.action.ts.ejs'), this.destinationPath('actions', `delete-${this.resourceName}.resource.action.ts`), templateData);
73
+ this.fs.copyTpl(this.templatePath('resources/resource/actions/update.resource.action.ts.ejs'), this.destinationPath('actions', `update-${this.resourceName}.resource.action.ts`), templateData);
73
74
  }
74
75
  }
75
76
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../src/commands/create-external-resource/generator-octo-external-resource-template/generators/app/index.ts"],"names":[],"mappings":"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"}
@@ -19,25 +19,16 @@ export class Add<%= resourceNamePascal %>ResourceAction extends ANodeAction impl
19
19
 
20
20
  async handle(diff: Diff<<%= resourceNamePascal %>>): Promise<<%= resourceNamePascal %>Schema['response']> {
21
21
  // Get properties.
22
- const <%= resourceName %> = diff.node;
23
- const properties = <%= resourceName %>.properties;
24
- const response = <%= resourceName %>.response;
25
- const tags = <%= resourceName %>.tags;
22
+ const <%= resourceNameCamel %> = diff.node;
23
+ const properties = <%= resourceNameCamel %>.properties;
24
+ const response = <%= resourceNameCamel %>.response;
25
+ const tags = <%= resourceNameCamel %>.tags;
26
26
 
27
27
  // Fix me: Implement the add resource logic.
28
- // This is where you would create the actual resource.
28
+ // This is where you would create the actual resource (SDK call, script, API request, ...).
29
29
 
30
- // Fix me: Return response properties.
31
- return response;
32
- }
33
-
34
- async mock(diff: Diff<<%= resourceNamePascal %>>, capture: Partial<<%= resourceNamePascal %>Schema['response']>): Promise<<%= resourceNamePascal %>Schema['response']> {
35
- // Get properties.
36
- const <%= resourceName %> = diff.node;
37
- const properties = <%= resourceName %>.properties;
38
- const response = <%= resourceName %>.response;
39
-
40
- // Fix me: Return response using captures.
30
+ // Fix me: Populate and return every declared response key. Each key must be declared on the
31
+ // schema's `response` so Octo can emit it as a Terraform output.
41
32
  return response;
42
33
  }
43
34
  }
@@ -1,6 +1,24 @@
1
1
  import { ANodeAction, Action, type Diff, DiffAction, Factory, type IResourceAction, hasNodeName } from '@quadnix/octo';
2
2
  import { <%= resourceNamePascal %> } from '../<%= resourceName %>.resource.js';
3
3
 
4
+ /**
5
+ * Deletes the resource.
6
+ *
7
+ * Unlike add and update, this does **not** run mid-apply. Terraform cannot run it: octo deletes a
8
+ * resource by removing its block from the configuration, and terraform will not run a
9
+ * `when = destroy` provisioner for a resource that is no longer in the configuration. So `octo
10
+ * commit` runs this instead, from the project directory, after terraform has destroyed the
11
+ * `null_resource`.
12
+ *
13
+ * Two consequences worth designing around:
14
+ *
15
+ * - **The working directory is not the one add and update saw.** Those run inside a terragrunt
16
+ * cache directory; this runs wherever `octo commit` was invoked. Anything positional - a relative
17
+ * file path, a relative config lookup - resolves somewhere else. Build absolute paths from a
18
+ * module input rather than assuming a cwd.
19
+ * - **Throwing here aborts the commit**, on purpose: octo state then still records the resource, so
20
+ * the next run diffs it again and retries. Failing loudly is better than a silent leak.
21
+ */
4
22
  @Action(<%= resourceNamePascal %>)
5
23
  export class Delete<%= resourceNamePascal %>ResourceAction extends ANodeAction implements IResourceAction<<%= resourceNamePascal %>> {
6
24
  constructor() {
@@ -18,9 +36,9 @@ export class Delete<%= resourceNamePascal %>ResourceAction extends ANodeAction i
18
36
 
19
37
  async handle(diff: Diff<<%= resourceNamePascal %>>): Promise<void> {
20
38
  // Get properties.
21
- const <%= resourceName %> = diff.node;
22
- const properties = <%= resourceName %>.properties;
23
- const response = <%= resourceName %>.response;
39
+ const <%= resourceNameCamel %> = diff.node;
40
+ const properties = <%= resourceNameCamel %>.properties;
41
+ const response = <%= resourceNameCamel %>.response;
24
42
 
25
43
  // Fix me: Implement the delete resource logic.
26
44
  // This is where you would delete the actual resource.
@@ -0,0 +1,63 @@
1
+ import { ANodeAction, Action, type Diff, DiffAction, Factory, type IResourceAction, hasNodeName } from '@quadnix/octo';
2
+ import type { <%= resourceNamePascal %>Schema } from '../index.schema.js';
3
+ import { <%= resourceNamePascal %> } from '../<%= resourceName %>.resource.js';
4
+
5
+ /**
6
+ * Handles the two `UPDATE` diffs an external resource receives.
7
+ *
8
+ * Neither is optional: a diff that no registered action matches aborts the whole transaction with
9
+ * "No matching action given for diff!". Deleting this file means a generated resource works until
10
+ * its first change and then refuses to apply at all.
11
+ *
12
+ * - **`properties`** - the default `diffProperties()` emits this whenever a property changes. You
13
+ * own the partial-update semantics. `diff.value` carries the changed properties; the resource's
14
+ * `properties` already hold the new values. If the underlying API cannot change an attribute in
15
+ * place, do not silently skip it - either recreate it here, or override `diffProperties()` on the
16
+ * resource to return `DiffAction.REPLACE` with a reason, which routes the change through the add
17
+ * and delete actions instead.
18
+ * - **`parent`** - emitted when a parent is replaced, with `diff.value` naming the new parent. The
19
+ * parent's outputs are this resource's inputs, so they have just changed underneath it: re-read
20
+ * them from `this.parents` and re-apply. Skipping this case is how an external resource ends up
21
+ * pointing at a parent that no longer exists.
22
+ */
23
+ @Action(<%= resourceNamePascal %>)
24
+ export class Update<%= resourceNamePascal %>ResourceAction extends ANodeAction implements IResourceAction<<%= resourceNamePascal %>> {
25
+ constructor() {
26
+ super();
27
+ }
28
+
29
+ filter(diff: Diff): boolean {
30
+ return (
31
+ diff.action === DiffAction.UPDATE &&
32
+ diff.node instanceof <%= resourceNamePascal %> &&
33
+ hasNodeName(diff.node, '<%= resourceName %>') &&
34
+ (diff.field === 'properties' || diff.field === 'parent')
35
+ );
36
+ }
37
+
38
+ async handle(diff: Diff<<%= resourceNamePascal %>>): Promise<<%= resourceNamePascal %>Schema['response']> {
39
+ // Get properties.
40
+ const <%= resourceNameCamel %> = diff.node;
41
+ const properties = <%= resourceNameCamel %>.properties;
42
+ const response = <%= resourceNameCamel %>.response;
43
+
44
+ // Fix me: Implement the update resource logic.
45
+ // This is where you would apply the changed properties to the actual resource.
46
+
47
+ // Fix me: Return every declared response key, re-reading any the update changed. Returning the
48
+ // response unchanged is what an unimplemented update looks like, and it reports success.
49
+ return response;
50
+ }
51
+ }
52
+
53
+ @Factory<Update<%= resourceNamePascal %>ResourceAction>(Update<%= resourceNamePascal %>ResourceAction)
54
+ export class Update<%= resourceNamePascal %>ResourceActionFactory {
55
+ private static instance: Update<%= resourceNamePascal %>ResourceAction;
56
+
57
+ static async create(): Promise<Update<%= resourceNamePascal %>ResourceAction> {
58
+ if (!this.instance) {
59
+ this.instance = new Update<%= resourceNamePascal %>ResourceAction();
60
+ }
61
+ return this.instance;
62
+ }
63
+ }