@intentius/chant-lexicon-aws 0.124.31 → 0.124.32

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 (644) hide show
  1. package/dist/actions/dynamodb.js +41 -0
  2. package/dist/actions/ecr.js +9 -0
  3. package/dist/actions/ecs.js +5 -0
  4. package/dist/actions/iam.js +3 -0
  5. package/dist/actions/index.js +9 -0
  6. package/dist/actions/lambda.js +11 -0
  7. package/dist/actions/logs.js +4 -0
  8. package/dist/actions/s3.js +40 -0
  9. package/dist/actions/sns.js +5 -0
  10. package/dist/actions/sqs.js +15 -0
  11. package/dist/agentcore/trace-fetch.d.ts.map +1 -1
  12. package/dist/agentcore/trace-fetch.js +472 -0
  13. package/dist/agentcore/trace-render.js +359 -0
  14. package/dist/ambient.js +148 -0
  15. package/dist/api/credential-chain.d.ts +30 -3
  16. package/dist/api/credential-chain.d.ts.map +1 -1
  17. package/dist/api/credential-chain.js +509 -0
  18. package/dist/api/read-client.d.ts +16 -43
  19. package/dist/api/read-client.d.ts.map +1 -1
  20. package/dist/api/read-client.js +458 -0
  21. package/dist/api/sigv4.d.ts +4 -4
  22. package/dist/api/sigv4.js +185 -0
  23. package/dist/behaviour-kinds.js +114 -0
  24. package/dist/caller-identity.d.ts +3 -5
  25. package/dist/caller-identity.d.ts.map +1 -1
  26. package/dist/caller-identity.js +146 -0
  27. package/dist/codegen/docs-cli.js +2 -0
  28. package/dist/codegen/docs.js +120 -0
  29. package/dist/codegen/enum-overlay.js +162 -0
  30. package/dist/codegen/extensions.js +139 -0
  31. package/dist/codegen/fallback.js +32 -0
  32. package/dist/codegen/generate-cli.js +15 -0
  33. package/dist/codegen/generate-lexicon.js +70 -0
  34. package/dist/codegen/generate-typescript.js +226 -0
  35. package/dist/codegen/generate.d.ts.map +1 -1
  36. package/dist/codegen/generate.js +234 -0
  37. package/dist/codegen/naming.js +135 -0
  38. package/dist/codegen/package.js +67 -0
  39. package/dist/codegen/patches.d.ts +26 -1
  40. package/dist/codegen/patches.d.ts.map +1 -1
  41. package/dist/codegen/patches.js +90 -0
  42. package/dist/codegen/property-overlay.js +85 -0
  43. package/dist/codegen/property-overlay.json +1 -16
  44. package/dist/codegen/sam.js +402 -0
  45. package/dist/codegen/typecheck.js +4 -0
  46. package/dist/codegen/versions.js +31 -0
  47. package/dist/components/__tests__/mock-cloud-executor.js +326 -0
  48. package/dist/components/apply.d.ts +44 -1
  49. package/dist/components/apply.d.ts.map +1 -1
  50. package/dist/components/apply.js +752 -0
  51. package/dist/components/builders.js +37 -0
  52. package/dist/components/capability-plugin.js +66 -0
  53. package/dist/components/cloud-executor.d.ts +35 -0
  54. package/dist/components/cloud-executor.d.ts.map +1 -1
  55. package/dist/components/cloud-executor.js +576 -0
  56. package/dist/components/config-bom.js +207 -0
  57. package/dist/components/host-delivery.js +117 -0
  58. package/dist/components/index.js +18 -0
  59. package/dist/components/job-submission.js +77 -0
  60. package/dist/components/publish.js +234 -0
  61. package/dist/components/safety.js +62 -0
  62. package/dist/components/wait-aws.js +68 -0
  63. package/dist/composites/agentcore-agent.js +187 -0
  64. package/dist/composites/agentcore-trust-policy.js +13 -0
  65. package/dist/composites/alb-shared.js +84 -0
  66. package/dist/composites/bucket-deployment.js +93 -0
  67. package/dist/composites/catalog.js +2714 -0
  68. package/dist/composites/dynamodb-table.js +66 -0
  69. package/dist/composites/ec2-instance-bundle.js +75 -0
  70. package/dist/composites/ec2-instance-role.js +26 -0
  71. package/dist/composites/ecr-repository.js +64 -0
  72. package/dist/composites/ecs-trust-policy.js +10 -0
  73. package/dist/composites/efs-with-access-point.js +44 -0
  74. package/dist/composites/eks-cluster.js +118 -0
  75. package/dist/composites/fargate-alb.js +216 -0
  76. package/dist/composites/fargate-service.js +222 -0
  77. package/dist/composites/index.js +28 -0
  78. package/dist/composites/lambda-api.js +15 -0
  79. package/dist/composites/lambda-dynamodb.js +77 -0
  80. package/dist/composites/lambda-eventbridge.js +27 -0
  81. package/dist/composites/lambda-function.js +54 -0
  82. package/dist/composites/lambda-s3.js +93 -0
  83. package/dist/composites/lambda-sns.js +23 -0
  84. package/dist/composites/lambda-sqs.js +34 -0
  85. package/dist/composites/landing-zone.js +82 -0
  86. package/dist/composites/microvm-app.js +293 -0
  87. package/dist/composites/minimal-vpc.js +40 -0
  88. package/dist/composites/monitoring-stack.js +105 -0
  89. package/dist/composites/nlb-service.js +61 -0
  90. package/dist/composites/rds-instance.js +98 -0
  91. package/dist/composites/scheduled-lambda.js +28 -0
  92. package/dist/composites/solr-fargate-service.js +33 -0
  93. package/dist/composites/step-functions-workflow.js +78 -0
  94. package/dist/composites/vpc-default.js +132 -0
  95. package/dist/condition.js +43 -0
  96. package/dist/coverage.js +4 -0
  97. package/dist/deep-observe.d.ts.map +1 -1
  98. package/dist/deep-observe.js +709 -0
  99. package/dist/deep-topology.js +226 -0
  100. package/dist/default-tags.js +50 -0
  101. package/dist/defaults.js +85 -0
  102. package/dist/dependencies.js +269 -0
  103. package/dist/detect.js +21 -0
  104. package/dist/disruption.d.ts.map +1 -1
  105. package/dist/disruption.js +129 -0
  106. package/dist/effect-receipt-row.js +107 -0
  107. package/dist/generated/index.d.ts +1297 -82
  108. package/dist/generated/index.d.ts.map +1 -1
  109. package/dist/generated/index.js +12382 -0
  110. package/dist/generated/runtime.js +4 -0
  111. package/dist/governance.js +131 -0
  112. package/dist/identity-observe.d.ts.map +1 -1
  113. package/dist/identity-observe.js +127 -0
  114. package/dist/import/generator.js +757 -0
  115. package/dist/import/live-export.js +34 -0
  116. package/dist/import/parser.js +394 -0
  117. package/dist/index.js +69 -0
  118. package/dist/integrity.json +6 -6
  119. package/dist/intrinsics.js +393 -0
  120. package/dist/lint/audit-catalog.js +87 -0
  121. package/dist/lint/audit-lineage.js +150 -0
  122. package/dist/lint/post-synth/cf-refs.js +247 -0
  123. package/dist/lint/post-synth/cor020.js +60 -0
  124. package/dist/lint/post-synth/ext001.d.ts.map +1 -1
  125. package/dist/lint/post-synth/ext001.js +197 -0
  126. package/dist/lint/post-synth/index.js +124 -0
  127. package/dist/lint/post-synth/waw010.js +41 -0
  128. package/dist/lint/post-synth/waw011.js +41 -0
  129. package/dist/lint/post-synth/waw013.js +38 -0
  130. package/dist/lint/post-synth/waw014.js +42 -0
  131. package/dist/lint/post-synth/waw015.js +88 -0
  132. package/dist/lint/post-synth/waw016.d.ts.map +1 -1
  133. package/dist/lint/post-synth/waw016.js +116 -0
  134. package/dist/lint/post-synth/waw017.js +43 -0
  135. package/dist/lint/post-synth/waw018.js +61 -0
  136. package/dist/lint/post-synth/waw019.js +64 -0
  137. package/dist/lint/post-synth/waw020.js +56 -0
  138. package/dist/lint/post-synth/waw021.js +44 -0
  139. package/dist/lint/post-synth/waw022.js +36 -0
  140. package/dist/lint/post-synth/waw023.js +40 -0
  141. package/dist/lint/post-synth/waw024.js +46 -0
  142. package/dist/lint/post-synth/waw025.js +36 -0
  143. package/dist/lint/post-synth/waw026.js +38 -0
  144. package/dist/lint/post-synth/waw027.js +41 -0
  145. package/dist/lint/post-synth/waw028.js +39 -0
  146. package/dist/lint/post-synth/waw029.js +54 -0
  147. package/dist/lint/post-synth/waw030.js +282 -0
  148. package/dist/lint/post-synth/waw031.js +58 -0
  149. package/dist/lint/post-synth/waw032.js +45 -0
  150. package/dist/lint/post-synth/waw033.js +75 -0
  151. package/dist/lint/post-synth/waw034.js +52 -0
  152. package/dist/lint/post-synth/waw035.js +56 -0
  153. package/dist/lint/post-synth/waw036.js +79 -0
  154. package/dist/lint/post-synth/waw037.js +67 -0
  155. package/dist/lint/post-synth/waw038.js +42 -0
  156. package/dist/lint/post-synth/waw039.js +42 -0
  157. package/dist/lint/post-synth/waw040.js +45 -0
  158. package/dist/lint/post-synth/waw041.js +40 -0
  159. package/dist/lint/post-synth/waw042.js +99 -0
  160. package/dist/lint/post-synth/waw043.js +51 -0
  161. package/dist/lint/post-synth/waw044.js +64 -0
  162. package/dist/lint/post-synth/waw045.js +49 -0
  163. package/dist/lint/post-synth/waw046.js +52 -0
  164. package/dist/lint/post-synth/waw047.js +43 -0
  165. package/dist/lint/post-synth/waw048.js +40 -0
  166. package/dist/lint/post-synth/waw049.js +78 -0
  167. package/dist/lint/post-synth/waw050.js +44 -0
  168. package/dist/lint/post-synth/waw051.js +41 -0
  169. package/dist/lint/post-synth/waw052.js +43 -0
  170. package/dist/lint/post-synth/waw053.js +43 -0
  171. package/dist/lint/post-synth/waw054.js +41 -0
  172. package/dist/lint/post-synth/waw055.js +41 -0
  173. package/dist/lint/post-synth/waw056.js +65 -0
  174. package/dist/lint/post-synth/waw057.js +43 -0
  175. package/dist/lint/post-synth/waw058.js +61 -0
  176. package/dist/lint/post-synth/waw059.js +338 -0
  177. package/dist/lint/post-synth/waw060.js +83 -0
  178. package/dist/lint/post-synth/waw061.js +60 -0
  179. package/dist/lint/post-synth/waw062.js +0 -0
  180. package/dist/lint/post-synth/waw063.js +0 -0
  181. package/dist/lint/post-synth/waw064.js +45 -0
  182. package/dist/lint/post-synth/waw065.js +104 -0
  183. package/dist/lint/post-synth/waw066.js +145 -0
  184. package/dist/lint/post-synth/waw067.js +115 -0
  185. package/dist/lint/post-synth/waw068.js +69 -0
  186. package/dist/lint/post-synth/waw069.js +0 -0
  187. package/dist/lint/rules/hardcoded-region.js +38 -0
  188. package/dist/lint/rules/iam-wildcard.js +60 -0
  189. package/dist/lint/rules/index.js +6 -0
  190. package/dist/lint/rules/s3-encryption.js +60 -0
  191. package/dist/live-attrs.js +42 -0
  192. package/dist/lsp/completions.d.ts.map +1 -1
  193. package/dist/lsp/completions.js +18 -0
  194. package/dist/lsp/hover.d.ts.map +1 -1
  195. package/dist/lsp/hover.js +66 -0
  196. package/dist/manifest.json +1 -1
  197. package/dist/mapping.js +33 -0
  198. package/dist/meta.json +17359 -784
  199. package/dist/nested-stack.js +95 -0
  200. package/dist/okf/index.md +203 -0
  201. package/dist/okf/rules/EXT001.md +1 -0
  202. package/dist/okf/rules/WAW016.md +2 -0
  203. package/dist/okf/rules/WAW019.md +1 -0
  204. package/dist/okf/rules/WAW028.md +1 -0
  205. package/dist/okf/rules/WAW030.md +2 -0
  206. package/dist/okf/rules/WAW039.md +1 -0
  207. package/dist/okf/rules/WAW049.md +1 -0
  208. package/dist/okf/rules/WAW056.md +1 -0
  209. package/dist/okf/rules/WAW058.md +1 -0
  210. package/dist/okf/rules/WAW062.md +1 -0
  211. package/dist/okf/rules/WAW064.md +1 -0
  212. package/dist/okf/rules/WAW065.md +1 -0
  213. package/dist/okf/rules/WAW066.md +1 -0
  214. package/dist/okf/rules/WAW067.md +1 -0
  215. package/dist/okf/rules/WAW068.md +1 -0
  216. package/dist/okf/rules/WAW069.md +4 -0
  217. package/dist/okf/types/AIWorkloadConfig.md +23 -0
  218. package/dist/okf/types/ARCRegionSwitchPlan.md +1 -0
  219. package/dist/okf/types/AccountAccessApplication.md +28 -0
  220. package/dist/okf/types/AccountAccessEntitlement.md +22 -0
  221. package/dist/okf/types/ActionTarget.md +20 -0
  222. package/dist/okf/types/AdConfiguration.md +21 -0
  223. package/dist/okf/types/Adapter.md +26 -0
  224. package/dist/okf/types/AgentContext.md +35 -0
  225. package/dist/okf/types/AgentGoal.md +31 -0
  226. package/dist/okf/types/AgentProfile.md +34 -0
  227. package/dist/okf/types/Alarm.md +3 -1
  228. package/dist/okf/types/AlarmModel.md +14 -9
  229. package/dist/okf/types/AmplifyWebhook.md +25 -0
  230. package/dist/okf/types/ApiCache.md +8 -8
  231. package/dist/okf/types/ApiGatewayManagedOverrides.md +5 -5
  232. package/dist/okf/types/AppAuthorization.md +35 -0
  233. package/dist/okf/types/AppBlockBuilder.md +1 -0
  234. package/dist/okf/types/AppInstance.md +2 -2
  235. package/dist/okf/types/AppInstanceBot.md +2 -2
  236. package/dist/okf/types/AppStreamFleet.md +3 -2
  237. package/dist/okf/types/AppSyncApiKey.md +6 -6
  238. package/dist/okf/types/AppSyncType.md +22 -0
  239. package/dist/okf/types/ApplicationStatusCheck.md +36 -0
  240. package/dist/okf/types/ApplicationVersion.md +4 -1
  241. package/dist/okf/types/ApplicationsList.md +26 -0
  242. package/dist/okf/types/ApprovalPolicy.md +28 -0
  243. package/dist/okf/types/ArchiveRule.md +24 -0
  244. package/dist/okf/types/Asset.md +30 -0
  245. package/dist/okf/types/Backup.md +31 -0
  246. package/dist/okf/types/BedrockAgentCoreDataset.md +1 -1
  247. package/dist/okf/types/BedrockAgentCoreGateway.md +3 -0
  248. package/dist/okf/types/BedrockSession.md +28 -0
  249. package/dist/okf/types/BillEstimate.md +35 -0
  250. package/dist/okf/types/Brand.md +32 -0
  251. package/dist/okf/types/CallAnalyticsCategory.md +25 -0
  252. package/dist/okf/types/Campaign.md +28 -0
  253. package/dist/okf/types/CapacityProvider.md +30 -0
  254. package/dist/okf/types/Case.md +24 -0
  255. package/dist/okf/types/CertificateAssociation.md +13 -0
  256. package/dist/okf/types/ChangeSet.md +36 -0
  257. package/dist/okf/types/ChannelFlow.md +29 -0
  258. package/dist/okf/types/ChimeChannel.md +39 -0
  259. package/dist/okf/types/Classifier.md +6 -6
  260. package/dist/okf/types/ClientVpnAuthorizationRule.md +6 -6
  261. package/dist/okf/types/ClientVpnEndpoint.md +2 -0
  262. package/dist/okf/types/ClientVpnRoute.md +5 -5
  263. package/dist/okf/types/CloudConnector.md +29 -0
  264. package/dist/okf/types/Cluster.md +39 -0
  265. package/dist/okf/types/ClusterSchedulerConfig.md +30 -0
  266. package/dist/okf/types/CodeCommitRepository.md +12 -12
  267. package/dist/okf/types/CodeConnectionsHost.md +26 -0
  268. package/dist/okf/types/CodeRepository.md +5 -5
  269. package/dist/okf/types/CompositeAlarm.md +1 -0
  270. package/dist/okf/types/ComputeEnvironment.md +2 -0
  271. package/dist/okf/types/ComputeNodeGroup.md +1 -1
  272. package/dist/okf/types/ComputeQuota.md +34 -0
  273. package/dist/okf/types/ConfigRule.md +1 -1
  274. package/dist/okf/types/ConfigurationRecorder.md +7 -6
  275. package/dist/okf/types/ConnectAttachment.md +2 -0
  276. package/dist/okf/types/ConnectQueue.md +5 -1
  277. package/dist/okf/types/ConnectVocabulary.md +28 -0
  278. package/dist/okf/types/ConnectionType.md +24 -0
  279. package/dist/okf/types/ConsentPortal.md +33 -0
  280. package/dist/okf/types/ContactMethod.md +29 -0
  281. package/dist/okf/types/ContainerAssociation.md +26 -0
  282. package/dist/okf/types/ContainerFleet.md +1 -1
  283. package/dist/okf/types/ContainerGroupDefinition.md +1 -1
  284. package/dist/okf/types/Content.md +40 -0
  285. package/dist/okf/types/ContentAssociation.md +28 -0
  286. package/dist/okf/types/CustomDetectionRuleAssociation.md +28 -0
  287. package/dist/okf/types/CustomEntityType.md +4 -9
  288. package/dist/okf/types/Customization.md +22 -0
  289. package/dist/okf/types/CwIntegration.md +31 -0
  290. package/dist/okf/types/DAXParameterGroup.md +3 -8
  291. package/dist/okf/types/DAXSubnetGroup.md +0 -5
  292. package/dist/okf/types/DBClusterEndpoint.md +31 -0
  293. package/dist/okf/types/DBProxyTargetGroup.md +1 -0
  294. package/dist/okf/types/DBSnapshot.md +62 -0
  295. package/dist/okf/types/DLMLifecyclePolicy.md +12 -12
  296. package/dist/okf/types/DLPSetting.md +31 -0
  297. package/dist/okf/types/DMSInstanceProfile.md +1 -1
  298. package/dist/okf/types/DRSLaunchConfigurationTemplate.md +28 -0
  299. package/dist/okf/types/Daemon.md +1 -0
  300. package/dist/okf/types/DataExchangeDataSet.md +29 -0
  301. package/dist/okf/types/DataIntegrationFlow.md +27 -0
  302. package/dist/okf/types/DataMigration.md +1 -1
  303. package/dist/okf/types/DataProvider.md +2 -1
  304. package/dist/okf/types/DataQualityRuleset.md +6 -11
  305. package/dist/okf/types/DataSource.md +23 -0
  306. package/dist/okf/types/Dataset.md +20 -0
  307. package/dist/okf/types/DatasetIntegration.md +23 -0
  308. package/dist/okf/types/DbCluster.md +1 -1
  309. package/dist/okf/types/DbInstance.md +8 -2
  310. package/dist/okf/types/DeadlineBudget.md +29 -0
  311. package/dist/okf/types/DelegationSet.md +23 -0
  312. package/dist/okf/types/DeliveryChannel.md +6 -11
  313. package/dist/okf/types/DevOpsAgentAgentSpace.md +4 -0
  314. package/dist/okf/types/DevOpsAgentService.md +1 -0
  315. package/dist/okf/types/DevOpsAgentTrigger.md +28 -0
  316. package/dist/okf/types/DirectConnectGatewayAttachment.md +2 -0
  317. package/dist/okf/types/Directory.md +60 -0
  318. package/dist/okf/types/DocDBDBClusterParameterGroup.md +5 -10
  319. package/dist/okf/types/DocDBDBSubnetGroup.md +4 -9
  320. package/dist/okf/types/DocDBElasticClusterSnapshot.md +36 -0
  321. package/dist/okf/types/DocumentClassifierEndpoint.md +27 -0
  322. package/dist/okf/types/Domain.md +27 -0
  323. package/dist/okf/types/EKSCertificateAuthority.md +42 -0
  324. package/dist/okf/types/EKSCluster.md +8 -0
  325. package/dist/okf/types/EcSnapshot.md +66 -0
  326. package/dist/okf/types/EmailIdentityCertificate.md +15 -0
  327. package/dist/okf/types/EndpointConfig.md +14 -13
  328. package/dist/okf/types/EntityRecognizer.md +27 -0
  329. package/dist/okf/types/EntityRecognizerEndpoint.md +31 -0
  330. package/dist/okf/types/EnvironmentEC2.md +13 -13
  331. package/dist/okf/types/EvaluationForm.md +1 -0
  332. package/dist/okf/types/Evaluator.md +6 -2
  333. package/dist/okf/types/EventAction.md +26 -0
  334. package/dist/okf/types/EventRule.md +2 -0
  335. package/dist/okf/types/EventSource.md +30 -0
  336. package/dist/okf/types/EventTracker.md +22 -0
  337. package/dist/okf/types/EventsV2EventBus.md +28 -0
  338. package/dist/okf/types/EventsV2ResourcePolicy.md +19 -0
  339. package/dist/okf/types/EventsV2Subscriber.md +39 -0
  340. package/dist/okf/types/ExperimentDefinition.md +39 -0
  341. package/dist/okf/types/ExperimentRun.md +33 -0
  342. package/dist/okf/types/ExperimentTrialComponent.md +13 -11
  343. package/dist/okf/types/FHIRDatastore.md +3 -0
  344. package/dist/okf/types/FSxSnapshot.md +5 -5
  345. package/dist/okf/types/FSxVolume.md +9 -9
  346. package/dist/okf/types/FeaturedResultsSet.md +26 -0
  347. package/dist/okf/types/Feed.md +1 -0
  348. package/dist/okf/types/FieldLevelEncryptionConfig.md +25 -0
  349. package/dist/okf/types/FieldLevelEncryptionProfile.md +22 -0
  350. package/dist/okf/types/FileCache.md +45 -0
  351. package/dist/okf/types/Filter.md +27 -0
  352. package/dist/okf/types/Firewall.md +6 -0
  353. package/dist/okf/types/FlowMediaStream.md +28 -0
  354. package/dist/okf/types/FlowOutput.md +1 -0
  355. package/dist/okf/types/FpgaImage.md +38 -0
  356. package/dist/okf/types/Function.md +2 -2
  357. package/dist/okf/types/Gateway.md +41 -0
  358. package/dist/okf/types/GatewayClusterAssociations.md +23 -0
  359. package/dist/okf/types/GatewayRateLimit.md +26 -0
  360. package/dist/okf/types/GatewayRule.md +32 -0
  361. package/dist/okf/types/GlobalReplicationGroup.md +3 -0
  362. package/dist/okf/types/GlobalResolver.md +1 -1
  363. package/dist/okf/types/GlobalTable.md +1 -0
  364. package/dist/okf/types/GlueConnection.md +5 -4
  365. package/dist/okf/types/GlueSecurityConfiguration.md +1 -6
  366. package/dist/okf/types/GlueSession.md +38 -0
  367. package/dist/okf/types/GlueTable.md +5 -10
  368. package/dist/okf/types/GlueWorkflow.md +5 -10
  369. package/dist/okf/types/Group.md +27 -0
  370. package/dist/okf/types/Harness.md +1 -0
  371. package/dist/okf/types/HostKey.md +33 -0
  372. package/dist/okf/types/HostedZone.md +1 -0
  373. package/dist/okf/types/HttpApi.md +2 -0
  374. package/dist/okf/types/HttpNamespace.md +5 -5
  375. package/dist/okf/types/HubV2.md +1 -0
  376. package/dist/okf/types/HumanTaskUi.md +22 -0
  377. package/dist/okf/types/IPv4Pool.md +28 -0
  378. package/dist/okf/types/ImageBuilder.md +1 -0
  379. package/dist/okf/types/ImageBuilderImage.md +1 -1
  380. package/dist/okf/types/ImagePipeline.md +1 -1
  381. package/dist/okf/types/InferenceComponent.md +5 -1
  382. package/dist/okf/types/InfluxDBBackup.md +65 -0
  383. package/dist/okf/types/InfluxDBCluster.md +3 -0
  384. package/dist/okf/types/InfrastructureConfiguration.md +2 -0
  385. package/dist/okf/types/IngestionDestination.md +28 -0
  386. package/dist/okf/types/InputSecurityGroup.md +6 -4
  387. package/dist/okf/types/InspectorV2Connector.md +38 -0
  388. package/dist/okf/types/InstanceEventWindow.md +25 -0
  389. package/dist/okf/types/InstanceFleetConfig.md +10 -10
  390. package/dist/okf/types/InstanceGroupConfig.md +3 -3
  391. package/dist/okf/types/InstrumentationConfig.md +31 -0
  392. package/dist/okf/types/IntegrationAssociation.md +3 -0
  393. package/dist/okf/types/IoTSiteWiseApplication.md +34 -0
  394. package/dist/okf/types/IoTSiteWiseDataset.md +5 -2
  395. package/dist/okf/types/IoTSiteWiseTask.md +24 -0
  396. package/dist/okf/types/IpamExternalResourceVerificationToken.md +35 -0
  397. package/dist/okf/types/IpamInternetRegistryAssociation.md +32 -0
  398. package/dist/okf/types/Job.md +35 -0
  399. package/dist/okf/types/JobTemplate.md +26 -0
  400. package/dist/okf/types/KinesisChannel.md +31 -0
  401. package/dist/okf/types/KinesisStream.md +1 -0
  402. package/dist/okf/types/LambdaResourcePolicy.md +14 -0
  403. package/dist/okf/types/Lexicon.md +34 -0
  404. package/dist/okf/types/LicenseAssetGroup.md +23 -0
  405. package/dist/okf/types/LicenseConfiguration.md +33 -0
  406. package/dist/okf/types/LicenseServerEndpoint.md +32 -0
  407. package/dist/okf/types/LightsailKeyPair.md +29 -0
  408. package/dist/okf/types/LimitsProfile.md +27 -0
  409. package/dist/okf/types/LocationAzureBlob.md +2 -1
  410. package/dist/okf/types/LocationObjectStorage.md +1 -0
  411. package/dist/okf/types/LogAlarm.md +2 -0
  412. package/dist/okf/types/MGNConnector.md +23 -0
  413. package/dist/okf/types/MGNLaunchConfigurationTemplate.md +37 -0
  414. package/dist/okf/types/MLTransform.md +15 -15
  415. package/dist/okf/types/MWAAServerlessWorkflow.md +3 -0
  416. package/dist/okf/types/ManagedNotificationAccountContactAssociation.md +1 -0
  417. package/dist/okf/types/ManagedNotificationAdditionalChannelAssociation.md +1 -0
  418. package/dist/okf/types/MediaConvertJobTemplate.md +11 -13
  419. package/dist/okf/types/MediaConvertQueue.md +8 -10
  420. package/dist/okf/types/MediaInsightsPipelineConfiguration.md +28 -0
  421. package/dist/okf/types/MediaLiveInput.md +41 -18
  422. package/dist/okf/types/MediaPackageV2Channel.md +3 -0
  423. package/dist/okf/types/MediaPackageV2OriginEndpoint.md +1 -0
  424. package/dist/okf/types/MediaPipelineKinesisVideoStreamPool.md +28 -0
  425. package/dist/okf/types/MediaTailorFunction.md +27 -0
  426. package/dist/okf/types/MedicalVocabulary.md +21 -0
  427. package/dist/okf/types/Member.md +26 -0
  428. package/dist/okf/types/Memory.md +6 -0
  429. package/dist/okf/types/MemoryDBSnapshot.md +29 -0
  430. package/dist/okf/types/Metric.md +59 -0
  431. package/dist/okf/types/MetricAttribution.md +23 -0
  432. package/dist/okf/types/MicrosoftAD.md +11 -11
  433. package/dist/okf/types/MigrationProject.md +8 -1
  434. package/dist/okf/types/Monitor.md +26 -0
  435. package/dist/okf/types/NFSFileShare.md +44 -0
  436. package/dist/okf/types/NeptuneGraphGraph.md +1 -0
  437. package/dist/okf/types/NetworkConnector.md +4 -0
  438. package/dist/okf/types/NetworkFlowMonitorScope.md +23 -0
  439. package/dist/okf/types/NetworkMigrationDefinition.md +31 -0
  440. package/dist/okf/types/NetworkSecurityManagerDeployment.md +31 -0
  441. package/dist/okf/types/NetworkSecurityManagerPolicy.md +32 -0
  442. package/dist/okf/types/NetworkSecurityManagerScope.md +29 -0
  443. package/dist/okf/types/NotebookInstance.md +18 -18
  444. package/dist/okf/types/NotebookInstanceLifecycleConfig.md +6 -5
  445. package/dist/okf/types/NotifyConfiguration.md +35 -0
  446. package/dist/okf/types/OTelEnrichment.md +2 -0
  447. package/dist/okf/types/OnlineEvaluationConfig.md +0 -1
  448. package/dist/okf/types/OrganizationConfigRule.md +7 -7
  449. package/dist/okf/types/Outpost.md +32 -0
  450. package/dist/okf/types/ParallelData.md +40 -0
  451. package/dist/okf/types/Partition.md +5 -5
  452. package/dist/okf/types/PaymentConnector.md +4 -1
  453. package/dist/okf/types/Pentest.md +1 -0
  454. package/dist/okf/types/PerfReports.md +28 -0
  455. package/dist/okf/types/PermissionAssociation.md +30 -0
  456. package/dist/okf/types/PersonalizeDataset.md +1 -0
  457. package/dist/okf/types/PersonalizeDatasetGroup.md +1 -0
  458. package/dist/okf/types/PersonalizeSchema.md +1 -0
  459. package/dist/okf/types/Pipeline.md +25 -0
  460. package/dist/okf/types/PlaybackConfiguration.md +1 -0
  461. package/dist/okf/types/PolicyAssociation.md +1 -1
  462. package/dist/okf/types/PolicyGrant.md +2 -2
  463. package/dist/okf/types/PolicyPrincipalAttachment.md +2 -7
  464. package/dist/okf/types/PortalProduct.md +24 -0
  465. package/dist/okf/types/PrefetchSchedule.md +25 -0
  466. package/dist/okf/types/PricingPlanManagerSubscription.md +31 -0
  467. package/dist/okf/types/PrincipalAssociation.md +27 -0
  468. package/dist/okf/types/PrivateDnsNamespace.md +8 -8
  469. package/dist/okf/types/PrivateVirtualInterface.md +1 -0
  470. package/dist/okf/types/ProcurementPortalPreference.md +45 -0
  471. package/dist/okf/types/Program.md +33 -0
  472. package/dist/okf/types/ProjectMembership.md +1 -1
  473. package/dist/okf/types/ProtocolsList.md +26 -0
  474. package/dist/okf/types/PublicDnsNamespace.md +7 -7
  475. package/dist/okf/types/PublicVirtualInterface.md +1 -0
  476. package/dist/okf/types/QEV2IdcApplication.md +25 -0
  477. package/dist/okf/types/QueryLoggingConfig.md +21 -0
  478. package/dist/okf/types/QuerySuggestionsBlockList.md +25 -0
  479. package/dist/okf/types/QuickSightAssignment.md +24 -0
  480. package/dist/okf/types/RAMResourceAssociation.md +27 -0
  481. package/dist/okf/types/RDSClusterSnapshot.md +54 -0
  482. package/dist/okf/types/RDSDBParameterGroup.md +5 -0
  483. package/dist/okf/types/RDSDeployment.md +41 -0
  484. package/dist/okf/types/RcsAgent.md +38 -0
  485. package/dist/okf/types/ReceiptRule.md +5 -5
  486. package/dist/okf/types/ReceiptRuleSet.md +1 -6
  487. package/dist/okf/types/RecommenderFilter.md +27 -0
  488. package/dist/okf/types/RecommenderSchema.md +25 -0
  489. package/dist/okf/types/RecordSet.md +16 -22
  490. package/dist/okf/types/RecoveryPlan.md +28 -0
  491. package/dist/okf/types/RedshiftIdcApplication.md +31 -0
  492. package/dist/okf/types/RedshiftSnapshot.md +59 -0
  493. package/dist/okf/types/RegistrationAttachment.md +28 -0
  494. package/dist/okf/types/Registry.md +41 -0
  495. package/dist/okf/types/RegistryRecord.md +38 -0
  496. package/dist/okf/types/RelatedItem.md +24 -0
  497. package/dist/okf/types/ReplicationConfigurationTemplate.md +35 -0
  498. package/dist/okf/types/ReplicationSubnetGroup.md +4 -9
  499. package/dist/okf/types/ReplicationTask.md +14 -14
  500. package/dist/okf/types/ReportGenerator.md +29 -0
  501. package/dist/okf/types/ReportGroup.md +1 -3
  502. package/dist/okf/types/ResilienceHubV2Policy.md +1 -0
  503. package/dist/okf/types/ResilienceHubV2Service.md +1 -0
  504. package/dist/okf/types/ResourceConfiguration.md +1 -1
  505. package/dist/okf/types/ResourceMetricsConfiguration.md +21 -0
  506. package/dist/okf/types/RestApi.md +1 -0
  507. package/dist/okf/types/RetrievalInstruction.md +32 -0
  508. package/dist/okf/types/RouterOutput.md +1 -0
  509. package/dist/okf/types/Rule.md +31 -0
  510. package/dist/okf/types/RunCache.md +29 -0
  511. package/dist/okf/types/Runtime.md +2 -1
  512. package/dist/okf/types/SCNInstance.md +33 -0
  513. package/dist/okf/types/SDBDomain.md +2 -2
  514. package/dist/okf/types/SMBFileShare.md +49 -0
  515. package/dist/okf/types/SageMakerArtifact.md +27 -0
  516. package/dist/okf/types/SageMakerEndpoint.md +0 -1
  517. package/dist/okf/types/ScalableTarget.md +1 -0
  518. package/dist/okf/types/ScalingPlan.md +6 -6
  519. package/dist/okf/types/ScheduledReport.md +31 -0
  520. package/dist/okf/types/SecondaryNetwork.md +26 -0
  521. package/dist/okf/types/SecurityAgentArtifact.md +25 -0
  522. package/dist/okf/types/SecurityAgentIntegration.md +31 -0
  523. package/dist/okf/types/Server.md +1 -0
  524. package/dist/okf/types/ServerlessCache.md +2 -0
  525. package/dist/okf/types/ServerlessCacheSnapshot.md +31 -0
  526. package/dist/okf/types/ServerlessRepoApplication.md +32 -0
  527. package/dist/okf/types/ServiceDiscoveryInstance.md +3 -7
  528. package/dist/okf/types/SipMediaApplication.md +27 -0
  529. package/dist/okf/types/SiteToSiteVpnAttachment.md +2 -0
  530. package/dist/okf/types/SnapshotCopyGrant.md +20 -0
  531. package/dist/okf/types/Solution.md +1 -0
  532. package/dist/okf/types/SourceAssociation.md +25 -0
  533. package/dist/okf/types/SourceCredential.md +6 -6
  534. package/dist/okf/types/SourceNetwork.md +23 -0
  535. package/dist/okf/types/StackFleetAssociation.md +2 -7
  536. package/dist/okf/types/StorageTierPolicy.md +20 -0
  537. package/dist/okf/types/StorageVirtualMachine.md +9 -9
  538. package/dist/okf/types/Stream.md +28 -0
  539. package/dist/okf/types/SubnetCidrReservation.md +26 -0
  540. package/dist/okf/types/SubscriptionProvider.md +26 -0
  541. package/dist/okf/types/SupportPermit.md +29 -0
  542. package/dist/okf/types/Table.md +2 -1
  543. package/dist/okf/types/TableOptimizer.md +5 -10
  544. package/dist/okf/types/Tape.md +31 -0
  545. package/dist/okf/types/Template.md +36 -0
  546. package/dist/okf/types/Tenant.md +2 -0
  547. package/dist/okf/types/Terminology.md +39 -0
  548. package/dist/okf/types/Thesaurus.md +25 -0
  549. package/dist/okf/types/ThingPrincipalAttachment.md +3 -8
  550. package/dist/okf/types/Topic.md +1 -0
  551. package/dist/okf/types/TopicRuleDestination.md +1 -0
  552. package/dist/okf/types/TrafficPolicy.md +26 -0
  553. package/dist/okf/types/TrafficPolicyInstance.md +28 -0
  554. package/dist/okf/types/TranscribeVocabulary.md +27 -0
  555. package/dist/okf/types/TransitGatewayRouteTableAttachment.md +2 -0
  556. package/dist/okf/types/TransitVirtualInterface.md +1 -0
  557. package/dist/okf/types/Tunnel.md +25 -0
  558. package/dist/okf/types/UsageLimit.md +26 -0
  559. package/dist/okf/types/UseCase.md +23 -0
  560. package/dist/okf/types/User.md +47 -0
  561. package/dist/okf/types/VPCEndpoint.md +1 -1
  562. package/dist/okf/types/VPCEndpointService.md +6 -0
  563. package/dist/okf/types/VPCPeeringConnection.md +2 -2
  564. package/dist/okf/types/VPNConcentrator.md +1 -1
  565. package/dist/okf/types/VPNConnection.md +1 -1
  566. package/dist/okf/types/VerifiedDestinationNumber.md +25 -0
  567. package/dist/okf/types/View.md +27 -0
  568. package/dist/okf/types/VoiceConnector.md +30 -0
  569. package/dist/okf/types/Volume.md +44 -0
  570. package/dist/okf/types/Vpc.md +1 -1
  571. package/dist/okf/types/VpcAttachment.md +2 -0
  572. package/dist/okf/types/WebFunction.md +27 -0
  573. package/dist/okf/types/WebFunctionEndpoint.md +44 -0
  574. package/dist/okf/types/WebFunctionRevision.md +32 -0
  575. package/dist/okf/types/WickrNetwork.md +27 -0
  576. package/dist/okf/types/Worker.md +29 -0
  577. package/dist/okf/types/Workforce.md +26 -0
  578. package/dist/okf/types/Workload.md +35 -0
  579. package/dist/okf/types/WorkloadEstimate.md +35 -0
  580. package/dist/okf/types/Workspace.md +28 -0
  581. package/dist/okf/types/Workteam.md +8 -8
  582. package/dist/op/activities/aws-apply.js +214 -0
  583. package/dist/op/activities/floci.js +97 -0
  584. package/dist/op/activities/index.js +32 -0
  585. package/dist/op/builders.js +50 -0
  586. package/dist/ownership.js +52 -0
  587. package/dist/package-cli.js +25 -0
  588. package/dist/parameter.js +19 -0
  589. package/dist/plugin.d.ts.map +1 -1
  590. package/dist/plugin.js +1006 -0
  591. package/dist/properties.js +166 -0
  592. package/dist/pseudo.js +25 -0
  593. package/dist/receipt-store.d.ts.map +1 -1
  594. package/dist/receipt-store.js +233 -0
  595. package/dist/reference-catalog.js +106 -0
  596. package/dist/rules/ext001.ts +3 -3
  597. package/dist/rules/waw016.ts +2 -2
  598. package/dist/serializer.js +529 -0
  599. package/dist/spec/fetch.js +193 -0
  600. package/dist/spec/parse.js +259 -0
  601. package/dist/spec/pin.js +185 -0
  602. package/dist/spec/pinned-types.json +203 -0
  603. package/dist/stack-errors.js +14 -0
  604. package/dist/taggable.d.ts.map +1 -1
  605. package/dist/taggable.js +33 -0
  606. package/dist/teardown.js +199 -0
  607. package/dist/template-sections.js +53 -0
  608. package/dist/template-transform.js +50 -0
  609. package/dist/types/index.d.ts +18847 -1124
  610. package/dist/validate-cli.js +16 -0
  611. package/dist/validate.js +33 -0
  612. package/package.json +9 -9
  613. package/src/agentcore/trace-fetch.ts +2 -1
  614. package/src/api/credential-chain.ts +119 -9
  615. package/src/api/credential-isolation.test.ts +72 -0
  616. package/src/api/read-client-chain.test.ts +159 -0
  617. package/src/api/read-client.ts +42 -6
  618. package/src/api/sigv4.ts +4 -4
  619. package/src/caller-identity.ts +3 -5
  620. package/src/codegen/any-budget.test.ts +12 -2
  621. package/src/codegen/generate.ts +9 -0
  622. package/src/codegen/package.ts +2 -2
  623. package/src/codegen/patches.test.ts +95 -0
  624. package/src/codegen/patches.ts +53 -9
  625. package/src/codegen/property-overlay.json +1 -16
  626. package/src/components/apply.ts +218 -6
  627. package/src/components/cfn-plan-floci.e2e.test.ts +76 -0
  628. package/src/components/cfn-plan.test.ts +225 -16
  629. package/src/components/cloud-executor.ts +73 -25
  630. package/src/deep-observe.ts +2 -1
  631. package/src/disruption.ts +2 -1
  632. package/src/generated/index.d.ts +18847 -1124
  633. package/src/generated/index.ts +1376 -161
  634. package/src/generated/lexicon-aws.json +17359 -784
  635. package/src/identity-observe.ts +2 -1
  636. package/src/lint/post-synth/ext001.ts +3 -3
  637. package/src/lint/post-synth/waw016.ts +2 -2
  638. package/src/lsp/completions.ts +2 -1
  639. package/src/lsp/hover.ts +2 -1
  640. package/src/plugin.ts +2 -1
  641. package/src/receipt-store.ts +2 -1
  642. package/src/spec/pin.ts +3 -3
  643. package/src/spec/pinned-types.json +203 -0
  644. package/src/taggable.ts +2 -2
@@ -0,0 +1,752 @@
1
+ /**
2
+ * apply family — the most cloud-shaped family (see docs/components/cloud-boundary).
3
+ * AWS leaves for this starter set: cfn-deploy, ecs-update-service,
4
+ * lambda-deploy, s3-sync, cdn-invalidate, run-migration.
5
+ *
6
+ * `cfn-deploy` carries declarative safety options (changeset preview,
7
+ * `onReplace`, `stageGsi`) — sticky per-resource knowledge (a DynamoDB GSI
8
+ * updates one at a time; a key-schema change forces replacement) lives inside
9
+ * the capability, configured by options, never scripted per component. See
10
+ * docs/components/capabilities.mdx#stickiness-lives-in-the-capability.
11
+ *
12
+ * `cfn-deploy` and `ecs-update-service` are real implementations (#557, epic
13
+ * #551) over the injectable `CloudExecutor` (./cloud-executor.ts).
14
+ * `lambda-deploy` gained a real implementation in #558 (epic #551) — the one
15
+ * new capability the fourth, genuinely different validation component
16
+ * (image-processor-lambda) needed; see ../SPRAWL-VALIDATION.md. `s3-sync`,
17
+ * `cdn-invalidate`, and `run-migration` are also real over the same executor —
18
+ * `run-migration` dispatches on its target transport (ECS one-off task, Lambda
19
+ * invoke, or SSM host command).
20
+ */
21
+ import { createHash } from "node:crypto";
22
+ import { readFileSync } from "node:fs";
23
+ import { computePlanDigest } from "@intentius/chant/lifecycle/plan-digest";
24
+ import { defaultCloudExecutor } from "./cloud-executor.js";
25
+ /** CloudFormation's wording when a change set has nothing to apply — the stack
26
+ * is already current. AWS phrases it "The submitted information didn't contain
27
+ * changes."; `aws cloudformation deploy` reports "No updates are to be
28
+ * performed."; keep both plus a bare "no changes" for other backends/Floci. */
29
+ const NO_CHANGE_REASON = /(did ?n['’]?t|does ?n['’]?t|did not|does not) contain changes|no updates are to be performed|no changes/i;
30
+ /**
31
+ * True when CloudFormation reports the change set has nothing to apply. AWS
32
+ * surfaces this as a FAILED change set whose `StatusReason` names the empty
33
+ * diff (executing it then errors); when no reason is available, a FAILED set
34
+ * with zero proposed changes is the same no-op. A FAILED set with any other
35
+ * reason is a genuine create failure and must NOT be treated as a no-op.
36
+ */
37
+ export function isNoopChangeSet(changeSet) {
38
+ if (changeSet.status !== "FAILED")
39
+ return false;
40
+ return changeSet.statusReason
41
+ ? NO_CHANGE_REASON.test(changeSet.statusReason)
42
+ : changeSet.changes.length === 0;
43
+ }
44
+ // ── cfn-deploy ───────────────────────────────────────────────────────────────
45
+ /**
46
+ * Whether a proposed change replaces its resource. CloudFormation's
47
+ * `Replacement: Conditional` counts: the replacement depends on a value it
48
+ * resolves only while applying, so a reviewer has to read it as one (#4084).
49
+ */
50
+ export function cfnChangeReplaces(change) {
51
+ return change.replacement || change.replacementMode === "Conditional";
52
+ }
53
+ /**
54
+ * One CloudFormation resource change as a change-set entry (#4084). The
55
+ * address is the logical id, which is also the entity name the aws
56
+ * lexicon's graph IR gives the resource, so the entry maps onto its node
57
+ * (#4022). `Add` is a create, `Modify` an update or (when it replaces) a
58
+ * replace, `Remove` a delete, `Import` an import that changes nothing else,
59
+ * and `Dynamic` an update CloudFormation could not describe further.
60
+ */
61
+ export function cfnChangeEntry(member, change) {
62
+ const attributes = [...new Set(change.details ?? [])].sort().map((path) => ({ path }));
63
+ // A change inside a nested stack (#3997) sits under the nested stacks'
64
+ // logical ids, the way a terraform address sits under its module.
65
+ const module = change.nestedStack?.length ? change.nestedStack.join("/") : undefined;
66
+ const base = {
67
+ member,
68
+ lexicon: "aws",
69
+ planner: "chant",
70
+ address: module ? `${module}/${change.logicalResourceId}` : change.logicalResourceId,
71
+ type: change.resourceType,
72
+ name: change.logicalResourceId,
73
+ ...(module ? { module } : {}),
74
+ attributes,
75
+ };
76
+ switch (change.action) {
77
+ case "Add":
78
+ return { ...base, action: "create" };
79
+ case "Remove":
80
+ return { ...base, action: "delete", disruption: "destroy" };
81
+ case "Import":
82
+ return { ...base, action: "no-op", importing: true };
83
+ case "Dynamic":
84
+ return { ...base, action: cfnChangeReplaces(change) ? "replace" : "update", disruption: cfnChangeReplaces(change) ? "replace" : "unknown" };
85
+ default:
86
+ return cfnChangeReplaces(change)
87
+ ? { ...base, action: "replace", disruption: "replace" }
88
+ : { ...base, action: "update", disruption: "in-place" };
89
+ }
90
+ }
91
+ /**
92
+ * The changes `onReplace: "block"` refuses: those CloudFormation says replace
93
+ * their resource (`Replacement: True`). `run` and `plan` refuse on the same
94
+ * set, so a plan that passes is one `run` would not block (#3997).
95
+ */
96
+ function blockedReplacements(changes) {
97
+ return changes.filter((c) => c.replacement);
98
+ }
99
+ function isCfnPlanArtifact(value) {
100
+ const v = value;
101
+ return v?.kind === "cfn-deploy-plan" && typeof v.stack === "string" && typeof v.changesDigest === "string";
102
+ }
103
+ /**
104
+ * A digest over a change set's changes as entries, independent of the change
105
+ * set's name and of the order CloudFormation lists them in. A change set with
106
+ * nothing to apply digests as no entries.
107
+ */
108
+ export function cfnChangesDigest(stack, changeSet) {
109
+ const entries = isNoopChangeSet(changeSet) ? [] : changeSet.changes.map((c) => cfnChangeEntry(stack, c));
110
+ entries.sort((a, b) => a.address.localeCompare(b.address) || a.action.localeCompare(b.action));
111
+ return computePlanDigest("cfn-deploy-changes", { stack, entries });
112
+ }
113
+ /**
114
+ * Thrown by `run` when the change set it created proposes other changes than
115
+ * the change set its plan read (#3997): the stack, the template or the
116
+ * parameters moved between the plan and the apply. The change set is deleted
117
+ * unexecuted. `planMoved` is core's mark for a moved plan
118
+ * (`isPlanMovedError`), so the command that applied it exits 3.
119
+ */
120
+ export class CfnPlanMovedError extends Error {
121
+ constructor(stack, planned, now) {
122
+ super(`cfn-deploy "${stack}": refusing to apply. The change set proposes other changes than the plan that was approved ` +
123
+ `(planned ${planned}, now ${now}); the stack, its template or its parameters changed since. Plan it again.`);
124
+ this.stack = stack;
125
+ this.planned = planned;
126
+ this.now = now;
127
+ this.planMoved = true;
128
+ this.name = "CfnPlanMovedError";
129
+ }
130
+ }
131
+ /** The template's bytes as a digest, or `null` when it cannot be read here (the change set then reports why). */
132
+ function templateDigest(path) {
133
+ try {
134
+ return `sha256:${createHash("sha256").update(readFileSync(path)).digest("hex")}`;
135
+ }
136
+ catch {
137
+ return null;
138
+ }
139
+ }
140
+ /**
141
+ * What a `cfn-deploy` plan binds: the environment, the stack, the template's
142
+ * bytes and the parameters as resolved, and the stacks whose outputs were
143
+ * not known yet. The proposed changes are not in it; they are the member's
144
+ * entries, which the change-set document's digest binds (#4084).
145
+ */
146
+ function cfnPlanDigest(ctx, stack, input, parameters, unresolved) {
147
+ return computePlanDigest("cfn-deploy-plan", {
148
+ env: ctx.env,
149
+ stack,
150
+ template: input.template,
151
+ templateDigest: templateDigest(input.template),
152
+ parameters,
153
+ unresolved,
154
+ });
155
+ }
156
+ /**
157
+ * Plan a `cfn-deploy` step without changing the stack (#4084): create a
158
+ * change set for the template and the resolved parameters, read the changes
159
+ * it proposes, and delete it without executing it. A stack that does not
160
+ * exist yet gets a CREATE change set, so every resource reads as a create,
161
+ * and the empty `REVIEW_IN_PROGRESS` stack CloudFormation made to hold it is
162
+ * deleted too. A change set with nothing to apply (`isNoopChangeSet`) gives
163
+ * a member with no entries. A step whose parameters read outputs that are
164
+ * not known yet, from a stack the same run applies first, creates no change
165
+ * set: its member gets a hole saying whose outputs it waits on, and no
166
+ * artifact, so `run` plans it afresh.
167
+ *
168
+ * With `onReplace: "block"` (the default), a change set that replaces a
169
+ * resource fails the plan with {@link CfnReplacementBlockedError}, so the
170
+ * refusal shows in the pull request's plan rather than at apply (#3997).
171
+ * Otherwise the result carries a {@link CfnPlanArtifact} that `run` checks
172
+ * its own change set against.
173
+ *
174
+ * The plan answers the outputs the stack will have (#3999), from the
175
+ * outputs it has now (`DescribeStacks`) and the change set: an output keeps
176
+ * its value when every resource its template `Value` reads keeps its
177
+ * physical resource, which an in-place `Modify` does and an `Add`, a
178
+ * `Remove` or a replacement does not ({@link cfnPlannedOutputs}). An output
179
+ * that reads a parameter, an import or a condition is known only after
180
+ * apply. A wrong guess costs a round, never a wrong apply: a dependent whose
181
+ * input applies as another value is held back and planned again.
182
+ */
183
+ async function planCfnDeploy(executor, ctx, input) {
184
+ const stack = input.stack ?? ctx.component;
185
+ const raw = { ...(input.inputs ?? {}), ...(input.imageRef !== undefined ? { ImageRef: input.imageRef } : {}) };
186
+ const parameters = {};
187
+ const missing = [];
188
+ for (const [key, value] of Object.entries(raw)) {
189
+ if (value === undefined || value === null) {
190
+ parameters[key] = null;
191
+ missing.push(key);
192
+ }
193
+ else
194
+ parameters[key] = typeof value === "string" ? value : JSON.stringify(value);
195
+ }
196
+ const unresolved = [...(ctx.unresolvedInputs ?? [])].sort();
197
+ const planDigest = cfnPlanDigest(ctx, stack, input, parameters, unresolved);
198
+ const member = (holes) => ({
199
+ member: stack,
200
+ lexicon: "aws",
201
+ planner: "chant",
202
+ status: "planned",
203
+ planDigest,
204
+ holes,
205
+ });
206
+ if (unresolved.length > 0 || missing.length > 0) {
207
+ const reason = unresolved.length > 0
208
+ ? `inputs from ${unresolved.join(", ")}; re-checked on apply`
209
+ : `inputs ${missing.sort().join(", ")} are known only at apply; re-checked on apply`;
210
+ return {
211
+ member: stack,
212
+ planDigest,
213
+ changeSet: { member: member([{ address: stack, type: "AWS::CloudFormation::Stack", reason }]), entries: [] },
214
+ };
215
+ }
216
+ const changeSet = await executor.cloudformation.createChangeSet({
217
+ stackName: stack,
218
+ templatePath: input.template,
219
+ parameters: flattenCfnInputs(input),
220
+ });
221
+ try {
222
+ if (isNoopChangeSet(changeSet)) {
223
+ const artifact = { kind: "cfn-deploy-plan", stack, changesDigest: cfnChangesDigest(stack, changeSet) };
224
+ // Nothing to apply, so the outputs the stack has are the ones it will have (#3999).
225
+ const standing = await standingOutputs(executor, stack);
226
+ const outputs = standing ? { known: { ...standing }, unknown: [] } : undefined;
227
+ return { member: stack, planDigest, artifact, changeSet: { member: member([]), entries: [] }, ...(outputs ? { outputs } : {}) };
228
+ }
229
+ if (changeSet.status === "FAILED") {
230
+ throw new Error(`cfn-deploy "${stack}": CloudFormation could not create a change set to plan it${changeSet.statusReason ? `: ${changeSet.statusReason}` : ""}`);
231
+ }
232
+ const blocked = blockedReplacements(changeSet.changes);
233
+ if (blocked.length > 0 && (input.onReplace ?? "block") === "block")
234
+ throw new CfnReplacementBlockedError(stack, blocked);
235
+ const entries = changeSet.changes.map((c) => cfnChangeEntry(stack, c));
236
+ const artifact = { kind: "cfn-deploy-plan", stack, changesDigest: cfnChangesDigest(stack, changeSet) };
237
+ const outputs = changeSet.stackCreated ? undefined : await plannedStackOutputs(executor, stack, input.template, changeSet.changes);
238
+ return { member: stack, planDigest, artifact, changeSet: { member: member([]), entries }, ...(outputs ? { outputs } : {}) };
239
+ }
240
+ finally {
241
+ await cleanUpPlanChangeSet(executor, changeSet);
242
+ }
243
+ }
244
+ /**
245
+ * Delete a plan's change set, and the empty stack a CREATE change set made
246
+ * when no stack existed before. A failure to clean up does not fail the
247
+ * plan: the change set holds nothing that applies, and the next CREATE
248
+ * change set reuses an empty stack left behind.
249
+ */
250
+ async function cleanUpPlanChangeSet(executor, changeSet) {
251
+ try {
252
+ await executor.cloudformation.deleteChangeSet({ stackName: changeSet.stackName, changeSetName: changeSet.changeSetName });
253
+ }
254
+ catch (err) {
255
+ console.error(`cfn-deploy plan "${changeSet.stackName}": could not delete change set ${changeSet.changeSetName}: ${err instanceof Error ? err.message : String(err)}`);
256
+ }
257
+ if (changeSet.stackCreated && executor.cloudformation.deleteStackShell) {
258
+ try {
259
+ await executor.cloudformation.deleteStackShell(changeSet.stackName);
260
+ }
261
+ catch (err) {
262
+ console.error(`cfn-deploy plan "${changeSet.stackName}": could not delete the empty stack its CREATE change set made: ${err instanceof Error ? err.message : String(err)}`);
263
+ }
264
+ }
265
+ }
266
+ /** The stack's outputs as they stand, or `undefined` when they cannot be read. */
267
+ async function standingOutputs(executor, stack) {
268
+ try {
269
+ return { ...(await executor.cloudformation.describeStack(stack)).outputs };
270
+ }
271
+ catch {
272
+ return undefined;
273
+ }
274
+ }
275
+ /**
276
+ * What the plan says of the stack's outputs once `changes` apply: none to
277
+ * say for a template with no `Outputs`, which needs no `DescribeStacks`.
278
+ */
279
+ async function plannedStackOutputs(executor, stack, templatePath, changes) {
280
+ const template = readTemplate(templatePath);
281
+ if (!template || typeof template !== "object")
282
+ return undefined;
283
+ if (Object.keys(template.Outputs ?? {}).length === 0)
284
+ return { known: {}, unknown: [] };
285
+ return cfnPlannedOutputs(template, changes, await standingOutputs(executor, stack));
286
+ }
287
+ /** The template at `path` as JSON, or `undefined` when it cannot be read or parsed here. */
288
+ function readTemplate(path) {
289
+ try {
290
+ return JSON.parse(readFileSync(path, "utf8"));
291
+ }
292
+ catch {
293
+ return undefined;
294
+ }
295
+ }
296
+ /**
297
+ * What a template's `Value` reads (#3999): the logical ids it names through
298
+ * `Ref`, `Fn::GetAtt` and `Fn::Sub`, and whether it reads anything this plan
299
+ * cannot follow (`Fn::ImportValue`, a condition's `Fn::If`, or an intrinsic
300
+ * it does not know).
301
+ */
302
+ function valueReads(value) {
303
+ const ids = new Set();
304
+ let opaque = false;
305
+ const sub = (text) => {
306
+ for (const m of text.matchAll(/\$\{([^}!][^}]*)\}/g))
307
+ ids.add(m[1].split(".")[0]);
308
+ };
309
+ const walk = (v) => {
310
+ if (Array.isArray(v))
311
+ return v.forEach(walk);
312
+ if (v === null || typeof v !== "object")
313
+ return;
314
+ const entries = Object.entries(v);
315
+ if (entries.length === 1) {
316
+ const [key, arg] = entries[0];
317
+ if (key === "Ref") {
318
+ if (typeof arg === "string")
319
+ ids.add(arg);
320
+ else
321
+ opaque = true;
322
+ return;
323
+ }
324
+ if (key === "Fn::GetAtt") {
325
+ if (Array.isArray(arg) && typeof arg[0] === "string")
326
+ ids.add(arg[0]);
327
+ else if (typeof arg === "string")
328
+ ids.add(arg.split(".")[0]);
329
+ else
330
+ opaque = true;
331
+ return;
332
+ }
333
+ if (key === "Fn::Sub") {
334
+ if (typeof arg === "string")
335
+ sub(arg);
336
+ else if (Array.isArray(arg) && typeof arg[0] === "string") {
337
+ const vars = (arg[1] ?? {});
338
+ for (const m of arg[0].matchAll(/\$\{([^}!][^}]*)\}/g))
339
+ if (!(m[1] in vars))
340
+ ids.add(m[1].split(".")[0]);
341
+ walk(vars);
342
+ }
343
+ else
344
+ opaque = true;
345
+ return;
346
+ }
347
+ if (key === "Fn::Join" || key === "Fn::Select" || key === "Fn::Split" || key === "Fn::Base64")
348
+ return walk(arg);
349
+ if (key.startsWith("Fn::") || key === "Condition") {
350
+ opaque = true;
351
+ return;
352
+ }
353
+ }
354
+ entries.forEach(([, x]) => walk(x));
355
+ };
356
+ walk(value);
357
+ return { ids, opaque };
358
+ }
359
+ /**
360
+ * The outputs a stack will have once `changes` apply (#3999), from its
361
+ * template and the outputs it has now. An output is known, at the value it
362
+ * has now, when its `Value` reads only pseudo parameters and resources whose
363
+ * physical resource the change set keeps (no `Add`, `Remove`, `Import` or
364
+ * `Dynamic`, no replacement, no change in a nested stack under it). One
365
+ * that reads a parameter, an import or a condition, one the stack does not
366
+ * have yet, and every output of a template this cannot read, is unknown.
367
+ * `undefined` when there is no template or no standing stack to read from.
368
+ */
369
+ export function cfnPlannedOutputs(template, changes, standing) {
370
+ if (!standing || template === null || typeof template !== "object")
371
+ return undefined;
372
+ const t = template;
373
+ const parameters = new Set(Object.keys(t.Parameters ?? {}));
374
+ const moved = new Set();
375
+ for (const c of changes) {
376
+ const id = c.nestedStack?.[0] ?? c.logicalResourceId;
377
+ const keeps = !c.nestedStack && c.action === "Modify" && !c.replacement && c.replacementMode !== "True" && c.replacementMode !== "Conditional";
378
+ if (!keeps)
379
+ moved.add(id);
380
+ }
381
+ const known = {};
382
+ const unknown = [];
383
+ for (const [name, output] of Object.entries(t.Outputs ?? {}).sort(([a], [b]) => a.localeCompare(b))) {
384
+ const { ids, opaque } = valueReads(output?.Value);
385
+ const stays = !opaque && output?.Condition === undefined && name in standing &&
386
+ [...ids].every((id) => id.startsWith("AWS::") || (!parameters.has(id) && !moved.has(id)));
387
+ if (stays)
388
+ known[name] = standing[name];
389
+ else
390
+ unknown.push(name);
391
+ }
392
+ return { known, unknown };
393
+ }
394
+ /** Whether a CloudFormation error says the stack does not exist. */
395
+ const STACK_MISSING = /does not exist/i;
396
+ /**
397
+ * Thrown when a changeset proposes a resource replacement and `onReplace` is
398
+ * `"block"` (the default) — refusing to apply rather than silently destroying
399
+ * and recreating a resource, which for a stateful resource (a DynamoDB table,
400
+ * an RDS instance) means data loss. Carries the specific resources CloudFormation
401
+ * proposed replacing, so the caller/human reviewing the changeset knows exactly
402
+ * what was refused.
403
+ */
404
+ export class CfnReplacementBlockedError extends Error {
405
+ constructor(stack, replacements) {
406
+ super(`cfn-deploy "${stack}": refusing changeset — it would replace ${replacements.length} resource(s) ` +
407
+ `(${replacements.map((r) => r.logicalResourceId).join(", ")}) and onReplace is "block". ` +
408
+ `Re-run with onReplace: "allow" or "snapshot-first" to proceed.`);
409
+ this.stack = stack;
410
+ this.replacements = replacements;
411
+ this.name = "CfnReplacementBlockedError";
412
+ }
413
+ }
414
+ /**
415
+ * Deploy a CloudFormation stack: create a changeset, apply the declarative
416
+ * safety policy against its proposed changes, then execute (or refuse) it and
417
+ * wait for the stack to reach a terminal status.
418
+ *
419
+ * - `onReplace: "block"` (default) — `CfnReplacementBlockedError` if any
420
+ * change requires replacement; the changeset is left/deleted unexecuted.
421
+ * - `onReplace: "allow"` — executes regardless of replacement.
422
+ * - `onReplace: "snapshot-first"` — takes a `snapshot-before`-style capture
423
+ * (via `executor.cloudformation`'s DynamoDB/RDS-aware snapshot, when the
424
+ * replaced resource is a stateful type) before executing.
425
+ * - `stageGsi` records intent only in this phase (the real add→backfill→remove
426
+ * staging is DynamoDB-specific choreography layered on top of the plain
427
+ * changeset apply; Phase 1 surfaces the option and passes it through
428
+ * uninterpreted rather than half-implementing GSI staging, since staging
429
+ * requires a second follow-up deploy the single-step `cfn-deploy` capability
430
+ * does not orchestrate on its own).
431
+ *
432
+ * Rollback: trigger CloudFormation's native `rollback-stack` — the stack's own
433
+ * automatic-rollback mechanism restores the last known-good state.
434
+ */
435
+ export function createCfnDeployCapability(executor = defaultCloudExecutor()) {
436
+ return {
437
+ kind: "cfn-deploy",
438
+ plan(ctx, input) {
439
+ return planCfnDeploy(executor, ctx, input);
440
+ },
441
+ async outputs(ctx, input) {
442
+ // The outputs the stack has now, for a dependent planned before it
443
+ // applies (#3183). A stack that does not exist yet has none.
444
+ try {
445
+ return (await executor.cloudformation.describeStack(input.stack ?? ctx.component)).outputs;
446
+ }
447
+ catch (err) {
448
+ if (STACK_MISSING.test(err instanceof Error ? err.message : String(err)))
449
+ return {};
450
+ throw err;
451
+ }
452
+ },
453
+ async run(ctx, input) {
454
+ const stack = input.stack ?? ctx.component;
455
+ const onReplace = input.onReplace ?? "block";
456
+ const changeSet = await executor.cloudformation.createChangeSet({
457
+ stackName: stack,
458
+ templatePath: input.template,
459
+ parameters: flattenCfnInputs(input),
460
+ });
461
+ // Handed the plan the approver approved (#3997), apply only a change
462
+ // set that proposes the same changes. Anything else means the stack,
463
+ // the template or the parameters moved since the plan.
464
+ const planned = ctx.plans?.[stack];
465
+ if (isCfnPlanArtifact(planned)) {
466
+ const now = cfnChangesDigest(stack, changeSet);
467
+ if (now !== planned.changesDigest) {
468
+ await cleanUpPlanChangeSet(executor, changeSet);
469
+ throw new CfnPlanMovedError(stack, planned.changesDigest, now);
470
+ }
471
+ }
472
+ // An unchanged stack yields a change set with nothing to apply.
473
+ // `execute-change-set` rejects it ("The submitted information didn't
474
+ // contain changes"), which would fail this component and stop the whole
475
+ // run — so a re-run of `--components all` dies on the first already-current
476
+ // stack. Treat it as an idempotent no-op success instead: delete the empty
477
+ // change set and report the stack's current status/outputs so downstream
478
+ // steps still get real outputs and the run proceeds (#960).
479
+ if (isNoopChangeSet(changeSet)) {
480
+ await executor.cloudformation.deleteChangeSet({
481
+ stackName: stack,
482
+ changeSetName: changeSet.changeSetName,
483
+ });
484
+ const { stackStatus, outputs } = await executor.cloudformation.describeStack(stack);
485
+ return { stackStatus, outputs };
486
+ }
487
+ const replacements = blockedReplacements(changeSet.changes);
488
+ let snapshotId;
489
+ if (replacements.length > 0 && onReplace === "block") {
490
+ await executor.cloudformation.deleteChangeSet({
491
+ stackName: stack,
492
+ changeSetName: changeSet.changeSetName,
493
+ });
494
+ throw new CfnReplacementBlockedError(stack, replacements);
495
+ }
496
+ if (replacements.length > 0 && onReplace === "snapshot-first") {
497
+ // Phase 1: record which resources were replaced so the caller/audit
498
+ // trail has the fact captured; a dedicated `snapshot-before` capability
499
+ // handles resource-specific (DynamoDB/RDS/OpenSearch) capture and is
500
+ // composed ahead of `cfn-deploy` in the component's own phase list
501
+ // when the sticky resource needs a real point-in-time backup.
502
+ snapshotId = `pending-snapshot:${stack}:${replacements.map((r) => r.logicalResourceId).join(",")}`;
503
+ }
504
+ await executor.cloudformation.executeChangeSet({
505
+ stackName: stack,
506
+ changeSetName: changeSet.changeSetName,
507
+ });
508
+ const { stackStatus, outputs } = await executor.cloudformation.waitForStack(stack);
509
+ // `waitForStack` returns on any terminal (`*_COMPLETE`/`*_FAILED`) status,
510
+ // including the failure ones: a create that fails rolls back to
511
+ // `ROLLBACK_COMPLETE`, an update to `UPDATE_ROLLBACK_COMPLETE`, and hard
512
+ // failures end in `*_FAILED`. Treating those as success would report a
513
+ // failed deploy as green (and hand downstream steps an empty `outputs`),
514
+ // so throw — the same fail-closed contract the rest of the release model
515
+ // relies on.
516
+ // A missing status is fail-closed too: Floci's describe-stacks can omit
517
+ // StackStatus mid-rollback, and `undefined.includes` would throw a TypeError
518
+ // that masks the real deploy failure (#947).
519
+ if (!stackStatus || stackStatus.includes("ROLLBACK") || stackStatus.endsWith("_FAILED")) {
520
+ throw new Error(`cfn-deploy "${stack}": stack reached ${stackStatus ?? "an indeterminate status"} — the deploy failed and was rolled back. Inspect the stack events for the resource that failed to create/update.`);
521
+ }
522
+ return { stackStatus, outputs, ...(snapshotId ? { snapshotId } : {}) };
523
+ },
524
+ async rollback(ctx, input) {
525
+ const stack = input.stack ?? ctx.component;
526
+ try {
527
+ await executor.cloudformation.rollbackStack(stack);
528
+ }
529
+ catch (err) {
530
+ const message = err instanceof Error ? err.message : String(err);
531
+ // Local emulators (Floci) don't implement RollbackStack → `UnknownAction`.
532
+ // The stack is already in a terminal failed state; degrade to a clear
533
+ // message instead of crashing the compensation phase (#947).
534
+ if (/UnknownAction|not supported/i.test(message)) {
535
+ console.error(`cfn-deploy rollback "${stack}": the target doesn't support RollbackStack (a local emulator such as Floci) — skipping automated rollback. Original: ${message}`);
536
+ return;
537
+ }
538
+ throw err;
539
+ }
540
+ },
541
+ };
542
+ }
543
+ /** Flatten the wired `inputs` map plus `imageRef` (already resolved by the driver) to plain string CloudFormation parameters. */
544
+ function flattenCfnInputs(input) {
545
+ const params = {};
546
+ for (const [key, value] of Object.entries(input.inputs ?? {})) {
547
+ params[key] = typeof value === "string" ? value : JSON.stringify(value);
548
+ }
549
+ if (input.imageRef)
550
+ params.ImageRef = input.imageRef;
551
+ return Object.keys(params).length > 0 ? params : undefined;
552
+ }
553
+ /** Default `cfn-deploy` capability, backed by the real `CloudExecutor`. */
554
+ export const cfnDeployCapability = createCfnDeployCapability();
555
+ /**
556
+ * Roll a new task definition/image out to an ECS service via `UpdateService`.
557
+ * Before the update, `run` reads the service with `describe-services` and
558
+ * records the task definition it was running in its output. The rollback sends
559
+ * that previous task definition back (and the previous desired count, when the
560
+ * step changed it). The step's own `imageRef` is never the rollback target:
561
+ * it is the revision the step just rolled out, so re-sending it restores
562
+ * nothing (#2609). When the previous task definition could not be read, the
563
+ * rollback fails with a message naming the service rather than report a
564
+ * restore that changed nothing (#2605). A component that needs a specific
565
+ * task definition restored can still give itself an explicit rollback phase,
566
+ * such as `rollback-previous` with that `taskDefinition`.
567
+ */
568
+ export function createEcsUpdateServiceCapability(executor = defaultCloudExecutor()) {
569
+ return {
570
+ kind: "ecs-update-service",
571
+ async run(_ctx, input) {
572
+ // A failed read only costs the rollback its target; the forward update
573
+ // still runs, and the rollback then fails saying it has nothing to restore.
574
+ const before = await executor.ecs.describeService(input.cluster, input.service).catch(() => undefined);
575
+ const { deploymentId } = await executor.ecs.updateService({
576
+ cluster: input.cluster,
577
+ service: input.service,
578
+ taskDefinition: input.imageRef,
579
+ desiredCount: input.desiredCount,
580
+ forceNewDeployment: input.forceNewDeployment,
581
+ });
582
+ return {
583
+ deploymentId,
584
+ ...(before?.taskDefinition ? { previousTaskDefinition: before.taskDefinition } : {}),
585
+ ...(before && input.desiredCount !== undefined ? { previousDesiredCount: before.desiredCount } : {}),
586
+ };
587
+ },
588
+ async rollback(_ctx, input, output) {
589
+ const previous = output?.previousTaskDefinition;
590
+ if (!previous) {
591
+ throw new Error(`ecs-update-service rollback: the task definition service "${input.service}" ran before the step ` +
592
+ `was not recorded, so there is nothing to roll back to; ` +
593
+ `give the component a rollback phase that names the taskDefinition`);
594
+ }
595
+ await executor.ecs.rollbackService({
596
+ cluster: input.cluster,
597
+ service: input.service,
598
+ taskDefinition: previous,
599
+ desiredCount: output?.previousDesiredCount,
600
+ });
601
+ },
602
+ };
603
+ }
604
+ /** Default `ecs-update-service` capability, backed by the real `CloudExecutor`. */
605
+ export const ecsUpdateServiceCapability = createEcsUpdateServiceCapability();
606
+ /**
607
+ * Update a Lambda function's code to a new container image, wait for the
608
+ * update to apply, and (by default) publish an immutable version and repoint
609
+ * `alias` at it — the same digest-promotion invariant every other apply verb
610
+ * follows (`imageRef`/`codeRef` is a resolved `publish-image` digest, never a
611
+ * rebuild). Rollback restores whatever version `alias` pointed at before this
612
+ * step ran (captured up front), repointing the alias back — mirroring
613
+ * `ecs-update-service`'s best-effort re-apply style rather than a native
614
+ * automatic rollback (Lambda has none for code updates).
615
+ */
616
+ export function createLambdaDeployCapability(executor = defaultCloudExecutor()) {
617
+ const previousVersionByTarget = new Map();
618
+ return {
619
+ kind: "lambda-deploy",
620
+ async run(_ctx, input) {
621
+ const alias = input.alias ?? "live";
622
+ if (!previousVersionByTarget.has(input.functionName)) {
623
+ previousVersionByTarget.set(input.functionName, await executor.lambda.getAliasVersion(input.functionName, alias));
624
+ }
625
+ const { functionArn } = await executor.lambda.updateFunctionCode({
626
+ functionName: input.functionName,
627
+ imageUri: input.codeRef,
628
+ });
629
+ const { status } = await executor.lambda.waitForUpdate(input.functionName);
630
+ if (status !== "Successful") {
631
+ throw new Error(`lambda-deploy "${input.functionName}": code update ended "${status}"`);
632
+ }
633
+ if (input.publish === false) {
634
+ return { version: "$LATEST", functionArn };
635
+ }
636
+ const published = await executor.lambda.publishVersion({ functionName: input.functionName });
637
+ await executor.lambda.updateAlias({ functionName: input.functionName, alias, version: published.version });
638
+ return { version: published.version, functionArn: published.functionArn };
639
+ },
640
+ async rollback(_ctx, input) {
641
+ const alias = input.alias ?? "live";
642
+ const previousVersion = previousVersionByTarget.get(input.functionName);
643
+ if (!previousVersion)
644
+ return; // no prior alias version recorded — nothing to restore.
645
+ await executor.lambda.updateAlias({ functionName: input.functionName, alias, version: previousVersion });
646
+ },
647
+ };
648
+ }
649
+ /** Default `lambda-deploy` capability, backed by the real `CloudExecutor`. */
650
+ export const lambdaDeployCapability = createLambdaDeployCapability();
651
+ /** Sync a directory of static assets to an S3 bucket via `aws s3 sync` (endpoint-aware through the `CloudExecutor`). */
652
+ export function createS3SyncCapability(executor = defaultCloudExecutor()) {
653
+ return {
654
+ kind: "s3-sync",
655
+ rollbackPolicy: "needs-opt-out",
656
+ async run(_ctx, input) {
657
+ return executor.s3.sync({ from: input.from, to: input.to, delete: input.delete });
658
+ },
659
+ };
660
+ }
661
+ /** Default `s3-sync` capability, backed by the real `CloudExecutor`. */
662
+ export const s3SyncCapability = createS3SyncCapability();
663
+ /** Invalidate CDN cache paths after a content update (e.g. following `s3-sync`), via `aws cloudfront create-invalidation`. */
664
+ export function createCdnInvalidateCapability(executor = defaultCloudExecutor()) {
665
+ return {
666
+ kind: "cdn-invalidate",
667
+ rollbackPolicy: "needs-opt-out",
668
+ async run(_ctx, input) {
669
+ return executor.cloudfront.createInvalidation({
670
+ distributionId: input.distributionId,
671
+ paths: input.paths ?? ["/*"],
672
+ });
673
+ },
674
+ };
675
+ }
676
+ /** Default `cdn-invalidate` capability, backed by the real `CloudExecutor`. */
677
+ export const cdnInvalidateCapability = createCdnInvalidateCapability();
678
+ /**
679
+ * A runner that reports its outcome does so as a trailing JSON object
680
+ * `{"applied":bool,"version":"..."}` — on stdout (host) or in the Lambda
681
+ * response payload. Parse the last such line; when the runner emits nothing
682
+ * parseable, fall back to `applied` = "the process exited cleanly" and an empty
683
+ * version (an ECS task exposes only its exit code — no captured stdout — so it
684
+ * always takes this fallback).
685
+ */
686
+ function parseMigrationReport(text, appliedFallback) {
687
+ for (const line of text.split("\n").map((l) => l.trim()).reverse()) {
688
+ if (!line.startsWith("{"))
689
+ continue;
690
+ try {
691
+ const parsed = JSON.parse(line);
692
+ if (typeof parsed.applied === "boolean" || typeof parsed.version === "string") {
693
+ return { applied: parsed.applied ?? appliedFallback, version: parsed.version ?? "" };
694
+ }
695
+ }
696
+ catch {
697
+ // not the report line — keep scanning older lines.
698
+ }
699
+ }
700
+ return { applied: appliedFallback, version: "" };
701
+ }
702
+ /**
703
+ * Run a database/schema migration against a target as a deploy step, dispatching
704
+ * on the target transport (ECS one-off task, Lambda invoke, or SSM host command)
705
+ * through the injectable `CloudExecutor`. A non-clean outcome (non-zero exit, a
706
+ * Lambda `FunctionError`) throws so the phase fails rather than proceeding on an
707
+ * unmigrated schema.
708
+ */
709
+ export function createRunMigrationCapability(executor = defaultCloudExecutor()) {
710
+ return {
711
+ kind: "run-migration",
712
+ rollbackPolicy: "needs-opt-out",
713
+ async run(_ctx, input) {
714
+ const target = input.target;
715
+ switch (target.via) {
716
+ case "ecs-task": {
717
+ const { taskArn } = await executor.ecs.runTask({
718
+ cluster: target.cluster,
719
+ taskDefinition: target.taskDefinition,
720
+ container: target.container,
721
+ command: target.command,
722
+ launchType: target.launchType,
723
+ subnets: target.subnets,
724
+ securityGroups: target.securityGroups,
725
+ assignPublicIp: target.assignPublicIp,
726
+ });
727
+ const result = await executor.ecs.waitForTask(target.cluster, taskArn);
728
+ if (result.exitCode !== 0) {
729
+ throw new Error(`run-migration (ecs-task ${target.cluster}): task ${result.lastStatus} with exit ${result.exitCode ?? "none"}${result.stoppedReason ? ` (${result.stoppedReason})` : ""}`);
730
+ }
731
+ return { applied: true, version: "" };
732
+ }
733
+ case "lambda": {
734
+ const res = await executor.lambda.invoke({ functionName: target.function, payload: target.payload });
735
+ if (res.functionError) {
736
+ throw new Error(`run-migration (lambda ${target.function}): ${res.functionError} — ${res.payload.trim()}`);
737
+ }
738
+ return parseMigrationReport(res.payload, true);
739
+ }
740
+ case "host": {
741
+ const { stdout, exitCode } = await executor.host.exec({ host: target.host, command: target.command, cwd: target.cwd });
742
+ if (exitCode !== 0) {
743
+ throw new Error(`run-migration (host ${target.host}): command exited ${exitCode}`);
744
+ }
745
+ return parseMigrationReport(stdout, true);
746
+ }
747
+ }
748
+ },
749
+ };
750
+ }
751
+ /** Default `run-migration` capability, backed by the real `CloudExecutor`. */
752
+ export const runMigrationCapability = createRunMigrationCapability();