@empire-builder-kit/nx 1.0.0-rc.4 → 1.0.0-rc.41

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 (805) hide show
  1. package/README.md +44 -10
  2. package/executors.json +21 -1
  3. package/generators.json +10 -0
  4. package/package.json +31 -7
  5. package/src/aws/child-environment.d.ts +10 -0
  6. package/src/aws/child-environment.js +77 -0
  7. package/src/aws/identity.d.ts +13 -0
  8. package/src/aws/identity.js +41 -0
  9. package/src/aws-authority/index.d.ts +2 -0
  10. package/src/aws-authority/index.js +6 -0
  11. package/src/aws-authority/lambda-policy-ordering.d.ts +38 -0
  12. package/src/aws-authority/lambda-policy-ordering.js +56 -0
  13. package/src/aws-authority/stage-authority.d.ts +248 -0
  14. package/src/aws-authority/stage-authority.js +3558 -0
  15. package/src/blueprints/external-sandbox.d.ts +1 -1
  16. package/src/blueprints/external-sandbox.js +21 -9
  17. package/src/blueprints/manifest.d.ts +1 -1
  18. package/src/blueprints/resolver.js +28 -15
  19. package/src/cli/bootstrap.d.ts +1 -1
  20. package/src/cli/deploy-runtime.d.ts +30 -0
  21. package/src/cli/deploy-runtime.js +174 -0
  22. package/src/cli/dev-command.d.ts +18 -4
  23. package/src/cli/dev-command.js +71 -0
  24. package/src/cli/main.d.ts +9 -1
  25. package/src/cli/main.js +157 -24
  26. package/src/cli/output.d.ts +1 -1
  27. package/src/cli/output.js +1 -1
  28. package/src/cli/personal-secret-runtime.d.ts +12 -0
  29. package/src/cli/personal-secret-runtime.js +18 -3
  30. package/src/cli/secret-terminal.js +1 -1
  31. package/src/container-images.d.ts +1 -1
  32. package/src/container-images.js +1 -1
  33. package/src/developer-agent/context.js +41 -9
  34. package/src/developer-agent/generator-planning.js +20 -6
  35. package/src/developer-agent/git-inspection.d.ts +6 -2
  36. package/src/developer-agent/git-inspection.js +78 -6
  37. package/src/developer-agent/model.d.ts +5 -3
  38. package/src/developer-agent/model.js +4 -4
  39. package/src/developer-agent/operation-registry.d.ts +15 -0
  40. package/src/developer-agent/operation-registry.js +342 -49
  41. package/src/developer-agent/planning.d.ts +8 -1
  42. package/src/developer-agent/planning.js +39 -16
  43. package/src/developer-agent/preview-changes.d.ts +2 -0
  44. package/src/developer-agent/preview-changes.js +14 -2
  45. package/src/developer-agent/preview-source.js +3 -0
  46. package/src/developer-agent/validation.js +25 -9
  47. package/src/developer-agent/workspace-inspection.js +60 -5
  48. package/src/executors/blueprint-trust/blueprint-trust.js +6 -0
  49. package/src/executors/deployment-plan/deployment-plan.d.ts +2 -0
  50. package/src/executors/deployment-plan/deployment-plan.js +57 -2
  51. package/src/executors/dev-doctor/dev-doctor.js +13 -6
  52. package/src/executors/dev-task-cleanup/dev-task-cleanup.d.ts +23 -0
  53. package/src/executors/dev-task-cleanup/dev-task-cleanup.js +145 -0
  54. package/src/executors/dev-task-cleanup/schema.json +9 -0
  55. package/src/executors/dev-task-cleanup/task-stack-absence.d.ts +27 -0
  56. package/src/executors/dev-task-cleanup/task-stack-absence.js +281 -0
  57. package/src/executors/dev-task-cleanup/task-stack-checkpoint.d.ts +12 -0
  58. package/src/executors/dev-task-cleanup/task-stack-checkpoint.js +92 -0
  59. package/src/executors/fleet/fleet.js +1 -1
  60. package/src/executors/foundation-preflight/foundation-preflight.d.ts +1 -0
  61. package/src/executors/foundation-preflight/foundation-preflight.js +6 -2
  62. package/src/executors/foundation-preflight/schema.json +5 -0
  63. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.d.ts +13 -2
  64. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js +95 -31
  65. package/src/executors/foundation-profile-preflight/production-database-safeguard.d.ts +65 -0
  66. package/src/executors/foundation-profile-preflight/production-database-safeguard.js +223 -0
  67. package/src/executors/foundation-profile-preflight/schema.json +15 -4
  68. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.d.ts +11 -1
  69. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +70 -20
  70. package/src/executors/foundation-remove-preflight/schema.json +6 -1
  71. package/src/executors/github-bootstrap/github-bootstrap.d.ts +1 -0
  72. package/src/executors/github-bootstrap/github-bootstrap.js +3 -0
  73. package/src/executors/github-bootstrap/schema.json +7 -1
  74. package/src/executors/infrastructure-plan/infrastructure-plan.d.ts +29 -136
  75. package/src/executors/infrastructure-plan/infrastructure-plan.js +230 -3282
  76. package/src/executors/infrastructure-plan/schema.json +12 -52
  77. package/src/executors/local-deploy/federated-credential-transport.d.ts +48 -0
  78. package/src/executors/local-deploy/federated-credential-transport.js +252 -0
  79. package/src/executors/local-deploy/local-approval.d.ts +18 -0
  80. package/src/executors/local-deploy/local-approval.js +39 -0
  81. package/src/executors/local-deploy/local-deploy.d.ts +112 -0
  82. package/src/executors/local-deploy/local-deploy.js +1404 -0
  83. package/src/executors/local-deploy/schema.json +70 -0
  84. package/src/executors/refresh/refresh.js +2 -2
  85. package/src/executors/remove/remove.js +2 -2
  86. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.d.ts +42 -0
  87. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +1229 -0
  88. package/src/executors/router-waf-rehearsal/schema.json +29 -0
  89. package/src/executors/secret-initialize/schema.json +42 -0
  90. package/src/executors/secret-initialize/secret-initialize.d.ts +34 -0
  91. package/src/executors/secret-initialize/secret-initialize.js +297 -0
  92. package/src/executors/secret-metadata/schema.json +5 -0
  93. package/src/executors/secret-metadata/secret-metadata.d.ts +16 -2
  94. package/src/executors/secret-metadata/secret-metadata.js +129 -30
  95. package/src/executors/sst-lifecycle/generated-secret-retirement.d.ts +53 -0
  96. package/src/executors/sst-lifecycle/generated-secret-retirement.js +192 -0
  97. package/src/executors/sst-lifecycle/governed-native-operation.d.ts +48 -0
  98. package/src/executors/sst-lifecycle/governed-native-operation.js +163 -0
  99. package/src/executors/sst-lifecycle/logging-preflight.d.ts +5 -0
  100. package/src/executors/sst-lifecycle/logging-preflight.js +23 -13
  101. package/src/executors/sst-lifecycle/run-sst-command.d.ts +46 -6
  102. package/src/executors/sst-lifecycle/run-sst-command.js +750 -71
  103. package/src/executors/sst-lifecycle/schema.json +8 -1
  104. package/src/executors/sst-lifecycle/secret-preflight.d.ts +2 -0
  105. package/src/executors/sst-lifecycle/secret-preflight.js +13 -7
  106. package/src/executors/sst-lifecycle/sst-environment-source.d.ts +33 -0
  107. package/src/executors/sst-lifecycle/sst-environment-source.js +267 -0
  108. package/src/executors/sst-lifecycle/task-unlock.d.ts +15 -0
  109. package/src/executors/sst-lifecycle/task-unlock.js +126 -0
  110. package/src/executors/unlock/unlock.js +2 -2
  111. package/src/foundation/capability-plan.d.ts +43 -0
  112. package/src/foundation/capability-plan.js +168 -0
  113. package/src/foundation/cost-estimate.d.ts +170 -0
  114. package/src/foundation/cost-estimate.js +683 -0
  115. package/src/foundation/discovery.d.ts +14 -11
  116. package/src/foundation/discovery.js +32 -6
  117. package/src/foundation/index.d.ts +4 -0
  118. package/src/foundation/index.js +11 -0
  119. package/src/foundation/local-database-contract.d.ts +20 -0
  120. package/src/foundation/local-database-contract.js +262 -13
  121. package/src/foundation/local-private-smoke-access.d.ts +20 -0
  122. package/src/foundation/local-private-smoke-access.js +197 -0
  123. package/src/foundation/logging-preflight.js +1 -1
  124. package/src/foundation/logging.d.ts +3 -1
  125. package/src/foundation/logging.js +1 -1
  126. package/src/foundation/partial-state.d.ts +10 -0
  127. package/src/foundation/partial-state.js +21 -0
  128. package/src/foundation/preflight.js +37 -18
  129. package/src/foundation/private-smoke-access.d.ts +25 -0
  130. package/src/foundation/private-smoke-access.js +135 -0
  131. package/src/foundation/private-smoke-admission.d.ts +45 -0
  132. package/src/foundation/private-smoke-admission.js +180 -0
  133. package/src/foundation/private-smoke-control-plane.d.ts +18 -0
  134. package/src/foundation/private-smoke-control-plane.js +184 -0
  135. package/src/foundation/provision-database-bindings.d.ts +5 -0
  136. package/src/foundation/provision-database-bindings.js +41 -8
  137. package/src/foundation/provision-logical-database.js +15 -8
  138. package/src/foundation/requirements.d.ts +3 -3
  139. package/src/foundation/requirements.js +24 -12
  140. package/src/foundation/router-waf-rate-rehearsal.d.ts +97 -0
  141. package/src/foundation/router-waf-rate-rehearsal.js +210 -0
  142. package/src/foundation/router-waf.d.ts +149 -0
  143. package/src/foundation/router-waf.js +809 -0
  144. package/src/foundation/stages.d.ts +1 -0
  145. package/src/foundation/stages.js +11 -0
  146. package/src/generators/blueprint/blueprint.d.ts +5 -0
  147. package/src/generators/blueprint/blueprint.js +102 -0
  148. package/src/generators/blueprint/files.d.ts +6 -0
  149. package/src/generators/blueprint/files.js +217 -0
  150. package/src/generators/blueprint/schema.d.ts +4 -0
  151. package/src/generators/blueprint/schema.json +18 -0
  152. package/src/generators/formatting.d.ts +8 -0
  153. package/src/generators/formatting.js +141 -0
  154. package/src/generators/function/function.js +38 -17
  155. package/src/generators/logging-registry.d.ts +2 -0
  156. package/src/generators/logging-registry.js +22 -0
  157. package/src/generators/post-generation-install.js +2 -2
  158. package/src/generators/preset/dependency-overrides.d.ts +8 -0
  159. package/src/generators/preset/dependency-overrides.js +55 -0
  160. package/src/generators/preset/generator.js +43 -3
  161. package/src/generators/preset/schema.d.ts +10 -0
  162. package/src/generators/preset/schema.json +47 -0
  163. package/src/generators/preset/workspace-files-adopter-skills.d.ts +7 -0
  164. package/src/generators/preset/workspace-files-adopter-skills.js +324 -0
  165. package/src/generators/preset/workspace-files-ci-acceptance.d.ts +1 -0
  166. package/src/generators/preset/workspace-files-ci-acceptance.js +791 -0
  167. package/src/generators/preset/workspace-files-ci-install.d.ts +2 -0
  168. package/src/generators/preset/workspace-files-ci-install.js +196 -0
  169. package/src/generators/preset/workspace-files-developer-agent.d.ts +2 -0
  170. package/src/generators/preset/workspace-files-developer-agent.js +162 -44
  171. package/src/generators/preset/workspace-files-ecr-inspector.d.ts +18 -0
  172. package/src/generators/preset/workspace-files-ecr-inspector.js +298 -0
  173. package/src/generators/preset/workspace-files-foundation-workload-roles.js +5 -2
  174. package/src/generators/preset/workspace-files-performance-cost.d.ts +2 -2
  175. package/src/generators/preset/workspace-files-performance-cost.js +8 -8
  176. package/src/generators/preset/workspace-files-performance-load.d.ts +1 -1
  177. package/src/generators/preset/workspace-files-performance-load.js +39 -25
  178. package/src/generators/preset/workspace-files-shared-operation-claims.d.ts +10 -0
  179. package/src/generators/preset/workspace-files-shared-operation-claims.js +59 -0
  180. package/src/generators/preset/workspace-files-stage-authority.d.ts +6 -0
  181. package/src/generators/preset/workspace-files-stage-authority.js +529 -0
  182. package/src/generators/preset/workspace-files-thin-deploy.d.ts +65 -0
  183. package/src/generators/preset/workspace-files-thin-deploy.js +2507 -0
  184. package/src/generators/preset/workspace-files-thin-docs.d.ts +7 -0
  185. package/src/generators/preset/workspace-files-thin-docs.js +370 -0
  186. package/src/generators/preset/workspace-files-thin-release.d.ts +14 -0
  187. package/src/generators/preset/workspace-files-thin-release.js +26 -0
  188. package/src/generators/preset/workspace-files-workload-role-baseline.js +254 -42
  189. package/src/generators/preset/workspace-files.d.ts +18 -2
  190. package/src/generators/preset/workspace-files.js +1525 -609
  191. package/src/generators/repository-policy/repository-policy.js +235 -5
  192. package/src/generators/repository-policy/schema.d.ts +10 -0
  193. package/src/generators/repository-policy/schema.json +80 -4
  194. package/src/generators/repository-policy/tree-policy.d.ts +3 -0
  195. package/src/generators/repository-policy/tree-policy.js +25 -0
  196. package/src/generators/slice/built-in-plan-api-contract-files.js +49 -11
  197. package/src/generators/slice/built-in-plan-api-files.d.ts +1 -1
  198. package/src/generators/slice/built-in-plan-api-files.js +130 -414
  199. package/src/generators/slice/built-in-plan-async-work-files.js +166 -1969
  200. package/src/generators/slice/built-in-plan-authorization-files.js +102 -334
  201. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +975 -233
  202. package/src/generators/slice/built-in-plan-authorization-storage.d.ts +3 -0
  203. package/src/generators/slice/built-in-plan-authorization-storage.js +119 -0
  204. package/src/generators/slice/built-in-plan-background-work-files.d.ts +2 -0
  205. package/src/generators/slice/built-in-plan-background-work-files.js +99 -0
  206. package/src/generators/slice/built-in-plan-data-deletion-files.js +2 -830
  207. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js +5 -31
  208. package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
  209. package/src/generators/slice/built-in-plan-data-files.js +176 -1200
  210. package/src/generators/slice/built-in-plan-data-lifecycle-files.js +53 -28
  211. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +37 -2
  212. package/src/generators/slice/built-in-plan-data-retention-job-files.js +7 -2443
  213. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +50 -8
  214. package/src/generators/slice/built-in-plan-data-rights-files.js +6 -4482
  215. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +44 -25
  216. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js +25 -2
  217. package/src/generators/slice/built-in-plan-foundation-files.d.ts +2 -1
  218. package/src/generators/slice/built-in-plan-foundation-files.js +39 -18
  219. package/src/generators/slice/built-in-plan-frontend-files.js +14 -3
  220. package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
  221. package/src/generators/slice/built-in-plan-infrastructure-files.js +933 -730
  222. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js +75 -14
  223. package/src/generators/slice/built-in-plan-key-value-cleanup.d.ts +4 -0
  224. package/src/generators/slice/built-in-plan-key-value-cleanup.js +100 -0
  225. package/src/generators/slice/built-in-plan-key-value-consumer.d.ts +4 -0
  226. package/src/generators/slice/built-in-plan-key-value-consumer.js +151 -0
  227. package/src/generators/slice/built-in-plan-key-value-deletion.d.ts +2 -0
  228. package/src/generators/slice/built-in-plan-key-value-deletion.js +377 -0
  229. package/src/generators/slice/built-in-plan-key-value-delivery.d.ts +2 -0
  230. package/src/generators/slice/built-in-plan-key-value-delivery.js +137 -0
  231. package/src/generators/slice/built-in-plan-key-value-export.d.ts +2 -0
  232. package/src/generators/slice/built-in-plan-key-value-export.js +595 -0
  233. package/src/generators/slice/built-in-plan-key-value-files.d.ts +2 -0
  234. package/src/generators/slice/built-in-plan-key-value-files.js +31 -0
  235. package/src/generators/slice/built-in-plan-key-value-holds.d.ts +2 -0
  236. package/src/generators/slice/built-in-plan-key-value-holds.js +189 -0
  237. package/src/generators/slice/built-in-plan-key-value-infrastructure.d.ts +2 -0
  238. package/src/generators/slice/built-in-plan-key-value-infrastructure.js +102 -0
  239. package/src/generators/slice/built-in-plan-key-value-performance.d.ts +5 -0
  240. package/src/generators/slice/built-in-plan-key-value-performance.js +530 -0
  241. package/src/generators/slice/built-in-plan-key-value-provider.d.ts +4 -0
  242. package/src/generators/slice/built-in-plan-key-value-provider.js +366 -0
  243. package/src/generators/slice/built-in-plan-key-value-records.d.ts +3 -0
  244. package/src/generators/slice/built-in-plan-key-value-records.js +232 -0
  245. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.d.ts +2 -0
  246. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +103 -0
  247. package/src/generators/slice/built-in-plan-key-value-retention-job-files.d.ts +2 -0
  248. package/src/generators/slice/built-in-plan-key-value-retention-job-files.js +160 -0
  249. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.d.ts +2 -0
  250. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.js +329 -0
  251. package/src/generators/slice/built-in-plan-key-value-retention-worker.d.ts +2 -0
  252. package/src/generators/slice/built-in-plan-key-value-retention-worker.js +477 -0
  253. package/src/generators/slice/built-in-plan-key-value-retention.d.ts +2 -0
  254. package/src/generators/slice/built-in-plan-key-value-retention.js +184 -0
  255. package/src/generators/slice/built-in-plan-metadata-files.d.ts +1 -1
  256. package/src/generators/slice/built-in-plan-metadata-files.js +159 -29
  257. package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +2 -0
  258. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +324 -0
  259. package/src/generators/slice/built-in-plan-operations-files.d.ts +1 -1
  260. package/src/generators/slice/built-in-plan-operations-files.js +585 -97
  261. package/src/generators/slice/built-in-plan-performance-files.d.ts +2 -1
  262. package/src/generators/slice/built-in-plan-performance-files.js +220 -1074
  263. package/src/generators/slice/built-in-plan-project-files.js +141 -135
  264. package/src/generators/slice/built-in-plan-release-files.d.ts +1 -1
  265. package/src/generators/slice/built-in-plan-release-files.js +310 -70
  266. package/src/generators/slice/built-in-plan-reliability-files.d.ts +1 -1
  267. package/src/generators/slice/built-in-plan-reliability-files.js +283 -44
  268. package/src/generators/slice/built-in-plan-secret-runtime-files.d.ts +1 -1
  269. package/src/generators/slice/built-in-plan-secret-runtime-files.js +87 -76
  270. package/src/generators/slice/built-in-plan-shared.d.ts +4 -2
  271. package/src/generators/slice/built-in-plan-shared.js +41 -19
  272. package/src/generators/slice/built-in-plan-sql-events.d.ts +2 -0
  273. package/src/generators/slice/built-in-plan-sql-events.js +276 -0
  274. package/src/generators/slice/built-in-plan-testing-files.d.ts +1 -1
  275. package/src/generators/slice/built-in-plan-testing-files.js +304 -172
  276. package/src/generators/slice/built-in-plan-testing-persistence-event-files.d.ts +7 -0
  277. package/src/generators/slice/built-in-plan-testing-persistence-event-files.js +487 -0
  278. package/src/generators/slice/built-in-plan-testing-persistence-files.d.ts +2 -0
  279. package/src/generators/slice/built-in-plan-testing-persistence-files.js +180 -0
  280. package/src/generators/slice/built-in-plan-thin-release-files.d.ts +11 -0
  281. package/src/generators/slice/built-in-plan-thin-release-files.js +162 -0
  282. package/src/generators/slice/built-in-plan-verification-files.js +76 -2
  283. package/src/generators/slice/built-in-plan-web-files.d.ts +1 -1
  284. package/src/generators/slice/built-in-plan-web-files.js +223 -16
  285. package/src/generators/slice/built-in-plan-workload-role-files.d.ts +1 -1
  286. package/src/generators/slice/built-in-plan-workload-role-files.js +143 -279
  287. package/src/generators/slice/built-in-plan.d.ts +11 -1
  288. package/src/generators/slice/built-in-plan.js +83 -30
  289. package/src/generators/slice/data-policy-review-seed.d.ts +2 -0
  290. package/src/generators/slice/data-policy-review-seed.js +22 -0
  291. package/src/generators/slice/deployed-smoke-readiness.d.ts +2 -0
  292. package/src/generators/slice/deployed-smoke-readiness.js +214 -0
  293. package/src/generators/slice/local-source-identity.d.ts +2 -0
  294. package/src/generators/slice/local-source-identity.js +31 -0
  295. package/src/generators/slice/persistence-contract.d.ts +14 -0
  296. package/src/generators/slice/persistence-contract.js +32 -0
  297. package/src/generators/slice/slice.js +61 -50
  298. package/src/generators/sql/schema.d.ts +7 -0
  299. package/src/generators/sql/schema.json +38 -0
  300. package/src/generators/sql/sql.d.ts +6 -0
  301. package/src/generators/sql/sql.js +53 -0
  302. package/src/generators/upgrade/sql-seeded-reconciliation.d.ts +2 -0
  303. package/src/generators/upgrade/sql-seeded-reconciliation.js +170 -0
  304. package/src/generators/upgrade/upgrade.d.ts +15 -1
  305. package/src/generators/upgrade/upgrade.js +435 -44
  306. package/src/generators/workload/frozen-container.d.ts +1 -1
  307. package/src/generators/workload/performance-registration.d.ts +1 -0
  308. package/src/generators/workload/performance-registration.js +9 -11
  309. package/src/generators/workload/service-performance-files.d.ts +1 -0
  310. package/src/generators/workload/service-performance-files.js +27 -7
  311. package/src/generators/workload/workload.d.ts +1 -1
  312. package/src/generators/workload/workload.js +105 -29
  313. package/src/git-policy/action-pins.d.ts +5 -0
  314. package/src/git-policy/action-pins.js +5 -0
  315. package/src/git-policy/github-bootstrap.d.ts +48 -8
  316. package/src/git-policy/github-bootstrap.js +344 -176
  317. package/src/git-policy/routing.d.ts +7 -1
  318. package/src/git-policy/routing.js +62 -1
  319. package/src/index.d.ts +1 -0
  320. package/src/index.js +1 -0
  321. package/src/infrastructure-change/local-capability.d.ts +73 -0
  322. package/src/infrastructure-change/local-capability.js +114 -0
  323. package/src/infrastructure-change/model.d.ts +25 -4
  324. package/src/infrastructure-change/model.js +1 -0
  325. package/src/infrastructure-change/normalize.d.ts +4 -0
  326. package/src/infrastructure-change/normalize.js +47 -7
  327. package/src/infrastructure-change/plan.d.ts +30 -3
  328. package/src/infrastructure-change/plan.js +323 -13
  329. package/src/infrastructure-change/risk.d.ts +3 -1
  330. package/src/infrastructure-change/risk.js +96 -16
  331. package/src/local-dev/browser-verification.d.ts +37 -0
  332. package/src/local-dev/browser-verification.js +281 -0
  333. package/src/local-dev/contracts.d.ts +10 -1
  334. package/src/local-dev/contracts.js +114 -13
  335. package/src/local-dev/dev-command-core.js +24 -5
  336. package/src/local-dev/docker-credential-health.d.ts +14 -0
  337. package/src/local-dev/docker-credential-health.js +94 -0
  338. package/src/local-dev/environment-inspector.d.ts +7 -0
  339. package/src/local-dev/environment-inspector.js +42 -15
  340. package/src/local-dev/environment-state.js +2 -2
  341. package/src/local-dev/errors.d.ts +1 -1
  342. package/src/local-dev/errors.js +2 -0
  343. package/src/local-dev/fleet-client.js +2 -2
  344. package/src/local-dev/fleet-configuration.js +57 -25
  345. package/src/local-dev/fleet-inventory.js +58 -22
  346. package/src/local-dev/fleet-ipc.d.ts +7 -0
  347. package/src/local-dev/fleet-ipc.js +14 -2
  348. package/src/local-dev/fleet-launcher.d.ts +6 -0
  349. package/src/local-dev/fleet-launcher.js +16 -4
  350. package/src/local-dev/fleet-logs.js +50 -22
  351. package/src/local-dev/fleet-process.d.ts +20 -1
  352. package/src/local-dev/fleet-process.js +197 -41
  353. package/src/local-dev/fleet-runner-evidence.d.ts +5 -0
  354. package/src/local-dev/fleet-runner-evidence.js +56 -0
  355. package/src/local-dev/fleet-runtime.js +268 -229
  356. package/src/local-dev/fleet-session.d.ts +2 -0
  357. package/src/local-dev/fleet-session.js +28 -11
  358. package/src/local-dev/fleet-slice-runner-daemon.js +4 -0
  359. package/src/local-dev/fleet-state.d.ts +5 -2
  360. package/src/local-dev/fleet-state.js +25 -4
  361. package/src/local-dev/fleet-supervisor.d.ts +3 -0
  362. package/src/local-dev/fleet-supervisor.js +66 -11
  363. package/src/local-dev/fleet-web-start.d.ts +12 -0
  364. package/src/local-dev/fleet-web-start.js +48 -0
  365. package/src/local-dev/identity.js +3 -14
  366. package/src/local-dev/index.d.ts +1 -0
  367. package/src/local-dev/index.js +1 -0
  368. package/src/local-dev/native-completion.d.ts +9 -0
  369. package/src/local-dev/native-completion.js +130 -0
  370. package/src/local-dev/nx-workspace.d.ts +4 -2
  371. package/src/local-dev/nx-workspace.js +11 -6
  372. package/src/local-dev/personal-stage.d.ts +4 -5
  373. package/src/local-dev/personal-stage.js +6 -54
  374. package/src/local-dev/port-claims.d.ts +13 -0
  375. package/src/local-dev/port-claims.js +46 -0
  376. package/src/local-dev/ports.d.ts +14 -2
  377. package/src/local-dev/ports.js +78 -3
  378. package/src/local-dev/private-state.d.ts +11 -0
  379. package/src/local-dev/private-state.js +146 -40
  380. package/src/local-dev/process-group.d.ts +4 -0
  381. package/src/local-dev/process-group.js +29 -0
  382. package/src/local-dev/process-identity.d.ts +8 -0
  383. package/src/local-dev/process-identity.js +31 -1
  384. package/src/local-dev/proxy.js +11 -12
  385. package/src/local-dev/runtime-paths.js +1 -1
  386. package/src/local-dev/slice-claim.js +1 -1
  387. package/src/local-dev/slice-runner.d.ts +15 -6
  388. package/src/local-dev/slice-runner.js +189 -54
  389. package/src/local-dev/task-attachment.d.ts +17 -0
  390. package/src/local-dev/task-attachment.js +73 -0
  391. package/src/local-dev/task-authority.d.ts +10 -0
  392. package/src/local-dev/task-authority.js +27 -0
  393. package/src/local-dev/task-identity.d.ts +33 -0
  394. package/src/local-dev/task-identity.js +418 -0
  395. package/src/local-dev/task-native-writer.d.ts +18 -0
  396. package/src/local-dev/task-native-writer.js +329 -0
  397. package/src/local-dev/tls.js +8 -2
  398. package/src/local-dev/web-launch.d.ts +9 -0
  399. package/src/local-dev/web-launch.js +130 -0
  400. package/src/ownership/composition.d.ts +2 -1
  401. package/src/ownership/composition.js +1 -0
  402. package/src/performance/cost-collection.d.ts +1 -1
  403. package/src/performance/cost-collection.js +4 -2
  404. package/src/performance/cost-controls.d.ts +8 -4
  405. package/src/performance/cost-controls.js +39 -28
  406. package/src/performance/evidence.d.ts +1 -1
  407. package/src/performance/evidence.js +5 -3
  408. package/src/performance/load-safety.js +5 -3
  409. package/src/performance/model.d.ts +4 -4
  410. package/src/performance/model.js +4 -5
  411. package/src/performance/scenario.d.ts +22 -0
  412. package/src/performance/scenario.js +100 -92
  413. package/src/release/index.d.ts +0 -2
  414. package/src/release/index.js +0 -2
  415. package/src/release/source-authority.d.ts +5 -5
  416. package/src/release/source-authority.js +141 -124
  417. package/src/repository-policy/aurora-preflight.d.ts +1 -1
  418. package/src/repository-policy/aurora-preflight.js +4 -1
  419. package/src/repository-policy/capacity-migration.d.ts +3 -0
  420. package/src/repository-policy/capacity-migration.js +21 -0
  421. package/src/repository-policy/deployment-plan.d.ts +4 -1
  422. package/src/repository-policy/deployment-plan.js +9 -0
  423. package/src/repository-policy/foundation-profile.js +10 -1
  424. package/src/repository-policy/policy.d.ts +57 -3
  425. package/src/repository-policy/policy.js +497 -11
  426. package/src/schemas/blueprint-v1.json +5 -4
  427. package/src/schemas/foundation-requirement-v1.json +5 -4
  428. package/src/schemas/performance-policy-v1.json +3 -3
  429. package/src/schemas/repository-policy-v1.json +130 -6
  430. package/src/schemas/testing-evidence-result-v1.json +1 -1
  431. package/src/secrets/adapters.d.ts +7 -2
  432. package/src/secrets/adapters.js +34 -3
  433. package/src/secrets/aws-control-plane.d.ts +10 -1
  434. package/src/secrets/aws-control-plane.js +67 -0
  435. package/src/secrets/generated-aws-control-plane.d.ts +23 -0
  436. package/src/secrets/generated-aws-control-plane.js +259 -0
  437. package/src/secrets/metadata.js +38 -10
  438. package/src/secrets/model.d.ts +8 -1
  439. package/src/secrets/model.js +24 -3
  440. package/src/secrets/operator.d.ts +91 -3
  441. package/src/secrets/operator.js +463 -13
  442. package/src/secrets/personal-command.d.ts +18 -2
  443. package/src/secrets/personal-command.js +66 -12
  444. package/src/secrets/registry.d.ts +2 -1
  445. package/src/secrets/registry.js +18 -1
  446. package/src/secrets/verification.js +15 -2
  447. package/src/secrets/workload-access.js +10 -2
  448. package/src/sst-environment-source-format.d.ts +6 -0
  449. package/src/sst-environment-source-format.js +199 -0
  450. package/src/supply-chain/action-pins.js +61 -7
  451. package/src/supply-chain/blueprint-trust-git.js +85 -24
  452. package/src/supply-chain/blueprint-verification-authority.js +55 -3
  453. package/src/supply-chain/build-output-bounds.d.ts +2 -0
  454. package/src/supply-chain/build-output-bounds.js +12 -0
  455. package/src/supply-chain/build-output.d.ts +7 -1
  456. package/src/supply-chain/build-output.js +177 -24
  457. package/src/supply-chain/ecr-scanning.d.ts +5 -3
  458. package/src/supply-chain/ecr-scanning.js +11 -7
  459. package/src/supply-chain/ecs-deployed-image.d.ts +5 -3
  460. package/src/supply-chain/ecs-deployed-image.js +6 -4
  461. package/src/supply-chain/generated-blueprint-trust-command.js +18 -1
  462. package/src/supply-chain/generated-command.js +1 -0
  463. package/src/supply-chain/generated-container-release-command.js +1285 -124
  464. package/src/supply-chain/generated-ecr-collector-command.d.ts +0 -1
  465. package/src/supply-chain/generated-ecr-collector-command.js +200 -93
  466. package/src/supply-chain/generated-files.js +25 -14
  467. package/src/supply-chain/generated-scanner-command.js +2 -1
  468. package/src/supply-chain/index.d.ts +1 -1
  469. package/src/supply-chain/index.js +2 -1
  470. package/src/supply-chain/sbom.d.ts +1 -1
  471. package/src/supply-chain/sbom.js +30 -5
  472. package/src/supply-chain/scanner.js +3 -0
  473. package/src/testing-evidence/fixture-scope.d.ts +2 -1
  474. package/src/testing-evidence/fixture-scope.js +4 -2
  475. package/src/testing-evidence/result.d.ts +2 -1
  476. package/src/testing-evidence/result.js +18 -4
  477. package/src/workload-roles/account-baseline.d.ts +11 -0
  478. package/src/workload-roles/account-baseline.js +253 -16
  479. package/src/workload-roles/authority.d.ts +3 -1
  480. package/src/workload-roles/authority.js +48 -2
  481. package/src/workload-roles/aws-s3-state.js +27 -0
  482. package/src/workload-roles/boundary.d.ts +2 -1
  483. package/src/workload-roles/boundary.js +9 -2
  484. package/src/workload-roles/handler.js +52 -24
  485. package/src/workload-roles/index.d.ts +10 -17
  486. package/src/workload-roles/index.js +5 -18
  487. package/src/workload-roles/injection.js +1 -1
  488. package/src/workload-roles/provisioner.js +12 -4
  489. package/src/workload-roles/registration.d.ts +1 -0
  490. package/src/workload-roles/registration.js +5 -0
  491. package/src/workload-roles/stage-boundary.js +1 -1
  492. package/src/workload-roles/standard-slice.js +3 -3
  493. package/src/workspace-deployment/affected-lifecycle.d.ts +53 -0
  494. package/src/workspace-deployment/affected-lifecycle.js +84 -0
  495. package/src/workspace-deployment/identity.d.ts +3 -0
  496. package/src/workspace-deployment/identity.js +22 -0
  497. package/src/workspace-deployment/index.d.ts +4 -0
  498. package/src/workspace-deployment/index.js +8 -0
  499. package/src/workspace-deployment/migration-evidence.d.ts +29 -0
  500. package/src/workspace-deployment/migration-evidence.js +83 -0
  501. package/src/workspace-deployment/migration.d.ts +27 -0
  502. package/src/workspace-deployment/migration.js +109 -0
  503. package/src/workspace-deployment/ownership.d.ts +81 -0
  504. package/src/workspace-deployment/ownership.js +381 -0
  505. package/src/api-contract/baseline-update.js.map +0 -1
  506. package/src/api-contract/compatibility.js.map +0 -1
  507. package/src/api-contract/contract-graph.js.map +0 -1
  508. package/src/api-contract/evidence.js.map +0 -1
  509. package/src/api-contract/index.js.map +0 -1
  510. package/src/api-contract/model.fixtures.d.ts +0 -2
  511. package/src/api-contract/model.fixtures.js +0 -81
  512. package/src/api-contract/model.fixtures.js.map +0 -1
  513. package/src/api-contract/model.js.map +0 -1
  514. package/src/api-contract/rollout.js.map +0 -1
  515. package/src/authorization/compatibility.js.map +0 -1
  516. package/src/authorization/index.js.map +0 -1
  517. package/src/blueprints/execution.js.map +0 -1
  518. package/src/blueprints/external-sandbox.js.map +0 -1
  519. package/src/blueprints/index.js.map +0 -1
  520. package/src/blueprints/inputs.js.map +0 -1
  521. package/src/blueprints/manifest.js.map +0 -1
  522. package/src/blueprints/resolver.js.map +0 -1
  523. package/src/blueprints/transitions.js.map +0 -1
  524. package/src/cli/agent-command.js.map +0 -1
  525. package/src/cli/agent-runtime.js.map +0 -1
  526. package/src/cli/blueprint-authority.js.map +0 -1
  527. package/src/cli/blueprint-command.js.map +0 -1
  528. package/src/cli/bootstrap.js.map +0 -1
  529. package/src/cli/dev-command.js.map +0 -1
  530. package/src/cli/main.js.map +0 -1
  531. package/src/cli/output.js.map +0 -1
  532. package/src/cli/personal-secret-runtime.js.map +0 -1
  533. package/src/cli/secret-terminal.js.map +0 -1
  534. package/src/container-images.js.map +0 -1
  535. package/src/data-lifecycle/index.js.map +0 -1
  536. package/src/data-lifecycle/model.fixtures.d.ts +0 -2
  537. package/src/data-lifecycle/model.fixtures.js +0 -244
  538. package/src/data-lifecycle/model.fixtures.js.map +0 -1
  539. package/src/data-lifecycle/model.js.map +0 -1
  540. package/src/data-lifecycle/sensitive-artifacts.js.map +0 -1
  541. package/src/data-lifecycle/validation.js.map +0 -1
  542. package/src/database-retirement/contract.js.map +0 -1
  543. package/src/database-retirement/index.js.map +0 -1
  544. package/src/deterministic-order.js.map +0 -1
  545. package/src/developer-agent/context.js.map +0 -1
  546. package/src/developer-agent/generator-planning.js.map +0 -1
  547. package/src/developer-agent/generator-preview.js.map +0 -1
  548. package/src/developer-agent/git-inspection.js.map +0 -1
  549. package/src/developer-agent/handoff.js.map +0 -1
  550. package/src/developer-agent/index.js.map +0 -1
  551. package/src/developer-agent/model.js.map +0 -1
  552. package/src/developer-agent/operation-registry.js.map +0 -1
  553. package/src/developer-agent/ordering.js.map +0 -1
  554. package/src/developer-agent/planning.js.map +0 -1
  555. package/src/developer-agent/preview-changes.js.map +0 -1
  556. package/src/developer-agent/preview-source.js.map +0 -1
  557. package/src/developer-agent/validation.js.map +0 -1
  558. package/src/developer-agent/workspace-inspection.js.map +0 -1
  559. package/src/developer-agent/workspace-path.js.map +0 -1
  560. package/src/executors/blueprint-trust/blueprint-trust.js.map +0 -1
  561. package/src/executors/blueprint-verification/blueprint-verification.js.map +0 -1
  562. package/src/executors/deploy/deploy.js.map +0 -1
  563. package/src/executors/deployment-plan/deployment-plan.js.map +0 -1
  564. package/src/executors/dev/dev.js.map +0 -1
  565. package/src/executors/dev-doctor/dev-doctor.js.map +0 -1
  566. package/src/executors/dev-setup/dev-setup.js.map +0 -1
  567. package/src/executors/developer-context/developer-context.js.map +0 -1
  568. package/src/executors/fleet/fleet.js.map +0 -1
  569. package/src/executors/foundation-preflight/foundation-preflight.js.map +0 -1
  570. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +0 -1
  571. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +0 -1
  572. package/src/executors/github-bootstrap/github-bootstrap.js.map +0 -1
  573. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +0 -1
  574. package/src/executors/refresh/refresh.js.map +0 -1
  575. package/src/executors/remove/remove.js.map +0 -1
  576. package/src/executors/secret-guardrails/secret-guardrails.js.map +0 -1
  577. package/src/executors/secret-metadata/secret-metadata.js.map +0 -1
  578. package/src/executors/sst-lifecycle/logging-preflight.js.map +0 -1
  579. package/src/executors/sst-lifecycle/run-sst-command.js.map +0 -1
  580. package/src/executors/sst-lifecycle/secret-preflight.js.map +0 -1
  581. package/src/executors/unlock/unlock.js.map +0 -1
  582. package/src/executors/work-markers/work-markers.js.map +0 -1
  583. package/src/foundation/discovery.js.map +0 -1
  584. package/src/foundation/index.js.map +0 -1
  585. package/src/foundation/local-database-contract.js.map +0 -1
  586. package/src/foundation/logging-preflight.js.map +0 -1
  587. package/src/foundation/logging.js.map +0 -1
  588. package/src/foundation/preflight.js.map +0 -1
  589. package/src/foundation/provision-database-bindings.js.map +0 -1
  590. package/src/foundation/provision-logical-database.js.map +0 -1
  591. package/src/foundation/requirements.js.map +0 -1
  592. package/src/foundation/router-origin-proof.js.map +0 -1
  593. package/src/foundation/stages.js.map +0 -1
  594. package/src/frontend-security/index.js.map +0 -1
  595. package/src/frontend-security/security-headers.js.map +0 -1
  596. package/src/generators/feature-registry.js.map +0 -1
  597. package/src/generators/function/function.js.map +0 -1
  598. package/src/generators/job/job.js.map +0 -1
  599. package/src/generators/logging-registry.js.map +0 -1
  600. package/src/generators/post-generation-install.js.map +0 -1
  601. package/src/generators/preset/generator.js.map +0 -1
  602. package/src/generators/preset/tool-versions.js.map +0 -1
  603. package/src/generators/preset/workspace-files-developer-agent.js.map +0 -1
  604. package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +0 -1
  605. package/src/generators/preset/workspace-files-performance-cost.js.map +0 -1
  606. package/src/generators/preset/workspace-files-performance-load.js.map +0 -1
  607. package/src/generators/preset/workspace-files-workload-role-baseline.js.map +0 -1
  608. package/src/generators/preset/workspace-files.js.map +0 -1
  609. package/src/generators/repository-policy/repository-policy.js.map +0 -1
  610. package/src/generators/service/service.js.map +0 -1
  611. package/src/generators/slice/built-in-plan-api-contract-files.js.map +0 -1
  612. package/src/generators/slice/built-in-plan-api-files.js.map +0 -1
  613. package/src/generators/slice/built-in-plan-async-work-files.js.map +0 -1
  614. package/src/generators/slice/built-in-plan-authorization-files.js.map +0 -1
  615. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +0 -1
  616. package/src/generators/slice/built-in-plan-data-deletion-files.js.map +0 -1
  617. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +0 -1
  618. package/src/generators/slice/built-in-plan-data-files.js.map +0 -1
  619. package/src/generators/slice/built-in-plan-data-lifecycle-files.js.map +0 -1
  620. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +0 -1
  621. package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +0 -1
  622. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +0 -1
  623. package/src/generators/slice/built-in-plan-data-rights-files.js.map +0 -1
  624. package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +0 -1
  625. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +0 -1
  626. package/src/generators/slice/built-in-plan-foundation-files.js.map +0 -1
  627. package/src/generators/slice/built-in-plan-frontend-files.js.map +0 -1
  628. package/src/generators/slice/built-in-plan-infrastructure-files.js.map +0 -1
  629. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +0 -1
  630. package/src/generators/slice/built-in-plan-metadata-files.js.map +0 -1
  631. package/src/generators/slice/built-in-plan-operations-files.js.map +0 -1
  632. package/src/generators/slice/built-in-plan-performance-files.js.map +0 -1
  633. package/src/generators/slice/built-in-plan-project-files.js.map +0 -1
  634. package/src/generators/slice/built-in-plan-release-files.js.map +0 -1
  635. package/src/generators/slice/built-in-plan-reliability-files.js.map +0 -1
  636. package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +0 -1
  637. package/src/generators/slice/built-in-plan-shared.js.map +0 -1
  638. package/src/generators/slice/built-in-plan-testing-files.js.map +0 -1
  639. package/src/generators/slice/built-in-plan-verification-files.js.map +0 -1
  640. package/src/generators/slice/built-in-plan-web-files.js.map +0 -1
  641. package/src/generators/slice/built-in-plan-workload-role-files.js.map +0 -1
  642. package/src/generators/slice/built-in-plan.js.map +0 -1
  643. package/src/generators/slice/slice.js.map +0 -1
  644. package/src/generators/upgrade/upgrade.js.map +0 -1
  645. package/src/generators/workload/frozen-container.js.map +0 -1
  646. package/src/generators/workload/performance-registration.js.map +0 -1
  647. package/src/generators/workload/reliability-registration.js.map +0 -1
  648. package/src/generators/workload/service-performance-files.js.map +0 -1
  649. package/src/generators/workload/workload.js.map +0 -1
  650. package/src/git-policy/action-pins.js.map +0 -1
  651. package/src/git-policy/github-bootstrap.js.map +0 -1
  652. package/src/git-policy/index.js.map +0 -1
  653. package/src/git-policy/routing.js.map +0 -1
  654. package/src/index.js.map +0 -1
  655. package/src/infrastructure-change/convergence.js.map +0 -1
  656. package/src/infrastructure-change/drift.js.map +0 -1
  657. package/src/infrastructure-change/index.js.map +0 -1
  658. package/src/infrastructure-change/model.js.map +0 -1
  659. package/src/infrastructure-change/normalize.js.map +0 -1
  660. package/src/infrastructure-change/plan.js.map +0 -1
  661. package/src/infrastructure-change/risk.js.map +0 -1
  662. package/src/infrastructure-change/summary.js.map +0 -1
  663. package/src/local-dev/context-discovery.js.map +0 -1
  664. package/src/local-dev/contract-validation.js.map +0 -1
  665. package/src/local-dev/contracts.js.map +0 -1
  666. package/src/local-dev/control-contract.js.map +0 -1
  667. package/src/local-dev/dev-command-core.js.map +0 -1
  668. package/src/local-dev/effects.js.map +0 -1
  669. package/src/local-dev/environment-inspector.js.map +0 -1
  670. package/src/local-dev/environment-state.js.map +0 -1
  671. package/src/local-dev/errors.js.map +0 -1
  672. package/src/local-dev/fleet-client.js.map +0 -1
  673. package/src/local-dev/fleet-configuration.js.map +0 -1
  674. package/src/local-dev/fleet-inventory.js.map +0 -1
  675. package/src/local-dev/fleet-ipc.js.map +0 -1
  676. package/src/local-dev/fleet-launcher.js.map +0 -1
  677. package/src/local-dev/fleet-lock.js.map +0 -1
  678. package/src/local-dev/fleet-logs.js.map +0 -1
  679. package/src/local-dev/fleet-process.js.map +0 -1
  680. package/src/local-dev/fleet-runtime.js.map +0 -1
  681. package/src/local-dev/fleet-session.js.map +0 -1
  682. package/src/local-dev/fleet-slice-runner-daemon.js.map +0 -1
  683. package/src/local-dev/fleet-startup.js.map +0 -1
  684. package/src/local-dev/fleet-state.js.map +0 -1
  685. package/src/local-dev/fleet-supervisor-daemon.js.map +0 -1
  686. package/src/local-dev/fleet-supervisor.js.map +0 -1
  687. package/src/local-dev/gateway-daemon.js.map +0 -1
  688. package/src/local-dev/gateway.js.map +0 -1
  689. package/src/local-dev/identity.js.map +0 -1
  690. package/src/local-dev/index.js.map +0 -1
  691. package/src/local-dev/local-context.js.map +0 -1
  692. package/src/local-dev/nx-workspace.js.map +0 -1
  693. package/src/local-dev/personal-secret-ledger.js.map +0 -1
  694. package/src/local-dev/personal-stage.js.map +0 -1
  695. package/src/local-dev/portless.js.map +0 -1
  696. package/src/local-dev/ports.js.map +0 -1
  697. package/src/local-dev/private-state.js.map +0 -1
  698. package/src/local-dev/process-identity.js.map +0 -1
  699. package/src/local-dev/proxy.js.map +0 -1
  700. package/src/local-dev/runtime-paths.js.map +0 -1
  701. package/src/local-dev/secret-slice-claim.js.map +0 -1
  702. package/src/local-dev/slice-claim.js.map +0 -1
  703. package/src/local-dev/slice-runner.js.map +0 -1
  704. package/src/local-dev/tls.js.map +0 -1
  705. package/src/ownership/composition.js.map +0 -1
  706. package/src/ownership/foundation-record.js.map +0 -1
  707. package/src/ownership/hash.js.map +0 -1
  708. package/src/ownership/index.js.map +0 -1
  709. package/src/ownership/json-ownership.js.map +0 -1
  710. package/src/ownership/record.js.map +0 -1
  711. package/src/ownership/workspace-record.js.map +0 -1
  712. package/src/performance/cost-collection.js.map +0 -1
  713. package/src/performance/cost-controls.js.map +0 -1
  714. package/src/performance/evidence.js.map +0 -1
  715. package/src/performance/index.js.map +0 -1
  716. package/src/performance/load-safety.js.map +0 -1
  717. package/src/performance/model.js.map +0 -1
  718. package/src/performance/pr-artifact-budget.js.map +0 -1
  719. package/src/performance/runner.js.map +0 -1
  720. package/src/performance/scenario-endpoint.js.map +0 -1
  721. package/src/performance/scenario.js.map +0 -1
  722. package/src/performance/test-fixtures.d.ts +0 -7
  723. package/src/performance/test-fixtures.js +0 -169
  724. package/src/performance/test-fixtures.js.map +0 -1
  725. package/src/performance/unit-cost.js.map +0 -1
  726. package/src/release/index.js.map +0 -1
  727. package/src/release/lifecycle.js.map +0 -1
  728. package/src/release/manifest.js.map +0 -1
  729. package/src/release/rollout.js.map +0 -1
  730. package/src/release/source-authority.js.map +0 -1
  731. package/src/repository-policy/aurora-preflight.js.map +0 -1
  732. package/src/repository-policy/deployment-plan.js.map +0 -1
  733. package/src/repository-policy/foundation-profile.js.map +0 -1
  734. package/src/repository-policy/index.js.map +0 -1
  735. package/src/repository-policy/policy.js.map +0 -1
  736. package/src/secrets/adapters.js.map +0 -1
  737. package/src/secrets/aws-control-plane.js.map +0 -1
  738. package/src/secrets/declaration-verification.js.map +0 -1
  739. package/src/secrets/guardrails.js.map +0 -1
  740. package/src/secrets/index.js.map +0 -1
  741. package/src/secrets/metadata.js.map +0 -1
  742. package/src/secrets/model.js.map +0 -1
  743. package/src/secrets/operator.js.map +0 -1
  744. package/src/secrets/permissions.js.map +0 -1
  745. package/src/secrets/personal-command.js.map +0 -1
  746. package/src/secrets/personal-ledger.js.map +0 -1
  747. package/src/secrets/registry.js.map +0 -1
  748. package/src/secrets/verification.js.map +0 -1
  749. package/src/secrets/workload-access.js.map +0 -1
  750. package/src/supply-chain/action-pins.js.map +0 -1
  751. package/src/supply-chain/blueprint-trust-git.js.map +0 -1
  752. package/src/supply-chain/blueprint-trust-process.js.map +0 -1
  753. package/src/supply-chain/blueprint-trust.js.map +0 -1
  754. package/src/supply-chain/blueprint-verification-authority.js.map +0 -1
  755. package/src/supply-chain/blueprint-verification-execution.js.map +0 -1
  756. package/src/supply-chain/build-output.js.map +0 -1
  757. package/src/supply-chain/common.js.map +0 -1
  758. package/src/supply-chain/container-artifact-contract.js.map +0 -1
  759. package/src/supply-chain/container-release.js.map +0 -1
  760. package/src/supply-chain/ecr-applicability.js.map +0 -1
  761. package/src/supply-chain/ecr-scanning.js.map +0 -1
  762. package/src/supply-chain/ecs-deployed-image.js.map +0 -1
  763. package/src/supply-chain/errors.js.map +0 -1
  764. package/src/supply-chain/generated-blueprint-trust-command.js.map +0 -1
  765. package/src/supply-chain/generated-command.js.map +0 -1
  766. package/src/supply-chain/generated-container-release-command.js.map +0 -1
  767. package/src/supply-chain/generated-ecr-collector-command.js.map +0 -1
  768. package/src/supply-chain/generated-files.js.map +0 -1
  769. package/src/supply-chain/generated-scanner-command.js.map +0 -1
  770. package/src/supply-chain/index.js.map +0 -1
  771. package/src/supply-chain/inventory.js.map +0 -1
  772. package/src/supply-chain/license-expression.js.map +0 -1
  773. package/src/supply-chain/pnpm-toolchain-authority.js.map +0 -1
  774. package/src/supply-chain/policy.js.map +0 -1
  775. package/src/supply-chain/publication.js.map +0 -1
  776. package/src/supply-chain/sbom.js.map +0 -1
  777. package/src/supply-chain/scanner.js.map +0 -1
  778. package/src/supply-chain/vendored-source.js.map +0 -1
  779. package/src/testing-evidence/fixture-scope.js.map +0 -1
  780. package/src/testing-evidence/index.js.map +0 -1
  781. package/src/testing-evidence/quarantine.js.map +0 -1
  782. package/src/testing-evidence/result.js.map +0 -1
  783. package/src/testing-evidence/runner-adapter.js.map +0 -1
  784. package/src/testing-evidence/sensitive-artifacts.js.map +0 -1
  785. package/src/validation.js.map +0 -1
  786. package/src/work-markers/index.js.map +0 -1
  787. package/src/work-markers/work-markers.js.map +0 -1
  788. package/src/workload-roles/account-baseline.js.map +0 -1
  789. package/src/workload-roles/authority.js.map +0 -1
  790. package/src/workload-roles/aws-adapter.js.map +0 -1
  791. package/src/workload-roles/aws-internal-handler.js.map +0 -1
  792. package/src/workload-roles/aws-s3-state.js.map +0 -1
  793. package/src/workload-roles/aws-sdk-control-plane.js.map +0 -1
  794. package/src/workload-roles/boundary.js.map +0 -1
  795. package/src/workload-roles/convergence.js.map +0 -1
  796. package/src/workload-roles/effective-policy.js.map +0 -1
  797. package/src/workload-roles/handler.js.map +0 -1
  798. package/src/workload-roles/history.js.map +0 -1
  799. package/src/workload-roles/index.js.map +0 -1
  800. package/src/workload-roles/injection.js.map +0 -1
  801. package/src/workload-roles/manifest.js.map +0 -1
  802. package/src/workload-roles/provisioner.js.map +0 -1
  803. package/src/workload-roles/registration.js.map +0 -1
  804. package/src/workload-roles/stage-boundary.js.map +0 -1
  805. package/src/workload-roles/standard-slice.js.map +0 -1
@@ -2,180 +2,397 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderProductInfrastructureFiles = renderProductInfrastructureFiles;
4
4
  const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
5
+ const built_in_plan_key_value_retention_infrastructure_js_1 = require("./built-in-plan-key-value-retention-infrastructure.js");
5
6
  /** @internal */
6
- function renderProductInfrastructureFiles(name, pascalName, workspace) {
7
+ function renderProductInfrastructureFiles(name, pascalName, workspace, protectedRuntimeStages = ['staging', 'production'], sql = false, network = sql) {
7
8
  const identifierPrefix = (0, built_in_plan_shared_js_1.lowerCamelIdentifier)(pascalName);
8
9
  const recordExportWorkflowName = (0, built_in_plan_shared_js_1.stableGeneratedName)(40, name);
9
- return {
10
- 'jobs/data-retention-maintenance-launcher.ts': `import {
11
- ECSClient,
12
- RunTaskCommand,
13
- } from '@aws-sdk/client-ecs';
14
- import { createLogger } from '@empire-builder-kit/runtime/logging';
10
+ const files = {
11
+ 'infra/event-subscriptions.ts': `/** Read the existing seeded event contract; never broaden source or stage routing. */
12
+ export function sameSliceEventDetailTypes(value: unknown): string[] {
13
+ const contract = value as {
14
+ kind?: unknown;
15
+ schemaVersion?: unknown;
16
+ slice?: unknown;
17
+ events?: unknown;
18
+ } | null;
19
+ if (
20
+ !contract || contract.kind !== 'ebk-event-contract-schema' ||
21
+ contract.schemaVersion !== 1 || contract.slice !== '${name}' ||
22
+ !Array.isArray(contract.events) || contract.events.length < 2 ||
23
+ contract.events.length > 32
24
+ ) throw new Error('Event subscriptions require the bounded seeded ${name} EventContractSchema.');
25
+ const types = new Set<string>();
26
+ for (const raw of contract.events) {
27
+ const event = raw as {
28
+ detailType?: unknown;
29
+ source?: unknown;
30
+ schemaVersion?: unknown;
31
+ data?: unknown;
32
+ } | null;
33
+ if (
34
+ !event || typeof event.detailType !== 'string' ||
35
+ !/^[A-Za-z][A-Za-z0-9._-]{0,127}$/.test(event.detailType) ||
36
+ event.source !== '${name}' || typeof event.schemaVersion !== 'number' ||
37
+ !Number.isSafeInteger(event.schemaVersion) || event.schemaVersion < 1 ||
38
+ !event.data || typeof event.data !== 'object' || Array.isArray(event.data) ||
39
+ types.has(event.detailType)
40
+ ) throw new Error('Event subscriptions require unique literal types, exact Slice sources and valid schemas.');
41
+ types.add(event.detailType);
42
+ }
43
+ if (!types.has('${pascalName}Created') || !types.has('DataLifecycleChanged'))
44
+ throw new Error('The generated event contract must retain its built-in event declarations.');
45
+ // Lifecycle consumers have their own exact source declaration and rule.
46
+ types.delete('DataLifecycleChanged');
47
+ return [...types].sort();
48
+ }
49
+ `,
50
+ 'infra/route-function-materialization.ts': `type RouteFunctionArgs = {
51
+ ebkRouteMaterialization?: unknown;
52
+ handler: string;
53
+ environment?: unknown;
54
+ link?: unknown;
55
+ permissions?: unknown;
56
+ } & Record<string, any>;
15
57
 
16
- const UUID =
17
- /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
18
- const ECS_CLUSTER_ARN =
19
- new RegExp(
20
- '^arn:(?:aws|aws-cn|aws-us-gov):ecs:[a-z0-9-]+:' +
21
- '[0-9]{12}:cluster/[A-Za-z0-9_./-]{1,255}$',
22
- );
23
- const ECS_TASK_DEFINITION_ARN =
24
- /^arn:(?:aws|aws-cn|aws-us-gov):ecs:[a-z0-9-]+:[0-9]{12}:task-definition\\/[A-Za-z0-9_-]{1,255}:[1-9][0-9]*$/;
25
- const NETWORK_ID = /^(?:sg|subnet)-[0-9a-f]{8,32}$/;
26
- const CONTAINER_NAME = /^[A-Za-z0-9_-]{1,255}$/;
58
+ type OutputFactory = (value: any) => {
59
+ apply(callback: (value: any) => any): unknown;
60
+ };
27
61
 
28
- function required(name: string): string {
29
- const value = process.env[name]?.trim();
30
- if (!value) throw new Error(name + ' is required.');
31
- return value;
32
- }
62
+ type RouteRegistrar<Result> = (
63
+ rawRoute: string,
64
+ handler: string,
65
+ args?: Record<string, any>,
66
+ ) => Result;
33
67
 
34
- function requiredArn(name: string, pattern: RegExp): string {
35
- const value = required(name);
36
- if (!pattern.test(value)) {
37
- throw new Error(name + ' is not the exact expected ECS ARN.');
68
+ export function createVpcRouteFunctionMaterializer(input: {
69
+ directHandlers: readonly string[];
70
+ foundationVpc?: unknown;
71
+ output: OutputFactory;
72
+ }) {
73
+ const directHandlerLimit = 2;
74
+ const compositionDirectHandlerLimit = 64;
75
+ const routeFunctionLimit = 23;
76
+ if (
77
+ !Array.isArray(input.directHandlers) ||
78
+ input.directHandlers.length !== directHandlerLimit ||
79
+ input.directHandlers.some(
80
+ (handler) =>
81
+ typeof handler !== 'string' ||
82
+ handler.length === 0 ||
83
+ handler.length > 256,
84
+ ) ||
85
+ new Set(input.directHandlers).size !== input.directHandlers.length
86
+ ) {
87
+ throw new Error(
88
+ 'Direct API routes require the exact bounded unique handler inventory.',
89
+ );
38
90
  }
39
- return value;
40
- }
91
+ const directHandlers = new Set(input.directHandlers);
92
+ const compositionDirectHandlers = new Set<string>();
93
+ const routeFunctions = new Map<string, RouteFunctionArgs>();
94
+ const materializedRouteFunctions = new Set<string>();
41
95
 
42
- function requiredBoolean(name: string): boolean {
43
- const value = required(name);
44
- if (value !== 'true' && value !== 'false') {
45
- throw new Error(name + ' must be exactly true or false.');
46
- }
47
- return value === 'true';
96
+ const transform = (args: any): void => {
97
+ if (
98
+ typeof args !== 'object' ||
99
+ args === null ||
100
+ Array.isArray(args) ||
101
+ typeof args.handler !== 'string' ||
102
+ args.handler.length === 0
103
+ ) {
104
+ throw new Error(
105
+ 'API route handler transforms require one literal handler path.',
106
+ );
107
+ }
108
+ const routeFunction = routeFunctions.get(args.handler);
109
+ if (!routeFunction) {
110
+ if (directHandlers.has(args.handler)) {
111
+ if (args.ebkRouteMaterialization !== undefined) {
112
+ throw new Error(
113
+ 'Built-in direct API route materialization authority is ambiguous.',
114
+ );
115
+ }
116
+ return;
117
+ }
118
+ if (
119
+ args.ebkRouteMaterialization === 'direct' &&
120
+ !compositionDirectHandlers.has(args.handler) &&
121
+ compositionDirectHandlers.size < compositionDirectHandlerLimit
122
+ ) {
123
+ delete args.ebkRouteMaterialization;
124
+ compositionDirectHandlers.add(args.handler);
125
+ return;
126
+ }
127
+ throw new Error(
128
+ 'API route handler lacks registered materialization authority.',
129
+ );
130
+ }
131
+ if (
132
+ args.ebkRouteMaterialization !== undefined ||
133
+ routeFunction.handler !== args.handler ||
134
+ materializedRouteFunctions.has(args.handler)
135
+ ) {
136
+ throw new Error(
137
+ 'VPC API route handler materialization authority is ambiguous.',
138
+ );
139
+ }
140
+
141
+ // SST 4.17.1 resolves the complete FunctionArgs definition before it
142
+ // calls this transform. Passing imported Foundation Outputs as that
143
+ // definition can therefore defer the route component itself during
144
+ // refresh. Keep the definition literal until here, then reproduce
145
+ // functionBuilder's route-over-default merge exactly.
146
+ const defaultEnvironment = args.environment;
147
+ const defaultLink = args.link;
148
+ const defaultPermissions = args.permissions;
149
+ Object.assign(args, routeFunction);
150
+ args.environment = input
151
+ .output([defaultEnvironment, routeFunction.environment])
152
+ .apply(([defaults, route]: [any, any]) => ({
153
+ ...(defaults ?? {}),
154
+ ...(route ?? {}),
155
+ }));
156
+ args.link = input
157
+ .output([defaultLink, routeFunction.link])
158
+ .apply(([defaults, route]: [any, any]) => [
159
+ ...(defaults ?? []),
160
+ ...(route ?? []),
161
+ ]);
162
+ args.permissions = input
163
+ .output([defaultPermissions, routeFunction.permissions])
164
+ .apply(([defaults, route]: [any, any]) => [
165
+ ...(defaults ?? []),
166
+ ...(route ?? []),
167
+ ]);
168
+ materializedRouteFunctions.add(args.handler);
169
+ };
170
+
171
+ const route = <Result>(
172
+ rawRoute: string,
173
+ handler: RouteFunctionArgs,
174
+ args: Record<string, any> | undefined,
175
+ register: RouteRegistrar<Result>,
176
+ ): Result => {
177
+ const handlerPath = handler.handler;
178
+ if (
179
+ typeof rawRoute !== 'string' ||
180
+ rawRoute.length === 0 ||
181
+ rawRoute.length > 512 ||
182
+ typeof handlerPath !== 'string' ||
183
+ handlerPath.length === 0 ||
184
+ handlerPath.length > 256 ||
185
+ typeof register !== 'function' ||
186
+ directHandlers.has(handlerPath) ||
187
+ routeFunctions.has(handlerPath) ||
188
+ routeFunctions.size >= routeFunctionLimit
189
+ ) {
190
+ throw new Error(
191
+ 'VPC API routes require one bounded unique literal handler registration.',
192
+ );
193
+ }
194
+ routeFunctions.set(handlerPath, {
195
+ ...handler,
196
+ handler: handlerPath,
197
+ ...(input.foundationVpc === undefined ? {} : { vpc: input.foundationVpc }),
198
+ });
199
+ try {
200
+ return register(rawRoute, handlerPath, args);
201
+ } catch (error) {
202
+ routeFunctions.delete(handlerPath);
203
+ throw error;
204
+ }
205
+ };
206
+
207
+ return Object.freeze({ route, transform });
48
208
  }
209
+ `,
210
+ 'infra/next-build-authority.ts': `import {
211
+ chmodSync,
212
+ existsSync,
213
+ lstatSync,
214
+ readdirSync,
215
+ realpathSync,
216
+ unlinkSync,
217
+ } from 'node:fs';
218
+ import { join, relative, resolve } from 'node:path';
49
219
 
50
- function requiredNetworkIds(name: string): string[] {
51
- let value: unknown;
52
- try {
53
- value = JSON.parse(required(name));
54
- } catch {
55
- throw new Error(name + ' must be one bounded JSON array.');
56
- }
220
+ const maximumEntries = 65_536;
221
+ const maximumDepth = 64;
222
+ const maximumFinderMetadataFiles = 256;
223
+ const maximumFinderMetadataBytes = 1_048_576n;
224
+
225
+ // SST 4.17.1 awaits FunctionArgs.hook.postbuild after Runtime.Build has
226
+ // materialized the exact directory that its Lambda zipper consumes. Finder
227
+ // metadata removed only from OpenNext's earlier output can be recreated or
228
+ // copied through package-local node_modules before that boundary. Sanitize the
229
+ // final derived bundle here so the bytes reviewed by the infrastructure plan
230
+ // are the bytes SST packages.
231
+ export function removeFinderMetadataFromBuiltFunction(rootPath: string): number {
232
+ const root = resolve(rootPath);
233
+ const rootIdentity = lstatSync(root, { bigint: true });
57
234
  if (
58
- !Array.isArray(value) ||
59
- value.length < 1 ||
60
- value.length > 16 ||
61
- value.some(
62
- (entry) => typeof entry !== 'string' || !NETWORK_ID.test(entry),
63
- )
235
+ !rootIdentity.isDirectory() ||
236
+ rootIdentity.isSymbolicLink() ||
237
+ realpathSync(root) !== root
64
238
  ) {
65
- throw new Error(name + ' must contain only exact AWS network IDs.');
239
+ throw new Error('The built Function root has an invalid identity.');
66
240
  }
67
- return value;
68
- }
69
241
 
70
- function requiredScheduledEventId(event: unknown): string {
71
- const id =
72
- event && typeof event === 'object' && 'id' in event
73
- ? (event as { id?: unknown }).id
74
- : undefined;
75
- if (typeof id !== 'string' || !UUID.test(id)) {
76
- throw new Error('Scheduled maintenance requires one exact event ID.');
242
+ const pendingDirectories = [{ depth: 0, path: root }];
243
+ let observedEntries = 0;
244
+ let removedFinderMetadata = 0;
245
+ while (pendingDirectories.length > 0) {
246
+ const current = pendingDirectories.pop();
247
+ if (!current) break;
248
+ if (current.depth > maximumDepth) {
249
+ throw new Error('The built Function tree exceeds its depth bound.');
250
+ }
251
+ for (const entry of readdirSync(current.path, { withFileTypes: true }).sort(
252
+ (left, right) =>
253
+ left.name < right.name ? -1 : left.name > right.name ? 1 : 0,
254
+ )) {
255
+ observedEntries += 1;
256
+ if (observedEntries > maximumEntries) {
257
+ throw new Error('The built Function tree exceeds its entry bound.');
258
+ }
259
+ const entryPath = join(current.path, entry.name);
260
+ const identity = lstatSync(entryPath, { bigint: true });
261
+ if (entry.name === '.DS_Store') {
262
+ removedFinderMetadata += 1;
263
+ if (
264
+ removedFinderMetadata > maximumFinderMetadataFiles ||
265
+ !identity.isFile() ||
266
+ identity.isSymbolicLink() ||
267
+ identity.nlink !== 1n ||
268
+ identity.size > maximumFinderMetadataBytes
269
+ ) {
270
+ throw new Error(
271
+ 'The built Function Finder metadata has an invalid identity.',
272
+ );
273
+ }
274
+ unlinkSync(entryPath);
275
+ if (existsSync(entryPath)) {
276
+ throw new Error(
277
+ 'The built Function Finder metadata was not removed.',
278
+ );
279
+ }
280
+ continue;
281
+ }
282
+ if (identity.isDirectory() && !identity.isSymbolicLink()) {
283
+ const confined = relative(root, entryPath);
284
+ if (
285
+ confined === '..' ||
286
+ confined.startsWith('../') ||
287
+ resolve(root, confined) !== entryPath
288
+ ) {
289
+ throw new Error('The built Function entry escapes its root.');
290
+ }
291
+ pendingDirectories.push({ depth: current.depth + 1, path: entryPath });
292
+ }
293
+ }
294
+ // Finder can recreate its metadata in the interval between this hook and
295
+ // SST's asynchronous glob/archive pass. On macOS, close that exact race by
296
+ // removing only the owner's write bit from each completed derived
297
+ // directory. The generated build wrapper restores it before the next
298
+ // OpenNext build. Group/other permission bits remain unchanged.
299
+ if (process.platform === 'darwin') {
300
+ const currentIdentity = lstatSync(current.path, { bigint: true });
301
+ if (
302
+ !currentIdentity.isDirectory() ||
303
+ currentIdentity.isSymbolicLink()
304
+ ) {
305
+ throw new Error('The built Function directory changed identity.');
306
+ }
307
+ chmodSync(
308
+ current.path,
309
+ Number((currentIdentity.mode & 0o7_777n) & ~0o200n),
310
+ );
311
+ if ((lstatSync(current.path, { bigint: true }).mode & 0o200n) !== 0n) {
312
+ throw new Error('The built Function directory was not sealed.');
313
+ }
314
+ if (existsSync(join(current.path, '.DS_Store'))) {
315
+ throw new Error(
316
+ 'The built Function Finder metadata raced its final seal.',
317
+ );
318
+ }
319
+ }
77
320
  }
78
- return id.toLowerCase();
321
+ return removedFinderMetadata;
322
+ }
323
+ `,
324
+ 'infra/deployment-receipt.ts': `export interface SuccessfulDeploymentReceiptExpectation {
325
+ account: string;
326
+ project: string;
327
+ region: string;
328
+ sourceCommit: string;
329
+ stage: 'development' | 'staging' | 'production';
79
330
  }
80
331
 
81
- export async function handler(event: unknown) {
82
- const stage = required('EBK_STAGE');
83
- const logger = createLogger({
84
- component: 'job-data-retention-maintenance-launcher',
85
- feature: 'data-lifecycle',
86
- operation: 'retention-maintenance-launch',
87
- slice: '${name}',
88
- stage,
89
- workspace: required('EBK_WORKSPACE'),
90
- });
91
- const correlationId = requiredScheduledEventId(event);
92
- try {
93
- const containerName = required('EBK_MAINTENANCE_CONTAINER_NAME');
94
- if (!CONTAINER_NAME.test(containerName)) {
95
- throw new Error('Maintenance container name is invalid.');
96
- }
97
- const response = await new ECSClient({}).send(
98
- new RunTaskCommand({
99
- cluster: requiredArn('EBK_MAINTENANCE_CLUSTER_ARN', ECS_CLUSTER_ARN),
100
- count: 1,
101
- enableExecuteCommand: false,
102
- launchType: 'FARGATE',
103
- networkConfiguration: {
104
- awsvpcConfiguration: {
105
- assignPublicIp:
106
- requiredBoolean('EBK_MAINTENANCE_ASSIGN_PUBLIC_IP')
107
- ? 'ENABLED'
108
- : 'DISABLED',
109
- securityGroups: requiredNetworkIds(
110
- 'EBK_MAINTENANCE_SECURITY_GROUP_IDS',
111
- ),
112
- subnets: requiredNetworkIds('EBK_MAINTENANCE_SUBNET_IDS'),
113
- },
114
- },
115
- overrides: {
116
- containerOverrides: [
117
- {
118
- command: [
119
- 'node',
120
- 'dist/jobs/data-retention/src/maintenance.js',
121
- ],
122
- environment: [
123
- {
124
- name: 'EBK_MAINTENANCE_CORRELATION_ID',
125
- value: correlationId,
126
- },
127
- ],
128
- name: containerName,
129
- },
130
- ],
131
- },
132
- taskDefinition: requiredArn(
133
- 'EBK_MAINTENANCE_TASK_DEFINITION_ARN',
134
- ECS_TASK_DEFINITION_ARN,
135
- ),
136
- }),
332
+ export function validateSuccessfulDeploymentReceipt(
333
+ value: unknown,
334
+ expected: SuccessfulDeploymentReceiptExpectation,
335
+ ) {
336
+ const receipt = value as {
337
+ account?: unknown;
338
+ authority?: unknown;
339
+ children?: Array<{
340
+ outcome?: unknown;
341
+ project?: unknown;
342
+ target?: unknown;
343
+ }>;
344
+ kind?: unknown;
345
+ migrations?: Record<string, unknown>;
346
+ outcome?: unknown;
347
+ profile?: unknown;
348
+ region?: unknown;
349
+ schemaVersion?: unknown;
350
+ smoke?: Record<string, unknown>;
351
+ source?: { clean?: unknown; commit?: unknown };
352
+ stage?: unknown;
353
+ };
354
+ const deploymentChildren = Array.isArray(receipt?.children)
355
+ ? receipt.children.filter(
356
+ ({ outcome, project, target }) =>
357
+ outcome === 'succeeded' &&
358
+ project === expected.project &&
359
+ target === 'deploy',
360
+ )
361
+ : [];
362
+ if (
363
+ receipt?.kind !== 'ebk-deployment-receipt' ||
364
+ receipt.schemaVersion !== 1 ||
365
+ receipt.outcome !== 'succeeded' ||
366
+ !['local', 'github'].includes(String(receipt.authority)) ||
367
+ !['starter', 'production-isolated', 'fully-isolated'].includes(
368
+ String(receipt.profile),
369
+ ) ||
370
+ receipt.account !== expected.account ||
371
+ receipt.region !== expected.region ||
372
+ receipt.stage !== expected.stage ||
373
+ receipt.source?.clean !== true ||
374
+ receipt.source.commit !== expected.sourceCommit ||
375
+ !Array.isArray(receipt.children) ||
376
+ receipt.children.some(({ outcome }) => outcome !== 'succeeded') ||
377
+ deploymentChildren.length !== 1 ||
378
+ receipt.migrations?.[expected.project] !== 'completed-by-deploy-target' ||
379
+ receipt.smoke?.[expected.project] !== 'passed'
380
+ ) {
381
+ throw new Error(
382
+ 'Protected performance load requires one successful exact-source native deployment receipt.',
137
383
  );
138
- if (
139
- (response.failures?.length ?? 0) !== 0 ||
140
- response.tasks?.length !== 1 ||
141
- !response.tasks[0]?.taskArn
142
- ) {
143
- throw new Error('ECS did not accept exactly one maintenance task.');
144
- }
145
- logger.info('Retention maintenance task launched', {
146
- attributes: { launchCount: 1 },
147
- outcome: 'success',
148
- });
149
- return { accepted: true };
150
- } catch (error) {
151
- logger.error('Retention maintenance task launch failed', {
152
- attributes: {
153
- errorCode:
154
- error instanceof Error
155
- ? error.name.replace(/[^A-Za-z0-9_.-]/g, '').slice(0, 80)
156
- : 'RetentionMaintenanceLaunchError',
157
- },
158
- outcome: 'failure',
159
- });
160
- throw error;
161
384
  }
385
+ return Object.freeze(receipt);
162
386
  }
163
387
  `,
164
388
  'infra/product.ts': `import {
165
389
  createManagedLogGroupContract,
166
390
  createRouterOriginProofInjection,
167
- provisionDatabaseBindings,
391
+ ${sql ? ' provisionDatabaseBindings,\n' : ''}\
168
392
  } from '@empire-builder-kit/nx/foundation';
169
- import { validateReleaseManifest } from '@empire-builder-kit/nx/release';
170
393
  import * as random from '@pulumi/random';
171
394
  import { createHash } from 'node:crypto';
172
- import {
173
- lstatSync,
174
- readFileSync,
175
- readdirSync,
176
- realpathSync,
177
- } from 'node:fs';
178
- import { fileURLToPath } from 'node:url';
395
+ import { readFileSync } from 'node:fs';
179
396
  import {
180
397
  ${identifierPrefix}CleanupRecordExport,
181
398
  ${identifierPrefix}DatabaseHealth,
@@ -203,20 +420,33 @@ import {
203
420
  ${identifierPrefix}UseRecordDelegation,
204
421
  } from '../api/contracts/protected.js';
205
422
  import lifecycleConsumers from '../data/lifecycle-consumers.json';
206
- import databaseBindings from '../database/bindings.json';
423
+ import { EventContractSchema } from '../contracts/events.js';
424
+ import { sameSliceEventDetailTypes } from './event-subscriptions.js';
425
+ ${sql ? "import databaseBindings from '../database/bindings.json';\n" : ''}\
426
+ ${sql ? "import { createSqlOutboxInfrastructure } from './sql-outbox.js';\n" : ''}\
427
+ ${"import { createKeyValueInfrastructure } from './key-value.js';\n"}\
428
+ ${"import { createKeyValueRetentionInfrastructure } from './key-value-retention.js';\n"}\
207
429
  import localConfiguration from '../configuration/local-values.json';
430
+ import backgroundWorkPolicy from '../operations/background-work.json';
431
+ import { backgroundWorkSchedules } from './background-work.js';
208
432
  import { ConfigurationDeclarations } from '../configuration/declarations.js';
209
433
  import { assertAsyncAdapterDeploymentReady } from '../async/recovery-adapters.js';
210
434
  import {
211
435
  getFoundationInfrastructure,
212
- registerProductMigration,
436
+ ${sql ? ' registerProductMigration,\n' : ''}\
213
437
  registerProductRetention,
214
438
  } from './foundation.js';
439
+ import { createVpcRouteFunctionMaterializer } from './route-function-materialization.js';
440
+ import { removeFinderMetadataFromBuiltFunction } from './next-build-authority.js';
215
441
  import {
442
+ createStandardSliceNativeRuntimeAuthority,
443
+ } from './native-runtime-authority/index.js';
444
+ ${sql
445
+ ? `import {
216
446
  standardSliceDatabaseTaskFamily,
217
- standardSliceResourceNames,
218
- } from './workload-roles/effective-intent.js';
219
- import type { StandardSliceWorkloadRolePreflight } from './workload-roles/preflight.js';
447
+ } from './native-runtime-authority/effective-intent.js';
448
+ `
449
+ : ''}\
220
450
  import { createStandardSliceSecretLinks } from './personal-secrets.js';
221
451
  import { create${pascalName}PerformanceCostControls } from './performance-cost-controls.js';
222
452
  import {
@@ -226,10 +456,11 @@ import {
226
456
  } from './authorization.js';
227
457
  import { createStandardDataExportStore } from './data-export.js';
228
458
  import { create${pascalName}Reliability } from './reliability.js';
229
- import { resolveStandardContainerImage } from './container-images.js';
459
+ ${sql ? "import { resolveStandardContainerImage } from './container-images.js';\n" : ''}\
230
460
  import {
231
461
  defineEventConsumerAlarms,
232
462
  } from '@empire-builder-kit/runtime/observability';
463
+ import { validateSuccessfulDeploymentReceipt } from './deployment-receipt.js';
233
464
  // <ebk:composition-imports:start>
234
465
  // <ebk:composition-imports:end>
235
466
 
@@ -244,11 +475,12 @@ function protectedPerformanceDeploymentAuthority(input: {
244
475
  );
245
476
  }
246
477
  if (input.enabled === 'false') return undefined;
247
- if (input.stage !== 'staging' && input.stage !== 'production') {
478
+ if (!${JSON.stringify(protectedRuntimeStages)}.includes(input.stage)) {
248
479
  throw new Error(
249
- 'Protected performance load can be deployed only to staging or production.',
480
+ 'Protected performance load requires one active rehearsal or production stage.',
250
481
  );
251
482
  }
483
+ const stage = input.stage as 'development' | 'production' | 'staging';
252
484
  const accountId = process.env.AWS_EXPECTED_ACCOUNT_ID?.trim() ?? '';
253
485
  const region = process.env.AWS_REGION?.trim() ?? '';
254
486
  if (
@@ -284,60 +516,38 @@ function protectedPerformanceDeploymentAuthority(input: {
284
516
  'Protected performance load requires the exact deployed release candidate.',
285
517
  );
286
518
  }
287
- const releaseManifestDirectory = new URL(
288
- '../.ebk/evidence/release-manifests/',
289
- import.meta.url,
290
- );
291
- const releaseManifestNames = readdirSync(releaseManifestDirectory).filter(
292
- (entry) => /^release-[a-f0-9]{24}[.]json$/.test(entry),
293
- );
294
- if (releaseManifestNames.length !== 1) {
295
- throw new Error(
296
- 'Protected performance load requires one exact deployed release manifest.',
297
- );
298
- }
299
- const releaseManifestUrl = new URL(
300
- releaseManifestNames[0]!,
301
- releaseManifestDirectory,
519
+ const deploymentReceiptBytes = readFileSync(
520
+ new URL(
521
+ '../../../.ebk/evidence/deployment/latest.json',
522
+ import.meta.url,
523
+ ),
302
524
  );
303
- const releaseManifestPath = fileURLToPath(releaseManifestUrl);
304
- const releaseManifestMetadata = lstatSync(releaseManifestPath);
305
- if (
306
- !releaseManifestMetadata.isFile() ||
307
- releaseManifestMetadata.isSymbolicLink() ||
308
- releaseManifestMetadata.size <= 0 ||
309
- releaseManifestMetadata.size > 10 * 1024 * 1024 ||
310
- realpathSync(releaseManifestPath) !== releaseManifestPath
311
- ) {
312
- throw new Error(
313
- 'Protected performance load release manifest is not one bounded canonical file.',
314
- );
315
- }
316
- const releaseManifest = validateReleaseManifest(
317
- JSON.parse(readFileSync(releaseManifestPath, 'utf8')),
525
+ validateSuccessfulDeploymentReceipt(
526
+ JSON.parse(deploymentReceiptBytes.toString('utf8')),
318
527
  {
319
- requireSupplyChain: true,
528
+ account: accountId,
529
+ project: '${name}',
530
+ region,
320
531
  sourceCommit: input.releaseSourceCommit,
532
+ stage,
321
533
  },
322
534
  );
323
- if (releaseManifestNames[0] !== releaseManifest.releaseId + '.json') {
324
- throw new Error(
325
- 'Protected performance load release manifest path differs from its identity.',
326
- );
327
- }
535
+ const deploymentReceiptDigest = createHash('sha256')
536
+ .update(deploymentReceiptBytes)
537
+ .digest('hex');
328
538
  return Object.freeze({
329
539
  candidateDigest: createHash('sha256')
330
540
  .update(candidateBytes)
331
541
  .digest('hex'),
332
- releaseId: releaseManifest.releaseId,
333
- releaseMaterialDigest: releaseManifest.materialDigest,
542
+ releaseId: 'release-' + deploymentReceiptDigest.slice(0, 24),
543
+ releaseMaterialDigest: deploymentReceiptDigest,
334
544
  target: Object.freeze({
335
545
  accountFingerprint:
336
546
  'sha256:' +
337
547
  createHash('sha256').update(accountId, 'utf8').digest('hex'),
338
548
  region,
339
549
  slice: '${name}',
340
- stage: input.stage as 'production' | 'staging',
550
+ stage,
341
551
  }),
342
552
  });
343
553
  }
@@ -448,19 +658,15 @@ function lambdaLogging(logGroupName: any, functionName?: any) {
448
658
  };
449
659
  }
450
660
 
451
- export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
452
- if (!$dev && !workloadRoles) {
453
- throw new Error(
454
- 'Protected workload-role preflight must complete before infrastructure construction.',
455
- );
456
- }
457
- const workloadRoleBindings = workloadRoles?.bindings;
661
+ export function product() {
662
+ const backgroundSchedules = backgroundWorkSchedules(
663
+ backgroundWorkPolicy,
664
+ $dev ? 'development' : $app.stage,
665
+ );
458
666
  const asyncAdaptersConfigured = assertAsyncAdapterDeploymentReady();
459
- const secretLinks = createStandardSliceSecretLinks({
460
- protectedAccess: workloadRoles?.secretAccess,
461
- });
667
+ const secretLinks = createStandardSliceSecretLinks();
462
668
  const performanceHmacLogicalName =
463
- '${pascalName}PerformanceLoadHmacKeys';
669
+ 'GeneratedPerformanceLoadHmacKeys';
464
670
  const secretLinksFor = (
465
671
  resource: string,
466
672
  excludeLogicalNames: readonly string[] = [],
@@ -473,21 +679,6 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
473
679
  ];
474
680
  // Workload generators compose multi-role secret bindings through this seam.
475
681
  void secretLinksForWorkloads;
476
- const workloadRoleResourceNames = workloadRoles
477
- ? standardSliceResourceNames(workloadRoles.intentContext)
478
- : undefined;
479
- if (workloadRoleResourceNames) {
480
- $transform(aws.dynamodb.Table, (args: any, _opts: any, logicalName: string) => {
481
- if (logicalName === '${pascalName}WebRevalidationTable') {
482
- args.name = workloadRoleResourceNames.webRevalidationTable;
483
- }
484
- });
485
- $transform(aws.sqs.Queue, (args: any, _opts: any, logicalName: string) => {
486
- if (logicalName === '${pascalName}WebRevalidationEventsQueue') {
487
- args.name = workloadRoleResourceNames.webRevalidationQueue;
488
- }
489
- });
490
- }
491
682
  const devPortInput = $dev ? (process.env.EBK_DEV_PORT ?? '3000') : '3000';
492
683
  if (!/^\\d+$/.test(devPortInput)) {
493
684
  throw new Error('EBK_DEV_PORT must be an integer from 1024 through 65535.');
@@ -496,17 +687,21 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
496
687
  if (!Number.isSafeInteger(devPort) || devPort < 1024 || devPort > 65535) {
497
688
  throw new Error('EBK_DEV_PORT must be an integer from 1024 through 65535.');
498
689
  }
499
- const protectedStage =
500
- $app.stage === 'staging' || $app.stage === 'production';
690
+ const protectedStage = ${JSON.stringify(protectedRuntimeStages)}.includes(
691
+ $app.stage,
692
+ );
501
693
  const sourceCommit =
502
694
  process.env.EBK_SOURCE_COMMIT ?? (protectedStage ? '' : 'unresolved');
503
695
  const releaseSourceCommit =
504
696
  process.env.EBK_RELEASE_SOURCE_COMMIT ?? sourceCommit;
505
- const exactDevelopmentRetirement =
697
+ ${sql
698
+ ? ` const exactDevelopmentRetirement =
506
699
  $app.stage === 'development' &&
507
700
  Object.values(databaseBindings).some((binding) =>
508
701
  binding.provisioned.includes('retirement_rehearsal'),
509
702
  );
703
+ `
704
+ : ''}\
510
705
  if (
511
706
  protectedStage &&
512
707
  (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(sourceCommit) ||
@@ -516,16 +711,31 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
516
711
  'Protected infrastructure requires exact deployment and release source Git object IDs.',
517
712
  );
518
713
  }
519
- const dataRetentionContainer = resolveStandardContainerImage({
520
- artifactId: '${name}.job.data-retention',
521
- local: {
522
- context: '../..',
523
- dockerfile: 'packages/${name}/jobs/data-retention/Dockerfile',
714
+ $transform(
715
+ aws.lambda.Invocation,
716
+ (args: any, _opts: any, logicalName: string) => {
717
+ if (logicalName !== '${pascalName}WebRevalidationSeed') return;
718
+ const triggers = args.triggers;
719
+ if (
720
+ !triggers ||
721
+ typeof triggers !== 'object' ||
722
+ Array.isArray(triggers) ||
723
+ Object.keys(triggers).length !== 1 ||
724
+ typeof triggers.version !== 'string'
725
+ ) {
726
+ throw new Error(
727
+ 'Pinned SST Next revalidation seed does not expose one exact version trigger.',
728
+ );
729
+ }
730
+ // SST 4.17.1 uses Date.now() here, which makes every preview propose a
731
+ // replacement even when the immutable application source is unchanged.
732
+ // Re-seed exactly once per released source instead.
733
+ args.triggers = { version: releaseSourceCommit };
524
734
  },
525
- sourceCommit: releaseSourceCommit,
526
- stage: $app.stage,
527
- });
528
- const databaseMigrationContainer = resolveStandardContainerImage({
735
+ );
736
+ ${''}\
737
+ ${sql
738
+ ? ` const databaseMigrationContainer = resolveStandardContainerImage({
529
739
  artifactId: '${name}.job.database-migration',
530
740
  local: {
531
741
  context: '../..',
@@ -544,6 +754,8 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
544
754
  sourceCommit: releaseSourceCommit,
545
755
  stage: $app.stage,
546
756
  });
757
+ `
758
+ : ''}\
547
759
  const performanceDeploymentAuthority = protectedStage
548
760
  ? protectedPerformanceDeploymentAuthority({
549
761
  enabled: process.env.EBK_PERFORMANCE_LOAD_ENABLED ?? 'false',
@@ -552,6 +764,172 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
552
764
  })
553
765
  : undefined;
554
766
  const foundation = getFoundationInfrastructure();
767
+ ${` const keyValue = createKeyValueInfrastructure({
768
+ eventBusArn: foundation.discovery.eventBusArn,
769
+ eventBusName: foundation.discovery.eventBusName,
770
+ alertTopicArn: foundation.discovery.alertTopicArn,
771
+ outbox: backgroundSchedules.outbox,
772
+ managedLogGroup,
773
+ lambdaLogging,
774
+ });
775
+ `}\
776
+ // Domain delivery is the key-value stream plus scheduled reconciliation; the
777
+ // async/outbox-relay Function drains only the isolated performance sink.
778
+ // Observation only: alarms never pause, drop, or retry an event intent.
779
+ const keyValueStreamDeliveryErrorAlarm = new aws.cloudwatch.MetricAlarm(
780
+ '${pascalName}KeyValueStreamDeliveryErrors',
781
+ {
782
+ alarmActions: [foundation.discovery.alertTopicArn],
783
+ alarmDescription: operationalAlarmDescription({
784
+ businessSymptom:
785
+ 'The key-value stream delivery Function failed an invocation.',
786
+ id: 'key-value-stream-delivery-errors',
787
+ runbook: 'docs/runbooks/async-recovery.md',
788
+ }),
789
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
790
+ dimensions: { FunctionName: keyValue.dispatcher.name },
791
+ evaluationPeriods: 1,
792
+ metricName: 'Errors',
793
+ name: '${name}-' + $app.stage + '-key-value-stream-delivery-errors',
794
+ namespace: 'AWS/Lambda',
795
+ period: 300,
796
+ statistic: 'Sum',
797
+ threshold: 1,
798
+ treatMissingData: 'notBreaching',
799
+ },
800
+ );
801
+ const keyValueStreamIteratorAgeAlarm = new aws.cloudwatch.MetricAlarm(
802
+ '${pascalName}KeyValueStreamIteratorAge',
803
+ {
804
+ alarmActions: [foundation.discovery.alertTopicArn],
805
+ alarmDescription: operationalAlarmDescription({
806
+ businessSymptom:
807
+ 'Prompt domain-event delivery from the key-value stream is falling behind.',
808
+ id: 'key-value-stream-iterator-age',
809
+ runbook: 'docs/runbooks/async-recovery.md',
810
+ }),
811
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
812
+ dimensions: { FunctionName: keyValue.dispatcher.name },
813
+ evaluationPeriods: 1,
814
+ metricName: 'IteratorAge',
815
+ name: '${name}-' + $app.stage + '-key-value-stream-iterator-age',
816
+ namespace: 'AWS/Lambda',
817
+ period: 300,
818
+ statistic: 'Maximum',
819
+ threshold: 600_000,
820
+ treatMissingData: 'notBreaching',
821
+ },
822
+ );
823
+ const keyValueReconciliationErrorAlarm = new aws.cloudwatch.MetricAlarm(
824
+ '${pascalName}KeyValueReconciliationErrors',
825
+ {
826
+ alarmActions: [foundation.discovery.alertTopicArn],
827
+ alarmDescription: operationalAlarmDescription({
828
+ businessSymptom: 'Durable domain-event recovery is failing.',
829
+ id: 'key-value-reconciliation-errors',
830
+ runbook: 'docs/runbooks/async-recovery.md',
831
+ }),
832
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
833
+ dimensions: { FunctionName: keyValue.reconciler.name },
834
+ evaluationPeriods: 1,
835
+ metricName: 'Errors',
836
+ name: '${name}-' + $app.stage + '-key-value-reconciliation-errors',
837
+ namespace: 'AWS/Lambda',
838
+ period: 300,
839
+ statistic: 'Sum',
840
+ threshold: 1,
841
+ treatMissingData: 'notBreaching',
842
+ },
843
+ );
844
+ // Reconciliation gauges are bounded per-run samples (one page per shard),
845
+ // so hourly periods cover the default and any sub-hourly reconciliation
846
+ // cadence. A slower configured cadence leaves empty periods, so these alarms
847
+ // can miss a backlog (see each registration's expectedFalseNegativeRisk).
848
+ const outboxBacklogAlarm = new aws.cloudwatch.MetricAlarm(
849
+ '${pascalName}OutboxBacklog',
850
+ {
851
+ alarmActions: [foundation.discovery.alertTopicArn],
852
+ alarmDescription: operationalAlarmDescription({
853
+ businessSymptom: 'Durable domain-event intents remain undelivered.',
854
+ id: 'outbox-backlog',
855
+ runbook: 'docs/runbooks/async-recovery.md',
856
+ }),
857
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
858
+ dimensions: { Slice: '${name}', Stage: $app.stage },
859
+ evaluationPeriods: 2,
860
+ metricName: 'OutboxBacklog',
861
+ name: '${name}-' + $app.stage + '-outbox-backlog',
862
+ namespace: 'EBK/Async',
863
+ period: 3600,
864
+ statistic: 'Maximum',
865
+ threshold: 1,
866
+ treatMissingData: 'notBreaching',
867
+ },
868
+ );
869
+ const eventIntentRejectedAlarm = new aws.cloudwatch.MetricAlarm(
870
+ '${pascalName}EventIntentRejected',
871
+ {
872
+ alarmActions: [foundation.discovery.alertTopicArn],
873
+ alarmDescription: operationalAlarmDescription({
874
+ businessSymptom: 'A retained domain-event intent cannot be delivered.',
875
+ id: 'event-intent-rejected',
876
+ runbook: 'docs/runbooks/async-recovery.md',
877
+ }),
878
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
879
+ dimensions: { Slice: '${name}', Stage: $app.stage },
880
+ evaluationPeriods: 1,
881
+ metricName: 'EventReconciliationRejected',
882
+ name: '${name}-' + $app.stage + '-event-intent-rejected',
883
+ namespace: 'EBK/Async',
884
+ period: 3600,
885
+ statistic: 'Maximum',
886
+ threshold: 1,
887
+ treatMissingData: 'notBreaching',
888
+ },
889
+ );
890
+ const eventDeliveryAttemptsAlarm = new aws.cloudwatch.MetricAlarm(
891
+ '${pascalName}EventDeliveryAttempts',
892
+ {
893
+ alarmActions: [foundation.discovery.alertTopicArn],
894
+ alarmDescription: operationalAlarmDescription({
895
+ businessSymptom:
896
+ 'A domain-event intent is repeatedly failing delivery.',
897
+ id: 'event-delivery-attempts',
898
+ runbook: 'docs/runbooks/async-recovery.md',
899
+ }),
900
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
901
+ dimensions: { Slice: '${name}', Stage: $app.stage },
902
+ evaluationPeriods: 1,
903
+ metricName: 'EventDeliveryMaxAttempts',
904
+ name: '${name}-' + $app.stage + '-event-delivery-attempts',
905
+ namespace: 'EBK/Async',
906
+ period: 3600,
907
+ statistic: 'Maximum',
908
+ threshold: 10,
909
+ treatMissingData: 'notBreaching',
910
+ },
911
+ );
912
+ const nativeAuthority = createStandardSliceNativeRuntimeAuthority({
913
+ ${sql
914
+ ? ` clusterId: foundation.discovery.clusterId,
915
+ clusterResourceId: foundation.database.clusterResourceId,
916
+ masterSecretArn: foundation.database.masterSecretArn,
917
+ `
918
+ : ''}\
919
+ eventBusArn: foundation.discovery.eventBusArn,
920
+ identityUserPoolArn: foundation.discovery.identityUserPoolArn,
921
+ });
922
+ const runtimeResourceNames = nativeAuthority.resourceNames;
923
+ $transform(aws.dynamodb.Table, (args: any, _opts: any, logicalName: string) => {
924
+ if (logicalName === '${pascalName}WebRevalidationTable') {
925
+ args.name = runtimeResourceNames.webRevalidationTable;
926
+ }
927
+ });
928
+ $transform(aws.sqs.Queue, (args: any, _opts: any, logicalName: string) => {
929
+ if (logicalName === '${pascalName}WebRevalidationEventsQueue') {
930
+ args.name = runtimeResourceNames.webRevalidationQueue;
931
+ }
932
+ });
555
933
  const performanceCostControls = create${pascalName}PerformanceCostControls({
556
934
  accountCostPolicyDigest: foundation.discovery.accountCostPolicyDigest,
557
935
  accountMonthlyMaximumUsd:
@@ -559,12 +937,15 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
559
937
  alertTopicArn: foundation.discovery.alertTopicArn,
560
938
  workspace: '${workspace}',
561
939
  });
562
- const databaseProvisions = provisionDatabaseBindings(foundation, {
940
+ ${sql
941
+ ? ` const databaseProvisions = provisionDatabaseBindings(foundation, {
563
942
  bindings: databaseBindings,
564
943
  slice: '${name}',
565
944
  });
566
945
  const databaseProvision = databaseProvisions.bindings.primary;
567
946
  const { db: database } = databaseProvision;
947
+ `
948
+ : ''}\
568
949
  const authClient = foundation.userPool.addClient('${pascalName}WebAuthClient', {
569
950
  transform: {
570
951
  client: {
@@ -584,16 +965,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
584
965
  const machineClientProvisioner = new sst.aws.Function(
585
966
  '${pascalName}MachineClientProvisioner',
586
967
  {
587
- ...(workloadRoleBindings?.authorization.provisioner ?? {}),
588
- ...(workloadRoles
589
- ? {}
590
- : {
591
- permissions:
592
- standardSliceMachineClientProvisionerPermissions({
593
- userPoolArn:
594
- foundation.discovery.identityUserPoolArn,
595
- }),
596
- }),
968
+ dev: false,
969
+ permissions: standardSliceMachineClientProvisionerPermissions({
970
+ userPoolArn: foundation.discovery.identityUserPoolArn,
971
+ }),
597
972
  environment: {
598
973
  EBK_SLICE: '${name}',
599
974
  EBK_STAGE: $app.stage,
@@ -601,7 +976,6 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
601
976
  },
602
977
  handler: 'authorization/machine-client-provisioner.handler',
603
978
  link: secretLinksFor('machine-client-provisioner'),
604
- runtime: 'python3.12',
605
979
  timeout: '2 minutes',
606
980
  ...lambdaLogging(machineClientProvisionerLogs.logGroup.name),
607
981
  },
@@ -617,9 +991,8 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
617
991
  userPoolId: foundation.userPool.id,
618
992
  });
619
993
  const dataExportStore = createStandardDataExportStore({
620
- bucketName: workloadRoleResourceNames?.dataExportBucket,
621
- keyAliasName: workloadRoleResourceNames?.dataExportKeyAlias,
622
- workloadRoleArn: workloadRoleBindings?.api.dataRights.role,
994
+ bucketName: runtimeResourceNames.dataExportBucket,
995
+ keyAliasName: runtimeResourceNames.dataExportKeyAlias,
623
996
  });
624
997
 
625
998
  const apiHealthLogs = managedLogGroup(
@@ -733,9 +1106,35 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
733
1106
  foundation.discovery.alertTopicArn,
734
1107
  );
735
1108
 
1109
+ const vpcRouteFunctionMaterializer =
1110
+ createVpcRouteFunctionMaterializer({
1111
+ directHandlers: [
1112
+ 'api/health.handler',
1113
+ 'async/webhook-ingress.handler',
1114
+ ],
1115
+ ${''}\
1116
+ output: $output,
1117
+ });
736
1118
  const api = new sst.aws.ApiGatewayV2('${pascalName}Api', {
737
- ...(performanceDeploymentAuthority ? { vpc: foundation.vpc } : {}),
1119
+ ${network ? ' ...(performanceDeploymentAuthority ? { vpc: foundation.vpc } : {}),\n' : ''}\
1120
+ transform: {
1121
+ route: {
1122
+ handler: vpcRouteFunctionMaterializer.transform,
1123
+ },
1124
+ },
738
1125
  });
1126
+ const routeInVpc = (
1127
+ rawRoute: string,
1128
+ handler: { handler: string } & Record<string, any>,
1129
+ args?: Record<string, any>,
1130
+ ) =>
1131
+ vpcRouteFunctionMaterializer.route(
1132
+ rawRoute,
1133
+ handler,
1134
+ args,
1135
+ (registeredRoute, registeredHandler, registeredArgs) =>
1136
+ api.route(registeredRoute, registeredHandler, registeredArgs),
1137
+ );
739
1138
  const performanceIngress = performanceDeploymentAuthority
740
1139
  ? (() => {
741
1140
  const originProof = new random.RandomPassword(
@@ -773,7 +1172,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
773
1172
  }
774
1173
  : undefined;
775
1174
  api.route(${identifierPrefix}Health.method + ' ' + ${identifierPrefix}Health.path, {
776
- ...(workloadRoleBindings?.api.health ?? {}),
1175
+ permissions: nativeAuthority.permissions('api-health'),
777
1176
  environment: {
778
1177
  EBK_SOURCE_COMMIT: releaseSourceCommit,
779
1178
  EBK_STAGE: $app.stage,
@@ -782,13 +1181,14 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
782
1181
  link: secretLinksFor('api-health'),
783
1182
  ...lambdaLogging(apiHealthLogs.logGroup.name),
784
1183
  });
785
- api.route(
1184
+ routeInVpc(
786
1185
  ${identifierPrefix}MachineAuthorizationProof.method +
787
1186
  ' ' +
788
1187
  ${identifierPrefix}MachineAuthorizationProof.path,
789
1188
  {
790
- ...(workloadRoleBindings?.api.machineAuthorizationProof ?? {}),
1189
+ permissions: nativeAuthority.permissions('api-machine-authorization-proof'),
791
1190
  environment: {
1191
+ ${' ...keyValue.environment,\n'}\
792
1192
  AUTH_CLIENT_ID: authClient.id,
793
1193
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
794
1194
  machineAuthorization.acceptedClientIdsJson,
@@ -798,11 +1198,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
798
1198
  },
799
1199
  handler: 'api/machine-authorization.handler',
800
1200
  link: [
801
- database,
1201
+ ${'keyValue.link'},
802
1202
  ...secretLinksFor('api-machine-authorization-proof'),
803
1203
  ],
804
1204
  ...lambdaLogging(machineAuthorizationProofTargetLogs.logGroup.name),
805
- vpc: foundation.vpc,
806
1205
  },
807
1206
  );
808
1207
  for (const route of [
@@ -819,9 +1218,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
819
1218
  operation: ${identifierPrefix}RevokeRecordDelegation,
820
1219
  },
821
1220
  ]) {
822
- api.route(route.operation.method + ' ' + route.operation.path, {
823
- ...(workloadRoleBindings?.api.delegations ?? {}),
1221
+ routeInVpc(route.operation.method + ' ' + route.operation.path, {
1222
+ permissions: nativeAuthority.permissions('api-delegations'),
824
1223
  environment: {
1224
+ ${' ...keyValue.environment,\n'}\
825
1225
  AUTH_CLIENT_ID: authClient.id,
826
1226
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
827
1227
  machineAuthorization.acceptedClientIdsJson,
@@ -830,9 +1230,8 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
830
1230
  EBK_STAGE: $app.stage,
831
1231
  },
832
1232
  handler: route.handler,
833
- link: [database, ...secretLinksFor('api-delegations')],
1233
+ link: [${'keyValue.link'}, ...secretLinksFor('api-delegations')],
834
1234
  ...lambdaLogging(delegationLogs.logGroup.name),
835
- vpc: foundation.vpc,
836
1235
  });
837
1236
  }
838
1237
  for (const route of [
@@ -873,12 +1272,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
873
1272
  operation: ${identifierPrefix}ExpireRecordHold,
874
1273
  },
875
1274
  ]) {
876
- api.route(route.operation.method + ' ' + route.operation.path, {
877
- ...(workloadRoleBindings?.api.dataRights ?? {}),
878
- ...(workloadRoles
879
- ? {}
880
- : { permissions: dataExportStore.dataRightsPermissions }),
1275
+ routeInVpc(route.operation.method + ' ' + route.operation.path, {
1276
+ permissions: nativeAuthority.permissions('api-data-rights'),
881
1277
  environment: {
1278
+ ${' ...keyValue.environment,\n'}\
882
1279
  AUTH_CLIENT_ID: authClient.id,
883
1280
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
884
1281
  machineAuthorization.acceptedClientIdsJson,
@@ -891,12 +1288,11 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
891
1288
  },
892
1289
  handler: route.handler,
893
1290
  link: [
894
- database,
1291
+ ${'keyValue.link'},
895
1292
  foundation.eventBus,
896
1293
  ...secretLinksFor('api-data-rights'),
897
1294
  ],
898
1295
  ...lambdaLogging(dataRightsLogs.logGroup.name),
899
- vpc: foundation.vpc,
900
1296
  });
901
1297
  }
902
1298
  for (const route of [
@@ -909,9 +1305,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
909
1305
  operation: ${identifierPrefix}DecideRetentionApproval,
910
1306
  },
911
1307
  ]) {
912
- api.route(route.operation.method + ' ' + route.operation.path, {
913
- ...(workloadRoleBindings?.api.databaseRecords ?? {}),
1308
+ routeInVpc(route.operation.method + ' ' + route.operation.path, {
1309
+ permissions: nativeAuthority.permissions('api-database-records'),
914
1310
  environment: {
1311
+ ${' ...keyValue.environment,\n'}\
915
1312
  AUTH_CLIENT_ID: authClient.id,
916
1313
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
917
1314
  machineAuthorization.acceptedClientIdsJson,
@@ -920,18 +1317,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
920
1317
  EBK_STAGE: $app.stage,
921
1318
  },
922
1319
  handler: route.handler,
923
- link: [database, ...secretLinksFor('api-database-records')],
1320
+ link: [${'keyValue.link'}, ...secretLinksFor('api-database-records')],
924
1321
  ...lambdaLogging(dataRetentionReviewLogs.logGroup.name),
925
- vpc: foundation.vpc,
926
1322
  });
927
1323
  }
928
- api.route(
1324
+ routeInVpc(
929
1325
  ${identifierPrefix}ProtectedExample.method +
930
1326
  ' ' +
931
1327
  ${identifierPrefix}ProtectedExample.path,
932
1328
  {
933
- ...(workloadRoleBindings?.api.protected ?? {}),
1329
+ permissions: nativeAuthority.permissions('api-protected'),
934
1330
  environment: {
1331
+ ${' ...keyValue.environment,\n'}\
935
1332
  AUTH_CLIENT_ID: authClient.id,
936
1333
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
937
1334
  machineAuthorization.acceptedClientIdsJson,
@@ -940,18 +1337,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
940
1337
  EBK_STAGE: $app.stage,
941
1338
  },
942
1339
  handler: 'api/protected.handler',
943
- link: [database, ...secretLinksFor('api-protected')],
1340
+ link: [${'keyValue.link'}, ...secretLinksFor('api-protected')],
944
1341
  ...lambdaLogging(protectedApiLogs.logGroup.name),
945
- vpc: foundation.vpc,
946
1342
  },
947
1343
  );
948
- api.route(
1344
+ routeInVpc(
949
1345
  ${identifierPrefix}DatabaseHealth.method +
950
1346
  ' ' +
951
1347
  ${identifierPrefix}DatabaseHealth.path,
952
1348
  {
953
- ...(workloadRoleBindings?.api.databaseHealth ?? {}),
1349
+ permissions: nativeAuthority.permissions('api-database-health'),
954
1350
  environment: {
1351
+ ${' ...keyValue.environment,\n'}\
955
1352
  AUTH_CLIENT_ID: authClient.id,
956
1353
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
957
1354
  machineAuthorization.acceptedClientIdsJson,
@@ -960,9 +1357,8 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
960
1357
  EBK_STAGE: $app.stage,
961
1358
  },
962
1359
  handler: 'database/runtime-health.handler',
963
- link: [database, ...secretLinksFor('api-database-health')],
1360
+ link: [${'keyValue.link'}, ...secretLinksFor('api-database-health')],
964
1361
  ...lambdaLogging(databaseHealthLogs.logGroup.name),
965
- vpc: foundation.vpc,
966
1362
  },
967
1363
  );
968
1364
  for (const route of [
@@ -979,9 +1375,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
979
1375
  operation: ${identifierPrefix}PutRecord,
980
1376
  },
981
1377
  ]) {
982
- api.route(route.operation.method + ' ' + route.operation.path, {
983
- ...(workloadRoleBindings?.api.databaseRecords ?? {}),
1378
+ routeInVpc(route.operation.method + ' ' + route.operation.path, {
1379
+ permissions: nativeAuthority.permissions('api-database-records'),
984
1380
  environment: {
1381
+ ${' ...keyValue.environment,\n'}\
985
1382
  AUTH_CLIENT_ID: authClient.id,
986
1383
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
987
1384
  machineAuthorization.acceptedClientIdsJson,
@@ -992,12 +1389,11 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
992
1389
  },
993
1390
  handler: route.handler,
994
1391
  link: [
995
- database,
1392
+ ${'keyValue.link'},
996
1393
  foundation.eventBus,
997
1394
  ...secretLinksFor('api-database-records'),
998
1395
  ],
999
1396
  ...lambdaLogging(databaseRecordsLogs.logGroup.name),
1000
- vpc: foundation.vpc,
1001
1397
  });
1002
1398
  }
1003
1399
  for (const route of [
@@ -1010,9 +1406,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1010
1406
  operation: ${identifierPrefix}DecideRecordDeletion,
1011
1407
  },
1012
1408
  ]) {
1013
- api.route(route.operation.method + ' ' + route.operation.path, {
1014
- ...(workloadRoleBindings?.api.databaseRecords ?? {}),
1409
+ routeInVpc(route.operation.method + ' ' + route.operation.path, {
1410
+ permissions: nativeAuthority.permissions('api-database-records'),
1015
1411
  environment: {
1412
+ ${' ...keyValue.environment,\n'}\
1016
1413
  AUTH_CLIENT_ID: authClient.id,
1017
1414
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
1018
1415
  machineAuthorization.acceptedClientIdsJson,
@@ -1021,18 +1418,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1021
1418
  EBK_STAGE: $app.stage,
1022
1419
  },
1023
1420
  handler: route.handler,
1024
- link: [database, ...secretLinksFor('api-database-records')],
1421
+ link: [${'keyValue.link'}, ...secretLinksFor('api-database-records')],
1025
1422
  ...lambdaLogging(databaseRecordsLogs.logGroup.name),
1026
- vpc: foundation.vpc,
1027
1423
  });
1028
1424
  }
1029
- api.route(
1425
+ routeInVpc(
1030
1426
  ${identifierPrefix}PublishCreated.method +
1031
1427
  ' ' +
1032
1428
  ${identifierPrefix}PublishCreated.path,
1033
1429
  {
1034
- ...(workloadRoleBindings?.api.publishCreated ?? {}),
1430
+ permissions: nativeAuthority.permissions('api-publish-created'),
1035
1431
  environment: {
1432
+ ${' ...keyValue.environment,\n'}\
1036
1433
  AUTH_CLIENT_ID: authClient.id,
1037
1434
  AUTH_MACHINE_ACCEPTED_CLIENT_IDS:
1038
1435
  machineAuthorization.acceptedClientIdsJson,
@@ -1043,21 +1440,17 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1043
1440
  },
1044
1441
  handler: 'api/publish-created.handler',
1045
1442
  link: [
1046
- database,
1443
+ ${'keyValue.link'},
1047
1444
  foundation.eventBus,
1048
1445
  ...secretLinksFor('api-publish-created'),
1049
1446
  ],
1050
1447
  ...lambdaLogging(eventPublisherLogs.logGroup.name),
1051
- vpc: foundation.vpc,
1052
1448
  },
1053
1449
  );
1054
1450
  const machineAuthorizationProof = new sst.aws.Function(
1055
1451
  '${pascalName}MachineAuthorizationProof',
1056
1452
  {
1057
- ...(workloadRoleBindings?.authorization.proof ?? {}),
1058
- ...(workloadRoles
1059
- ? {}
1060
- : { permissions: machineAuthorization.proof.permissions }),
1453
+ permissions: machineAuthorization.proof.permissions,
1061
1454
  environment: {
1062
1455
  ...machineAuthorization.proof.environment,
1063
1456
  AUTH_MACHINE_PROBE_URL:
@@ -1072,11 +1465,9 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1072
1465
  const dataExportCleanup = new sst.aws.Function(
1073
1466
  '${pascalName}DataExportCleanup',
1074
1467
  {
1075
- ...(workloadRoleBindings?.dataExport.cleanup ?? {}),
1076
- ...(workloadRoles
1077
- ? {}
1078
- : { permissions: dataExportStore.cleanupPermissions }),
1468
+ permissions: dataExportStore.cleanupPermissions,
1079
1469
  environment: {
1470
+ ${' ...keyValue.environment,\n'}\
1080
1471
  DATA_EXPORT_BUCKET_NAME: dataExportStore.bucket.bucket,
1081
1472
  DATA_EXPORT_KMS_KEY_ARN: dataExportStore.encryptionKey.arn,
1082
1473
  EBK_STAGE: $app.stage,
@@ -1084,24 +1475,21 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1084
1475
  },
1085
1476
  handler: 'jobs/data-export-cleanup.handler',
1086
1477
  link: [
1087
- database,
1478
+ ${'keyValue.link'},
1088
1479
  ...secretLinksFor('data-export-cleanup'),
1089
1480
  ],
1090
1481
  ...lambdaLogging(dataExportCleanupLogs.logGroup.name),
1091
1482
  timeout: '5 minutes',
1092
- vpc: foundation.vpc,
1483
+ ${''}\
1093
1484
  },
1094
1485
  );
1095
1486
  const dataExportCleanupRule = new aws.cloudwatch.EventRule(
1096
1487
  '${pascalName}DataExportCleanupSchedule',
1097
1488
  {
1098
- ...(workloadRoleResourceNames
1099
- ? { name: workloadRoleResourceNames.dataExportCleanupRule }
1100
- : {}),
1489
+ name: runtimeResourceNames.dataExportCleanupRule,
1101
1490
  description:
1102
1491
  'Hourly authoritative cleanup of expired confidential export versions.',
1103
- scheduleExpression: 'rate(1 hour)',
1104
- state: 'ENABLED',
1492
+ ...backgroundSchedules.exportCleanup,
1105
1493
  tags: {
1106
1494
  'ebk:management': 'standard-data-export',
1107
1495
  'ebk:slice': '${name}',
@@ -1146,9 +1534,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1146
1534
  const eventDlq = new sst.aws.Queue('${pascalName}EventDlq', {
1147
1535
  transform: {
1148
1536
  queue: {
1149
- ...(workloadRoleResourceNames
1150
- ? { name: workloadRoleResourceNames.eventDlq }
1151
- : {}),
1537
+ name: runtimeResourceNames.eventDlq,
1152
1538
  messageRetentionSeconds: 14 * 24 * 60 * 60,
1153
1539
  },
1154
1540
  },
@@ -1157,9 +1543,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1157
1543
  dlq: { queue: eventDlq.arn, retry: 5 },
1158
1544
  transform: {
1159
1545
  queue: {
1160
- ...(workloadRoleResourceNames
1161
- ? { name: workloadRoleResourceNames.eventQueue }
1162
- : {}),
1546
+ name: runtimeResourceNames.eventQueue,
1163
1547
  messageRetentionSeconds: 4 * 24 * 60 * 60,
1164
1548
  visibilityTimeoutSeconds: 120,
1165
1549
  },
@@ -1171,9 +1555,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1171
1555
  attributes: [{ name: 'report_digest', type: 'S' }],
1172
1556
  billingMode: 'PAY_PER_REQUEST',
1173
1557
  hashKey: 'report_digest',
1174
- ...(workloadRoleResourceNames
1175
- ? { name: workloadRoleResourceNames.asyncRecoveryLedger }
1176
- : {}),
1558
+ name: runtimeResourceNames.asyncRecoveryLedger,
1177
1559
  pointInTimeRecovery: { enabled: true },
1178
1560
  tags: {
1179
1561
  'ebk:async-recovery-ledger': 'true',
@@ -1188,19 +1570,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1188
1570
  );
1189
1571
  eventQueue.subscribe({
1190
1572
  environment: {
1573
+ ${' ...keyValue.environment,\n'}\
1191
1574
  EBK_STAGE: $app.stage,
1192
1575
  EBK_WORKLOAD_IDENTITY: '${name}:event-consumer',
1193
1576
  },
1194
1577
  handler: 'api/event-consumer.handler',
1195
- link: [database, ...secretLinksFor('event-consumer')],
1578
+ link: [${'keyValue.link'}, ...secretLinksFor('event-consumer')],
1579
+ permissions: nativeAuthority.permissions('event-consumer'),
1196
1580
  ...lambdaLogging(eventConsumerLogs.logGroup.name),
1197
1581
  timeout: '1 minute',
1198
- vpc: foundation.vpc,
1582
+ ${''}\
1199
1583
  }, {
1200
1584
  batch: { partialResponses: true },
1201
- transform: {
1202
- function: workloadRoleBindings?.queue.eventConsumer,
1203
- },
1204
1585
  });
1205
1586
  foundation.eventBus.subscribeQueue(
1206
1587
  '${pascalName}CreatedEventRule',
@@ -1208,7 +1589,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1208
1589
  {
1209
1590
  pattern: {
1210
1591
  detail: { meta: { stage: [$app.stage] } },
1211
- detailType: ['${pascalName}Created'],
1592
+ detailType: sameSliceEventDetailTypes(EventContractSchema),
1212
1593
  source: ['${name}'],
1213
1594
  },
1214
1595
  },
@@ -1258,9 +1639,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1258
1639
  {
1259
1640
  transform: {
1260
1641
  queue: {
1261
- ...(workloadRoleResourceNames
1262
- ? { name: workloadRoleResourceNames.asyncTargetDlq }
1263
- : {}),
1642
+ name: runtimeResourceNames.asyncTargetDlq,
1264
1643
  messageRetentionSeconds: 14 * 24 * 60 * 60,
1265
1644
  tags: {
1266
1645
  'ebk:async-recovery-source': 'async-target-dlq',
@@ -1274,9 +1653,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1274
1653
  const providerDlq = new sst.aws.Queue('${pascalName}ProviderDlq', {
1275
1654
  transform: {
1276
1655
  queue: {
1277
- ...(workloadRoleResourceNames
1278
- ? { name: workloadRoleResourceNames.providerDlq }
1279
- : {}),
1656
+ name: runtimeResourceNames.providerDlq,
1280
1657
  messageRetentionSeconds: 14 * 24 * 60 * 60,
1281
1658
  tags: {
1282
1659
  'ebk:async-recovery-source': 'provider-dlq',
@@ -1290,9 +1667,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1290
1667
  dlq: { queue: providerDlq.arn, retry: 5 },
1291
1668
  transform: {
1292
1669
  queue: {
1293
- ...(workloadRoleResourceNames
1294
- ? { name: workloadRoleResourceNames.providerQueue }
1295
- : {}),
1670
+ name: runtimeResourceNames.providerQueue,
1296
1671
  messageRetentionSeconds: 4 * 24 * 60 * 60,
1297
1672
  tags: {
1298
1673
  'ebk:async-recovery-destination': 'provider-queue',
@@ -1305,10 +1680,11 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1305
1680
  });
1306
1681
  const reliability = create${pascalName}Reliability({
1307
1682
  alertTopicArn: foundation.discovery.alertTopicArn,
1308
- alertTopicName:
1309
- foundation.discovery.alertTopicArn.split(':').at(-1) ?? '',
1683
+ alertTopicName: foundation.discovery.alertTopicArn.apply(
1684
+ (alertTopicArn: string) => alertTopicArn.split(':').at(-1) ?? '',
1685
+ ),
1310
1686
  apiId: api.id,
1311
- databaseClusterIdentifier: foundation.discovery.databaseClusterId,
1687
+ ${' databaseTableName: keyValue.table.name,\n'}\
1312
1688
  functionName: dataExportCleanup.name,
1313
1689
  providerQueueName: providerQueue.name,
1314
1690
  });
@@ -1356,6 +1732,9 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1356
1732
  );
1357
1733
  const runtimeConfiguration = protectedStage && !$dev
1358
1734
  ? (() => {
1735
+ const monitorRole = nativeAuthority.createAppConfigMonitorRole(
1736
+ '${pascalName}ConfigurationMonitorRole',
1737
+ );
1359
1738
  const application = new aws.appconfig.Application(
1360
1739
  '${pascalName}ConfigurationApplication',
1361
1740
  {
@@ -1381,8 +1760,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1381
1760
  reliability.providerDeadline,
1382
1761
  ].map((alarm) => ({
1383
1762
  alarmArn: alarm.arn,
1384
- alarmRoleArn:
1385
- workloadRoleBindings!.configuration.monitor.roleArn,
1763
+ alarmRoleArn: monitorRole.arn,
1386
1764
  })),
1387
1765
  name: $app.stage,
1388
1766
  tags: {
@@ -1523,6 +1901,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1523
1901
  providerQueue.subscribe(
1524
1902
  {
1525
1903
  environment: {
1904
+ ${' ...keyValue.environment,\n'}\
1526
1905
  EBK_STAGE: $app.stage,
1527
1906
  EBK_WORKLOAD_IDENTITY: '${name}:async-provider-worker',
1528
1907
  EBK_WORKSPACE: '${workspace}',
@@ -1530,26 +1909,24 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1530
1909
  },
1531
1910
  handler: 'async/provider-worker.handler',
1532
1911
  link: [
1533
- database,
1912
+ ${'keyValue.link'},
1534
1913
  providerQueue,
1535
1914
  ...secretLinksFor('async-provider-worker'),
1536
1915
  ],
1916
+ permissions: nativeAuthority.permissions('async-provider-worker'),
1537
1917
  ...lambdaLogging(asyncProviderWorkerLogs.logGroup.name),
1538
1918
  timeout: '1 minute',
1539
- vpc: foundation.vpc,
1919
+ ${''}\
1540
1920
  },
1541
1921
  {
1542
1922
  batch: { partialResponses: true },
1543
- transform: {
1544
- function: workloadRoleBindings?.async.providerWorker,
1545
- },
1546
1923
  },
1547
1924
  configurationDeployment
1548
1925
  ? { dependsOn: [configurationDeployment] }
1549
1926
  : {},
1550
1927
  );
1551
1928
  api.route('POST /${name}/webhooks/provider', {
1552
- ...(workloadRoleBindings?.async.webhookIngress ?? {}),
1929
+ permissions: nativeAuthority.permissions('async-webhook-ingress'),
1553
1930
  environment: {
1554
1931
  EBK_ASYNC_LEDGER_TABLE: asyncRecoveryLedger.name,
1555
1932
  EBK_STAGE: $app.stage,
@@ -1568,8 +1945,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1568
1945
  const asyncOutboxRelay = new sst.aws.Function(
1569
1946
  '${pascalName}AsyncOutboxRelay',
1570
1947
  {
1571
- ...(workloadRoleBindings?.async.outboxRelay ?? {}),
1948
+ permissions: nativeAuthority.permissions('async-outbox-relay'),
1572
1949
  environment: {
1950
+ ${' ...keyValue.environment,\n'}\
1951
+ ${''}\
1573
1952
  EBK_STAGE: $app.stage,
1574
1953
  EBK_WORKLOAD_IDENTITY: '${name}:async-outbox-relay',
1575
1954
  EBK_WORKSPACE: '${workspace}',
@@ -1577,38 +1956,117 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1577
1956
  },
1578
1957
  handler: 'async/outbox-relay.handler',
1579
1958
  link: [
1580
- database,
1959
+ ${'keyValue.link'},
1581
1960
  foundation.eventBus,
1582
1961
  ...secretLinksFor('async-outbox-relay'),
1583
1962
  ],
1584
1963
  ...lambdaLogging(asyncOutboxRelayLogs.logGroup.name),
1585
1964
  timeout: '1 minute',
1586
- vpc: foundation.vpc,
1965
+ ${''}\
1587
1966
  },
1588
1967
  );
1968
+ ${sql
1969
+ ? ` const sqlOutbox = createSqlOutboxInfrastructure({
1970
+ workspace: '${workspace}',
1971
+ database, eventBus: foundation.eventBus, eventBusName: foundation.discovery.eventBusName,
1972
+ secretLinks: secretLinksFor('async-outbox-relay'),
1973
+ vpc: foundation.vpc, schedule: backgroundSchedules.sqlOutboxRecovery,
1974
+ alertTopicArn: foundation.discovery.alertTopicArn,
1975
+ managedLogGroup, lambdaLogging,
1976
+ ${''}\
1977
+ });
1978
+ const sqlOutboxRelayErrorAlarm = new aws.cloudwatch.MetricAlarm(
1979
+ '${pascalName}SqlOutboxRelayErrors',
1980
+ {
1981
+ alarmActions: [foundation.discovery.alertTopicArn],
1982
+ alarmDescription: operationalAlarmDescription({
1983
+ businessSymptom: 'Relational event delivery is failing.',
1984
+ id: 'sql-outbox-relay-errors',
1985
+ runbook: 'docs/runbooks/async-recovery.md',
1986
+ }),
1987
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
1988
+ dimensions: { FunctionName: sqlOutbox.relay.name },
1989
+ evaluationPeriods: 1,
1990
+ metricName: 'Errors',
1991
+ name: '${name}-' + $app.stage + '-sql-outbox-relay-errors',
1992
+ namespace: 'AWS/Lambda',
1993
+ period: 300,
1994
+ statistic: 'Sum',
1995
+ threshold: 1,
1996
+ treatMissingData: 'notBreaching',
1997
+ },
1998
+ );
1999
+ // The relay counts every unpublished intent; Minimum ignores healthy
2000
+ // in-flight batches and alarms only when no run in an hour drained it.
2001
+ const sqlOutboxBacklogAlarm = new aws.cloudwatch.MetricAlarm(
2002
+ '${pascalName}SqlOutboxBacklog',
2003
+ {
2004
+ alarmActions: [foundation.discovery.alertTopicArn],
2005
+ alarmDescription: operationalAlarmDescription({
2006
+ businessSymptom: 'Relational event intents remain undelivered.',
2007
+ id: 'sql-outbox-backlog',
2008
+ runbook: 'docs/runbooks/async-recovery.md',
2009
+ }),
2010
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
2011
+ dimensions: { Slice: '${name}', Stage: $app.stage },
2012
+ evaluationPeriods: 2,
2013
+ metricName: 'SqlOutboxBacklog',
2014
+ name: '${name}-' + $app.stage + '-sql-outbox-backlog',
2015
+ namespace: 'EBK/Async',
2016
+ period: 3600,
2017
+ statistic: 'Minimum',
2018
+ threshold: 1,
2019
+ treatMissingData: 'notBreaching',
2020
+ },
2021
+ );
2022
+ const sqlOutboxAttemptsAlarm = new aws.cloudwatch.MetricAlarm(
2023
+ '${pascalName}SqlOutboxAttempts',
2024
+ {
2025
+ alarmActions: [foundation.discovery.alertTopicArn],
2026
+ alarmDescription: operationalAlarmDescription({
2027
+ businessSymptom:
2028
+ 'A relational event intent is repeatedly failing delivery.',
2029
+ id: 'sql-outbox-attempts',
2030
+ runbook: 'docs/runbooks/async-recovery.md',
2031
+ }),
2032
+ comparisonOperator: 'GreaterThanOrEqualToThreshold',
2033
+ dimensions: { Slice: '${name}', Stage: $app.stage },
2034
+ evaluationPeriods: 1,
2035
+ metricName: 'SqlOutboxMaxAttempts',
2036
+ name: '${name}-' + $app.stage + '-sql-outbox-attempts',
2037
+ namespace: 'EBK/Async',
2038
+ period: 3600,
2039
+ statistic: 'Maximum',
2040
+ threshold: 10,
2041
+ treatMissingData: 'notBreaching',
2042
+ },
2043
+ );
2044
+ `
2045
+ : ''}\
1589
2046
  const asyncInboxCleanup = new sst.aws.Function(
1590
2047
  '${pascalName}AsyncInboxCleanup',
1591
2048
  {
1592
- ...(workloadRoleBindings?.async.inboxCleanup ?? {}),
2049
+ permissions: nativeAuthority.permissions('async-inbox-cleanup'),
1593
2050
  environment: {
2051
+ ${' ...keyValue.environment,\n'}\
1594
2052
  EBK_STAGE: $app.stage,
1595
2053
  EBK_WORKLOAD_IDENTITY: '${name}:async-inbox-cleanup',
1596
2054
  EBK_WORKSPACE: '${workspace}',
1597
2055
  },
1598
2056
  handler: 'async/inbox-cleanup.handler',
1599
2057
  link: [
1600
- database,
2058
+ ${'keyValue.link'},
1601
2059
  ...secretLinksFor('async-inbox-cleanup'),
1602
2060
  ],
1603
2061
  ...lambdaLogging(asyncInboxCleanupLogs.logGroup.name),
1604
2062
  timeout: '5 minutes',
1605
- vpc: foundation.vpc,
2063
+ ${''}\
1606
2064
  },
1607
2065
  );
1608
2066
  const asyncScheduleTarget = new sst.aws.Function(
1609
2067
  '${pascalName}AsyncScheduleTarget',
1610
2068
  {
1611
- ...(workloadRoleBindings?.async.scheduleTarget ?? {}),
2069
+ permissions: nativeAuthority.permissions('async-schedule-target'),
1612
2070
  environment: {
1613
2071
  EBK_STAGE: $app.stage,
1614
2072
  EBK_WORKLOAD_IDENTITY: '${name}:async-schedule-target',
@@ -1623,7 +2081,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1623
2081
  const asyncWorkflowTask = new sst.aws.Function(
1624
2082
  '${pascalName}AsyncWorkflowTask',
1625
2083
  {
1626
- ...(workloadRoleBindings?.async.workflowTask ?? {}),
2084
+ permissions: nativeAuthority.permissions('async-workflow-task'),
1627
2085
  environment: {
1628
2086
  EBK_ASYNC_LEDGER_TABLE: asyncRecoveryLedger.name,
1629
2087
  EBK_STAGE: $app.stage,
@@ -1634,7 +2092,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1634
2092
  link: secretLinksFor('async-workflow-task'),
1635
2093
  ...lambdaLogging(
1636
2094
  asyncWorkflowTaskLogs.logGroup.name,
1637
- workloadRoleResourceNames?.workflowTaskFunction,
2095
+ runtimeResourceNames.workflowTaskFunction,
1638
2096
  ),
1639
2097
  timeout: '15 minutes',
1640
2098
  },
@@ -1655,9 +2113,9 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1655
2113
  const outboxRelayRule = new aws.cloudwatch.EventRule(
1656
2114
  '${pascalName}OutboxRelaySchedule',
1657
2115
  {
1658
- description: 'Durable outbox relay for committed domain events.',
1659
- scheduleExpression: 'rate(1 minute)',
1660
- state: 'ENABLED',
2116
+ description:
2117
+ 'Durable DynamoDB outbox relay; cadence and pause are independent of SQL capacity.',
2118
+ ...backgroundSchedules.outbox,
1661
2119
  tags: {
1662
2120
  'ebk:slice': '${name}',
1663
2121
  'ebk:stage': $app.stage,
@@ -1669,8 +2127,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1669
2127
  {
1670
2128
  description:
1671
2129
  'Bounded cleanup of expired async inbox idempotency records.',
1672
- scheduleExpression: 'rate(1 hour)',
1673
- state: 'ENABLED',
2130
+ ...backgroundSchedules.inboxCleanup,
1674
2131
  tags: {
1675
2132
  'ebk:slice': '${name}',
1676
2133
  'ebk:stage': $app.stage,
@@ -1778,6 +2235,10 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1778
2235
  );
1779
2236
  let recordExportWorkflow: any;
1780
2237
  if (!$dev && asyncAdaptersConfigured) {
2238
+ const recordExportWorkflowRole = nativeAuthority.createStepFunctionsRole(
2239
+ '${pascalName}RecordExportWorkflowRole',
2240
+ 'async-workflow-orchestration',
2241
+ );
1781
2242
  recordExportWorkflow = new aws.sfn.StateMachine(
1782
2243
  '${pascalName}RecordExportWorkflow',
1783
2244
  {
@@ -1921,8 +2382,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1921
2382
  'ebk-${recordExportWorkflowName}-' +
1922
2383
  $app.stage +
1923
2384
  '-record-export-v1',
1924
- roleArn:
1925
- workloadRoleBindings!.async.workflowOrchestration.roleArn,
2385
+ roleArn: recordExportWorkflowRole.arn,
1926
2386
  tags: {
1927
2387
  'ebk:slice': '${name}',
1928
2388
  'ebk:stage': $app.stage,
@@ -1933,14 +2393,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1933
2393
  );
1934
2394
  }
1935
2395
 
2396
+ const webServerLogging = lambdaLogging(nextServerLogs.logGroup.name);
1936
2397
  const web = new sst.aws.Nextjs('${pascalName}Web', {
2398
+ buildCommand: 'node ../tools/ebk-next-build-environment.mjs',
2399
+ invalidation: { wait: true },
1937
2400
  dev: {
1938
- command: \`pnpm exec next dev web --hostname 127.0.0.1 --port \${devPort}\`,
2401
+ command: 'node tools/ebk-next-dev.mjs',
1939
2402
  directory: '.',
1940
2403
  title: '${pascalName} web',
1941
2404
  url: \`http://127.0.0.1:\${devPort}/${name}\`,
1942
2405
  },
1943
2406
  environment: {
2407
+ ${' ...keyValue.environment,\n'}\
1944
2408
  AUTH_CLIENT_ID: authClient.id,
1945
2409
  AUTH_USER_POOL_ID: foundation.userPool.id,
1946
2410
  EBK_SOURCE_COMMIT: releaseSourceCommit,
@@ -1967,46 +2431,69 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
1967
2431
  ...runtimeConfigurationEnvironment,
1968
2432
  NEXT_PUBLIC_API_URL: api.url,
1969
2433
  },
1970
- link: [database, foundation.userPool],
2434
+ link: [keyValue.link, ${sql ? 'database, foundation.eventBus, ' : ''}foundation.userPool],
1971
2435
  path: 'web',
1972
2436
  router: { instance: foundation.router, path: '/${name}' },
1973
2437
  transform: {
1974
- assets: workloadRoleResourceNames
1975
- ? {
1976
- transform: {
1977
- bucket: {
1978
- bucket: workloadRoleResourceNames.webAssetsBucket,
1979
- },
1980
- },
1981
- }
1982
- : undefined,
2438
+ assets: {
2439
+ transform: {
2440
+ bucket: {
2441
+ bucket: runtimeResourceNames.webAssetsBucket,
2442
+ },
2443
+ },
2444
+ },
1983
2445
  imageOptimizer: {
1984
- ...(workloadRoleBindings?.next.imageOptimizer ?? {}),
2446
+ permissions: nativeAuthority.permissions('web-image-optimizer'),
2447
+ hook: {
2448
+ async postbuild(directory: string) {
2449
+ removeFinderMetadataFromBuiltFunction(directory);
2450
+ },
2451
+ },
1985
2452
  link: secretLinksFor('web-image-optimizer'),
1986
2453
  ...lambdaLogging(nextImageOptimizerLogs.logGroup.name),
1987
2454
  },
1988
2455
  revalidationEventsSubscriber: {
1989
- ...(workloadRoleBindings?.next.revalidationSubscriber ?? {}),
2456
+ permissions: nativeAuthority.permissions('web-revalidation-subscriber'),
1990
2457
  link: secretLinksFor('web-revalidation-subscriber'),
1991
2458
  ...lambdaLogging(nextRevalidationSubscriberLogs.logGroup.name),
1992
2459
  },
1993
2460
  revalidationSeeder: {
1994
- ...(workloadRoleBindings?.next.revalidationSeeder ?? {}),
2461
+ permissions: nativeAuthority.permissions('web-revalidation-seeder'),
1995
2462
  link: secretLinksFor('web-revalidation-seeder'),
1996
2463
  ...lambdaLogging(nextRevalidationSeederLogs.logGroup.name),
1997
2464
  },
1998
- server: {
1999
- ...(workloadRoleBindings?.next.server ?? {}),
2000
- link: secretLinksFor(
2001
- 'web-server',
2002
- performanceDeploymentBinding
2003
- ? []
2004
- : [performanceHmacLogicalName],
2005
- ),
2006
- ...lambdaLogging(nextServerLogs.logGroup.name),
2465
+ server(args: Record<string, unknown>) {
2466
+ args.permissions = $resolve({
2467
+ inherited: args.permissions,
2468
+ additional: nativeAuthority.permissions('web-server'),
2469
+ }).apply(({ inherited, additional }) => [
2470
+ ...((inherited ?? []) as unknown[]),
2471
+ ...additional,
2472
+ ]);
2473
+ args.hook = {
2474
+ async postbuild(directory: string) {
2475
+ removeFinderMetadataFromBuiltFunction(directory);
2476
+ },
2477
+ };
2478
+ // SST applies this transform to both its dev runtime and deployed
2479
+ // server. Preserve native/site links; secret links are additive.
2480
+ args.link = $output(args.link ?? []).apply((links: unknown[]) => [
2481
+ ...links,
2482
+ ...secretLinksFor(
2483
+ 'web-server',
2484
+ performanceDeploymentBinding
2485
+ ? []
2486
+ : [performanceHmacLogicalName],
2487
+ ),
2488
+ ]);
2489
+ Object.assign(args, webServerLogging);
2490
+ args.transform = {
2491
+ ...webServerLogging.transform,
2492
+ ...($dev ? { role: { tags: { 'ebk:dev-runtime': 'web' } } } : {}),
2493
+ };
2007
2494
  },
2008
2495
  },
2009
- vpc: foundation.vpc,
2496
+ ${sql ? ' vpc: foundation.vpc,\n' : ''}\
2010
2497
  }, configurationDeployment
2011
2498
  ? { dependsOn: [configurationDeployment] }
2012
2499
  : {});
@@ -2027,7 +2514,15 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2027
2514
  }
2028
2515
 
2029
2516
  const migrationControls: Record<string, any> = {};
2030
- if (!$dev) {
2517
+ ${` Object.assign(migrationControls, createKeyValueRetentionInfrastructure({
2518
+ keyValue, workspace: '${workspace}', eventBusArn: foundation.discovery.eventBusArn,
2519
+ alertTopicArn: foundation.discovery.alertTopicArn, schedule: backgroundSchedules.retention,
2520
+ scheduleName: runtimeResourceNames.dataRetentionMaintenanceRule,
2521
+ managedLogGroup, lambdaLogging, register: registerProductRetention,
2522
+ }));
2523
+ `}\
2524
+ ${sql
2525
+ ? ` if (!$dev) {
2031
2526
  const region = aws.getRegionOutput({}).name;
2032
2527
  const taskArguments = (task: any) => ({
2033
2528
  Cluster: task.cluster,
@@ -2049,33 +2544,38 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2049
2544
  Environment: [
2050
2545
  {
2051
2546
  Name: 'EBK_DATABASE_LIFECYCLE_CORRELATION_ID',
2052
- Value: '{% $states.input.databaseLifecycleCorrelationId %}',
2547
+ Value:
2548
+ '{% $states.context.Execution.Input.databaseLifecycleCorrelationId %}',
2053
2549
  },
2054
2550
  ...(callback
2055
2551
  ? [
2056
2552
  {
2057
2553
  Name: 'EBK_CANDIDATE_IDENTITY',
2058
- Value: '{% $states.input.candidateIdentity %}',
2554
+ Value:
2555
+ '{% $states.context.Execution.Input.candidateIdentity %}',
2059
2556
  },
2060
2557
  {
2061
2558
  Name: 'EBK_EXECUTION_DATABASE_IDENTIFIER',
2062
- Value: '{% $states.input.databaseIdentifier %}',
2559
+ Value:
2560
+ '{% $states.context.Execution.Input.databaseIdentifier %}',
2063
2561
  },
2064
2562
  {
2065
2563
  Name: 'EBK_EXECUTION_SLICE',
2066
- Value: '{% $states.input.slice %}',
2564
+ Value: '{% $states.context.Execution.Input.slice %}',
2067
2565
  },
2068
2566
  {
2069
2567
  Name: 'EBK_EXECUTION_STAGE',
2070
- Value: '{% $states.input.stage %}',
2568
+ Value: '{% $states.context.Execution.Input.stage %}',
2071
2569
  },
2072
2570
  {
2073
2571
  Name: 'EBK_REGISTRATION_DIGEST',
2074
- Value: '{% $states.input.registrationDigest %}',
2572
+ Value:
2573
+ '{% $states.context.Execution.Input.registrationDigest %}',
2075
2574
  },
2076
2575
  {
2077
2576
  Name: 'EBK_SOURCE_COMMIT',
2078
- Value: '{% $states.input.sourceCommit %}',
2577
+ Value:
2578
+ '{% $states.context.Execution.Input.sourceCommit %}',
2079
2579
  },
2080
2580
  {
2081
2581
  Name: 'EBK_STEP_FUNCTIONS_TASK_TOKEN',
@@ -2091,328 +2591,25 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2091
2591
  logicalName: string,
2092
2592
  definition: unknown,
2093
2593
  logGroup: any,
2094
- roleArn: string,
2095
- ) =>
2096
- new aws.sfn.StateMachine(logicalName, {
2594
+ roleResource: string,
2595
+ ) => {
2596
+ const role = nativeAuthority.createStepFunctionsRole(
2597
+ logicalName + 'Role',
2598
+ roleResource,
2599
+ );
2600
+ return new aws.sfn.StateMachine(logicalName, {
2097
2601
  definition: $jsonStringify(definition),
2098
2602
  loggingConfiguration: {
2099
2603
  includeExecutionData: false,
2100
2604
  level: 'ERROR',
2101
2605
  logDestination: $interpolate\`\${logGroup.arn}:*\`,
2102
2606
  },
2103
- roleArn,
2607
+ roleArn: role.arn,
2104
2608
  type: 'STANDARD',
2105
2609
  });
2106
-
2107
- if (!databaseProvision.readwriteSecretArn) {
2108
- throw new Error(
2109
- 'The active primary database is missing its read/write credential reference.',
2110
- );
2111
- }
2112
- const retentionTaskLogs = managedLogContract('job-data-retention');
2113
- const retentionTask = new sst.aws.Task('${pascalName}DataRetentionTask', {
2114
- ...workloadRoleBindings!.dataRetention.task,
2115
- cluster: foundation.cluster,
2116
- environment: {
2117
- ...dataRetentionContainer.environment,
2118
- AWS_REGION: region,
2119
- EBK_DATABASE_HOST: foundation.database.clusterEndpoint,
2120
- EBK_DATABASE_NAME: databaseProvision.databaseName,
2121
- EBK_DATABASE_PORT: $interpolate\`\${foundation.database.port}\`,
2122
- EBK_DATABASE_USERNAME: databaseProvision.readwriteRole,
2123
- EBK_RDS_CA_BUNDLE: '/app/rds-global-bundle.pem',
2124
- EBK_READWRITE_SECRET_ARN: databaseProvision.readwriteSecretArn,
2125
- EBK_SLICE: '${name}',
2126
- EBK_STAGE: $app.stage,
2127
- EBK_WORKLOAD_IDENTITY: '${name}:data-retention-job',
2128
- EBK_WORKSPACE: '${workspace}',
2129
- EVENT_BUS_NAME: foundation.eventBus.name,
2130
- },
2131
- image: dataRetentionContainer.image,
2132
- link: secretLinksFor('data-retention-job-task'),
2133
- logging: {
2134
- name: retentionTaskLogs.name,
2135
- retention: '1 month',
2136
- },
2137
- transform: {
2138
- logGroup: {
2139
- logGroupClass: retentionTaskLogs.logGroupClass,
2140
- tags: retentionTaskLogs.tags,
2141
- },
2142
- taskDefinition: {
2143
- family: workloadRoleResourceNames!.dataRetentionTaskFamily,
2144
- },
2145
- },
2146
- });
2147
- const retentionTaskLogDataProtection = managedLogDataProtection(
2148
- '${pascalName}DataRetentionTaskLog',
2149
- retentionTaskLogs,
2150
- retentionTaskLogs.name,
2151
- [retentionTask.nodes.taskDefinition],
2152
- foundation.discovery.alertTopicArn,
2153
- );
2154
- const retentionWorkflowLogs = managedLogGroup(
2155
- '${pascalName}DataRetentionWorkflowLogs',
2156
- 'job-data-retention-orchestration',
2157
- foundation.discovery.alertTopicArn,
2158
- );
2159
- const retentionOverrides = retentionTask.containers.apply(
2160
- (containers: string[]) => ({
2161
- ContainerOverrides: containers.map((containerName) => ({
2162
- Environment: [
2163
- {
2164
- Name: 'EBK_RETENTION_APPROVAL_ID',
2165
- Value: '{% $states.input.approvalRequestId %}',
2166
- },
2167
- {
2168
- Name: 'EBK_RETENTION_CORRELATION_ID',
2169
- Value: '{% $states.input.correlationId %}',
2170
- },
2171
- {
2172
- Name: 'EBK_RETENTION_AS_OF',
2173
- Value: '{% $states.input.asOf %}',
2174
- },
2175
- {
2176
- Name: 'EBK_RETENTION_MODE',
2177
- Value: '{% $states.input.mode %}',
2178
- },
2179
- {
2180
- Name: 'EBK_RETENTION_RUN_ID',
2181
- Value: '{% $states.input.runId %}',
2182
- },
2183
- {
2184
- Name: 'EBK_STEP_FUNCTIONS_TASK_TOKEN',
2185
- Value: '{% $states.context.Task.Token %}',
2186
- },
2187
- ],
2188
- Name: containerName,
2189
- })),
2190
- }),
2191
- );
2192
- const retentionStateMachine = createRawStateMachine(
2193
- '${pascalName}DataRetention',
2194
- {
2195
- StartAt: 'RunDataRetention',
2196
- States: {
2197
- DataRetentionSucceeded: {
2198
- QueryLanguage: 'JSONata',
2199
- Type: 'Succeed',
2200
- },
2201
- RunDataRetention: {
2202
- Arguments: {
2203
- ...taskArguments(retentionTask),
2204
- Overrides: retentionOverrides,
2205
- },
2206
- Next: 'DataRetentionSucceeded',
2207
- QueryLanguage: 'JSONata',
2208
- Resource: 'arn:aws:states:::ecs:runTask.waitForTaskToken',
2209
- Retry: [
2210
- {
2211
- BackoffRate: 2,
2212
- ErrorEquals: [
2213
- 'ECS.AmazonECSException',
2214
- 'ECS.ECSException',
2215
- ],
2216
- IntervalSeconds: 10,
2217
- MaxAttempts: 2,
2218
- },
2219
- ],
2220
- TimeoutSeconds: 2700,
2221
- Type: 'Task',
2222
- },
2223
- },
2224
- },
2225
- retentionWorkflowLogs.logGroup,
2226
- workloadRoleBindings!.dataRetention.orchestration.roleArn,
2227
- );
2228
- const retentionFailureAlarm = new aws.cloudwatch.MetricAlarm(
2229
- '${pascalName}DataRetentionFailure',
2230
- {
2231
- alarmActions: [foundation.discovery.alertTopicArn],
2232
- alarmDescription: operationalAlarmDescription({
2233
- businessSymptom:
2234
- 'The built-in retention Job terminated unsuccessfully.',
2235
- id: 'retention-job-failure',
2236
- runbook: 'docs/runbooks/database-recovery.md',
2237
- }),
2238
- comparisonOperator: 'GreaterThanOrEqualToThreshold',
2239
- evaluationPeriods: 1,
2240
- metricQueries: [
2241
- ...['ExecutionsFailed', 'ExecutionsTimedOut', 'ExecutionsAborted'].map(
2242
- (metricName, index) => ({
2243
- id: 'm' + index,
2244
- metric: {
2245
- dimensions: {
2246
- StateMachineArn: retentionStateMachine.arn,
2247
- },
2248
- metricName,
2249
- namespace: 'AWS/States',
2250
- period: 60,
2251
- stat: 'Sum',
2252
- },
2253
- returnData: false,
2254
- }),
2255
- ),
2256
- {
2257
- expression: 'm0+m1+m2',
2258
- id: 'failures',
2259
- label: 'Retention terminal execution failures',
2260
- returnData: true,
2261
- },
2262
- ],
2263
- name: '${name}-' + $app.stage + '-retention-job-failure',
2264
- threshold: 1,
2265
- treatMissingData: 'notBreaching',
2266
- },
2267
- );
2268
- const retentionRegistration = registerProductRetention(
2269
- retentionStateMachine.arn,
2270
- );
2271
- migrationControls.dataRetention = {
2272
- registration: retentionRegistration,
2273
- retentionFailureAlarm,
2274
- retentionStateMachine,
2275
- retentionTask,
2276
- retentionTaskLogDataProtection,
2277
- retentionWorkflowLogs,
2278
- };
2279
- const retentionMaintenanceTaskLogs = managedLogContract(
2280
- 'job-data-retention-maintenance',
2281
- );
2282
- const retentionMaintenanceTask = new sst.aws.Task(
2283
- '${pascalName}DataRetentionMaintenanceTask',
2284
- {
2285
- ...workloadRoleBindings!.dataRetention.maintenance.task,
2286
- cluster: foundation.cluster,
2287
- environment: {
2288
- ...dataRetentionContainer.environment,
2289
- AWS_REGION: region,
2290
- EBK_DATABASE_HOST: foundation.database.clusterEndpoint,
2291
- EBK_DATABASE_NAME: databaseProvision.databaseName,
2292
- EBK_DATABASE_PORT: $interpolate\`\${foundation.database.port}\`,
2293
- EBK_DATABASE_USERNAME: databaseProvision.readwriteRole,
2294
- EBK_RDS_CA_BUNDLE: '/app/rds-global-bundle.pem',
2295
- EBK_READWRITE_SECRET_ARN:
2296
- databaseProvision.readwriteSecretArn,
2297
- EBK_SLICE: '${name}',
2298
- EBK_STAGE: $app.stage,
2299
- EBK_WORKLOAD_IDENTITY: '${name}:data-retention-job',
2300
- EBK_WORKSPACE: '${workspace}',
2301
- },
2302
- image: dataRetentionContainer.image,
2303
- link: secretLinksFor(
2304
- 'data-retention-maintenance-job-task',
2305
- ),
2306
- logging: {
2307
- name: retentionMaintenanceTaskLogs.name,
2308
- retention: '1 month',
2309
- },
2310
- transform: {
2311
- logGroup: {
2312
- logGroupClass:
2313
- retentionMaintenanceTaskLogs.logGroupClass,
2314
- tags: retentionMaintenanceTaskLogs.tags,
2315
- },
2316
- taskDefinition: {
2317
- family:
2318
- workloadRoleResourceNames!
2319
- .dataRetentionMaintenanceTaskFamily,
2320
- },
2321
- },
2322
- },
2323
- );
2324
- const retentionMaintenanceTaskLogDataProtection =
2325
- managedLogDataProtection(
2326
- '${pascalName}DataRetentionMaintenanceTaskLog',
2327
- retentionMaintenanceTaskLogs,
2328
- retentionMaintenanceTaskLogs.name,
2329
- [retentionMaintenanceTask.nodes.taskDefinition],
2330
- foundation.discovery.alertTopicArn,
2331
- );
2332
- const retentionMaintenanceLauncherLogs = managedLogGroup(
2333
- '${pascalName}DataRetentionMaintenanceLauncherLogs',
2334
- 'job-data-retention-maintenance-launcher',
2335
- foundation.discovery.alertTopicArn,
2336
- );
2337
- const retentionMaintenanceContainerName =
2338
- retentionMaintenanceTask.containers.apply(
2339
- (containers: string[]) => {
2340
- if (containers.length !== 1 || !containers[0]) {
2341
- throw new Error(
2342
- 'Retention maintenance requires exactly one task container.',
2343
- );
2344
- }
2345
- return containers[0];
2346
- },
2347
- );
2348
- const retentionMaintenanceLauncher = new sst.aws.Function(
2349
- '${pascalName}DataRetentionMaintenanceLauncher',
2350
- {
2351
- ...workloadRoleBindings!.dataRetention.maintenance.launcher,
2352
- environment: {
2353
- EBK_MAINTENANCE_ASSIGN_PUBLIC_IP:
2354
- retentionMaintenanceTask.assignPublicIp.apply(
2355
- (value: boolean) => String(value),
2356
- ),
2357
- EBK_MAINTENANCE_CLUSTER_ARN:
2358
- retentionMaintenanceTask.cluster,
2359
- EBK_MAINTENANCE_CONTAINER_NAME:
2360
- retentionMaintenanceContainerName,
2361
- EBK_MAINTENANCE_SECURITY_GROUP_IDS: $jsonStringify(
2362
- retentionMaintenanceTask.securityGroups,
2363
- ),
2364
- EBK_MAINTENANCE_SUBNET_IDS: $jsonStringify(
2365
- retentionMaintenanceTask.subnets,
2366
- ),
2367
- EBK_MAINTENANCE_TASK_DEFINITION_ARN:
2368
- retentionMaintenanceTask.taskDefinition,
2369
- EBK_STAGE: $app.stage,
2370
- EBK_WORKSPACE: '${workspace}',
2371
- },
2372
- handler: 'jobs/data-retention-maintenance-launcher.handler',
2373
- ...lambdaLogging(
2374
- retentionMaintenanceLauncherLogs.logGroup.name,
2375
- ),
2376
- timeout: '1 minute',
2377
- },
2378
- );
2379
- const retentionMaintenanceRule = new aws.cloudwatch.EventRule(
2380
- '${pascalName}DataRetentionMaintenanceSchedule',
2381
- {
2382
- name:
2383
- workloadRoleResourceNames!.dataRetentionMaintenanceRule,
2384
- scheduleExpression: 'rate(1 day)',
2385
- },
2386
- );
2387
- const retentionMaintenancePermission =
2388
- new aws.lambda.Permission(
2389
- '${pascalName}DataRetentionMaintenanceSchedulePermission',
2390
- {
2391
- action: 'lambda:InvokeFunction',
2392
- function: retentionMaintenanceLauncher.arn,
2393
- principal: 'events.amazonaws.com',
2394
- sourceArn: retentionMaintenanceRule.arn,
2395
- },
2396
- );
2397
- const retentionMaintenanceTarget =
2398
- new aws.cloudwatch.EventTarget(
2399
- '${pascalName}DataRetentionMaintenanceTarget',
2400
- {
2401
- arn: retentionMaintenanceLauncher.arn,
2402
- rule: retentionMaintenanceRule.name,
2403
- targetId: 'DataRetentionMaintenance',
2404
- },
2405
- { dependsOn: [retentionMaintenancePermission] },
2406
- );
2407
- migrationControls.dataRetentionMaintenance = {
2408
- retentionMaintenanceLauncher,
2409
- retentionMaintenanceLauncherLogs,
2410
- retentionMaintenanceRule,
2411
- retentionMaintenanceTarget,
2412
- retentionMaintenanceTask,
2413
- retentionMaintenanceTaskLogDataProtection,
2414
2610
  };
2415
2611
 
2612
+ ${''}\
2416
2613
  for (const [databaseIdentifier, target] of Object.entries(
2417
2614
  databaseProvisions.databases,
2418
2615
  )) {
@@ -2434,12 +2631,12 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2434
2631
  'database-retirement',
2435
2632
  databaseIdentifier,
2436
2633
  );
2437
- const databaseRoleBindings =
2438
- workloadRoleBindings!.database(databaseIdentifier);
2439
2634
  const bootstrapTask = new sst.aws.Task(
2440
2635
  target.resourceName + 'BootstrapTask',
2441
2636
  {
2442
- ...databaseRoleBindings.bootstrap,
2637
+ permissions: nativeAuthority.permissions(
2638
+ 'database-' + databaseIdentifier + '-bootstrap-task',
2639
+ ),
2443
2640
  cluster: foundation.cluster,
2444
2641
  command: ['node', 'jobs/bootstrap-database.mjs'],
2445
2642
  environment: {
@@ -2496,7 +2693,9 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2496
2693
  const migrationTask = new sst.aws.Task(
2497
2694
  target.resourceName + 'MigrationTask',
2498
2695
  {
2499
- ...databaseRoleBindings.migration,
2696
+ permissions: nativeAuthority.permissions(
2697
+ 'database-' + databaseIdentifier + '-migration-task',
2698
+ ),
2500
2699
  cluster: foundation.cluster,
2501
2700
  environment: {
2502
2701
  ...databaseMigrationContainer.environment,
@@ -2562,6 +2761,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2562
2761
  Next: 'RunDatabaseMigration',
2563
2762
  QueryLanguage: 'JSONata',
2564
2763
  Resource: 'arn:aws:states:::ecs:runTask.sync',
2764
+ // The first bootstrap of a Slice runs minutes after its execution
2765
+ // role is created; ECR can still answer "not found" to the fresh
2766
+ // role and the task never starts (EBK-INT-2026-072). Bootstrap is
2767
+ // idempotent, so a bounded retry is safe.
2768
+ Retry: [
2769
+ {
2770
+ BackoffRate: 2,
2771
+ ErrorEquals: ['States.TaskFailed'],
2772
+ IntervalSeconds: 30,
2773
+ MaxAttempts: 3,
2774
+ },
2775
+ ],
2565
2776
  TimeoutSeconds: 2700,
2566
2777
  Type: 'Task',
2567
2778
  },
@@ -2583,7 +2794,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2583
2794
  },
2584
2795
  },
2585
2796
  migrationWorkflowLogs.logGroup,
2586
- databaseRoleBindings.migrationOrchestration.roleArn,
2797
+ 'database-' + databaseIdentifier + '-migration-orchestration',
2587
2798
  );
2588
2799
  const registration = registerProductMigration(
2589
2800
  target.resourceName + 'MigrationRegistration',
@@ -2592,10 +2803,11 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2592
2803
  );
2593
2804
  const retirementTask =
2594
2805
  $app.stage === 'development' &&
2595
- databaseIdentifier === 'retirement_rehearsal' &&
2596
- databaseRoleBindings.retirement
2806
+ databaseIdentifier === 'retirement_rehearsal'
2597
2807
  ? new sst.aws.Task(target.resourceName + 'RetirementTask', {
2598
- ...databaseRoleBindings.retirement.task,
2808
+ permissions: nativeAuthority.permissions(
2809
+ 'database-' + databaseIdentifier + '-retirement-task',
2810
+ ),
2599
2811
  cluster: foundation.cluster,
2600
2812
  command: ['node', 'jobs/retire-database.mjs'],
2601
2813
  environment: {
@@ -2709,7 +2921,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2709
2921
  },
2710
2922
  },
2711
2923
  retirementWorkflowLogs.logGroup,
2712
- databaseRoleBindings.retirement!.orchestration.roleArn,
2924
+ 'database-' + databaseIdentifier + '-retirement-orchestration',
2713
2925
  );
2714
2926
  retirementControl = {
2715
2927
  retirementWorkflowLogs,
@@ -2731,12 +2943,15 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2731
2943
  }
2732
2944
  }
2733
2945
 
2946
+ `
2947
+ : ''}\
2734
2948
  const outboxRelayAlarm = new aws.cloudwatch.MetricAlarm(
2735
2949
  '${pascalName}OutboxRelayErrors',
2736
2950
  {
2737
2951
  alarmActions: [foundation.discovery.alertTopicArn],
2738
2952
  alarmDescription: operationalAlarmDescription({
2739
- businessSymptom: 'The transactional outbox relay is failing.',
2953
+ businessSymptom:
2954
+ 'The isolated performance-sink outbox relay is failing.',
2740
2955
  id: 'outbox-relay-errors',
2741
2956
  runbook: 'docs/runbooks/async-recovery.md',
2742
2957
  }),
@@ -2821,27 +3036,6 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2821
3036
  treatMissingData: 'breaching',
2822
3037
  },
2823
3038
  );
2824
- const outboxBacklogAlarm = new aws.cloudwatch.MetricAlarm(
2825
- '${pascalName}OutboxBacklog',
2826
- {
2827
- alarmActions: [foundation.discovery.alertTopicArn],
2828
- alarmDescription: operationalAlarmDescription({
2829
- businessSymptom: 'Transactional outbox work is accumulating.',
2830
- id: 'outbox-backlog',
2831
- runbook: 'docs/runbooks/async-recovery.md',
2832
- }),
2833
- comparisonOperator: 'GreaterThanOrEqualToThreshold',
2834
- dimensions: { Slice: '${name}', Stage: $app.stage },
2835
- evaluationPeriods: 2,
2836
- metricName: 'OutboxBacklog',
2837
- name: '${name}-' + $app.stage + '-outbox-backlog',
2838
- namespace: 'EBK/Async',
2839
- period: 300,
2840
- statistic: 'Maximum',
2841
- threshold: 1,
2842
- treatMissingData: 'notBreaching',
2843
- },
2844
- );
2845
3039
  const inboxCleanupBacklogAlarm = new aws.cloudwatch.MetricAlarm(
2846
3040
  '${pascalName}InboxCleanupBacklog',
2847
3041
  {
@@ -2987,6 +3181,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
2987
3181
  performanceLoadCleanupBacklogAlarm,
2988
3182
  performanceLoadCleanupDeadlineAlarm,
2989
3183
  asyncOutboxRelay,
3184
+ ${sql ? ' sqlOutbox,\n sqlOutboxAttemptsAlarm,\n sqlOutboxBacklogAlarm,\n sqlOutboxRelayErrorAlarm,\n' : ''}\
2990
3185
  asyncRecoveryLedger,
2991
3186
  asyncScheduleTarget,
2992
3187
  asyncTargetDlq,
@@ -3006,12 +3201,18 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
3006
3201
  dataExportCleanupRule,
3007
3202
  dataExportCleanupTarget,
3008
3203
  dataExportStore,
3009
- database,
3204
+ ${sql ? ' database,\n' : ''}\
3205
+ ${' keyValue,\n'}\
3010
3206
  dlqAlarm,
3011
3207
  eventDlq,
3012
3208
  eventQueue,
3013
3209
  machineClientProvisioner,
3014
3210
  migrationControls,
3211
+ eventDeliveryAttemptsAlarm,
3212
+ eventIntentRejectedAlarm,
3213
+ keyValueReconciliationErrorAlarm,
3214
+ keyValueStreamDeliveryErrorAlarm,
3215
+ keyValueStreamIteratorAgeAlarm,
3015
3216
  outboxBacklogAlarm,
3016
3217
  outboxRelayAlarm,
3017
3218
  outboxRelayRule,
@@ -3034,5 +3235,7 @@ export function product(workloadRoles?: StandardSliceWorkloadRolePreflight) {
3034
3235
  }
3035
3236
  `,
3036
3237
  };
3238
+ Object.assign(files, (0, built_in_plan_key_value_retention_infrastructure_js_1.renderKeyValueRetentionInfrastructureFiles)(name, pascalName));
3239
+ return files;
3037
3240
  }
3038
3241
  //# sourceMappingURL=built-in-plan-infrastructure-files.js.map