@fjall/deploy-core 2.30.3 → 2.31.1

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 (64) hide show
  1. package/dist/.minified +1 -1
  2. package/dist/src/aws/organisations/oidcProvider.js +1 -1
  3. package/dist/src/aws/utils/cloudformationEventHelpers.d.ts +2 -2
  4. package/dist/src/aws/utils/cloudformationEventHelpers.js +1 -1
  5. package/dist/src/index.d.ts +2 -2
  6. package/dist/src/index.js +1 -1
  7. package/dist/src/orchestration/activeDeploymentGuard.d.ts +1 -1
  8. package/dist/src/orchestration/activeDeploymentGuard.js +3 -3
  9. package/dist/src/orchestration/application/applicationDeploy.js +1 -1
  10. package/dist/src/orchestration/application/applicationDeployHelpers.d.ts +2 -1
  11. package/dist/src/orchestration/application/applicationDeployHelpers.js +3 -3
  12. package/dist/src/orchestration/application/applicationDestroy.js +1 -1
  13. package/dist/src/orchestration/application/artefactCollection.d.ts +3 -2
  14. package/dist/src/orchestration/application/artefactCollection.js +1 -1
  15. package/dist/src/orchestration/application/codeOnlyDeploy.d.ts +0 -22
  16. package/dist/src/orchestration/application/codeOnlyDeploy.js +1 -1
  17. package/dist/src/orchestration/application/databaseEndpointReconcile.d.ts +2 -2
  18. package/dist/src/orchestration/application/databaseEndpointReconcile.js +1 -1
  19. package/dist/src/orchestration/application/destroyPreFlight.d.ts +33 -0
  20. package/dist/src/orchestration/application/destroyPreFlight.js +1 -0
  21. package/dist/src/orchestration/application/detectionPipeline.d.ts +1 -1
  22. package/dist/src/orchestration/application/detectionPipeline.js +1 -1
  23. package/dist/src/orchestration/application/dockerBuildHelper.js +1 -1
  24. package/dist/src/orchestration/application/lambdaCodeOnlyRollout.d.ts +42 -10
  25. package/dist/src/orchestration/application/lambdaCodeOnlyRollout.js +1 -1
  26. package/dist/src/orchestration/application/plan/computeDeployPlan.d.ts +1 -1
  27. package/dist/src/orchestration/application/plan/computeDeployPlan.js +1 -1
  28. package/dist/src/orchestration/application/serviceImageTagsRollback.d.ts +1 -1
  29. package/dist/src/orchestration/application/serviceImageTagsRollback.js +1 -1
  30. package/dist/src/orchestration/application/taskDefinitionRoll.d.ts +1 -1
  31. package/dist/src/orchestration/application/taskDefinitionRoll.js +1 -1
  32. package/dist/src/orchestration/destroy.js +1 -1
  33. package/dist/src/orchestration/drift/driftPreFlight.js +3 -3
  34. package/dist/src/orchestration/index.d.ts +1 -1
  35. package/dist/src/orchestration/index.js +1 -1
  36. package/dist/src/orchestration/organisation/cascadeHelpers.js +1 -1
  37. package/dist/src/orchestration/organisationDeploy/infraSteps.d.ts +1 -1
  38. package/dist/src/orchestration/organisationDeploy/infraSteps.js +1 -1
  39. package/dist/src/orchestration/organisationDeploy/orgCascadeDeploy.js +4 -4
  40. package/dist/src/orchestration/organisationDeploy/singleComponentDeploy.js +1 -1
  41. package/dist/src/orchestration/probes/deleteBlockProbes.d.ts +38 -0
  42. package/dist/src/orchestration/probes/deleteBlockProbes.js +1 -0
  43. package/dist/src/orchestration/remediation/recreatePreFlight.js +1 -1
  44. package/dist/src/orchestration/remediation/recreateResource.js +1 -1
  45. package/dist/src/orchestration/remediation/removalUpdate.d.ts +74 -13
  46. package/dist/src/orchestration/remediation/removalUpdate.js +1 -1
  47. package/dist/src/orchestration/restart/restartApplication.js +1 -1
  48. package/dist/src/orchestration/restart/secretsDrift.js +1 -1
  49. package/dist/src/orchestration/stackCleanup/stackResources.d.ts +5 -3
  50. package/dist/src/services/application/ApplicationStackService.d.ts +2 -1
  51. package/dist/src/services/application/ApplicationStackService.js +1 -1
  52. package/dist/src/services/infrastructure/CloudFormationService.d.ts +11 -10
  53. package/dist/src/services/infrastructure/CloudFormationService.js +1 -1
  54. package/dist/src/services/infrastructure/EcsService.d.ts +11 -9
  55. package/dist/src/services/infrastructure/EcsService.js +1 -1
  56. package/dist/src/services/infrastructure/EcsServiceResolver.d.ts +4 -4
  57. package/dist/src/services/infrastructure/EcsServiceResolver.js +1 -1
  58. package/dist/src/services/infrastructure/LambdaService.d.ts +19 -2
  59. package/dist/src/services/infrastructure/LambdaService.js +1 -1
  60. package/dist/src/types/application/ApplicationServiceTypes.d.ts +1 -0
  61. package/dist/src/types/application/ApplicationServiceTypes.js +1 -1
  62. package/dist/src/types/remediation.d.ts +1 -0
  63. package/dist/src/types/remediation.js +1 -1
  64. package/package.json +5 -4
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 216 files minified at 2026-07-16T01:01:46.559Z
1
+ 218 files minified at 2026-07-16T20:42:25.536Z
@@ -1 +1 @@
1
- import{ListOpenIDConnectProvidersCommand as l,ListRolesCommand as D,CreateOpenIDConnectProviderCommand as O,DeleteOpenIDConnectProviderCommand as w}from"@aws-sdk/client-iam";import{FJALL_OIDC_AUDIENCE as g,FJALL_OIDC_ISSUER_DOMAIN as f,FJALL_OIDC_PLACEHOLDER_THUMBPRINT as y,success as i,failure as v}from"@fjall/generator";import{maskSensitiveOutput as m,getErrorMessage as I}from"@fjall/util";import{logger as s}from"@fjall/util/logger";import{composeSdkAbortSignal as a,isAborted as c}from"./types.js";const C=`:oidc-provider/${f}`;async function A(d,r){try{if(c(r))return i({deleted:!1,reason:"aborted"});const e=((await d.send(new l({}),{abortSignal:a(r)})).OpenIDConnectProviderList??[]).map(o=>o.Arn).find(o=>typeof o=="string"&&o.endsWith(C));if(e===void 0)return i({deleted:!1,reason:"provider not present"});let t;do{if(c(r))return i({deleted:!1,reason:"aborted"});const o=await d.send(new D({Marker:t}),{abortSignal:a(r)});for(const p of o.Roles??[]){const u=p.AssumeRolePolicyDocument;if(typeof u=="string"&&decodeURIComponent(u).includes(e))return i({deleted:!1,reason:`still referenced by role ${p.RoleName??"(unknown)"}`})}t=o.IsTruncated===!0?o.Marker:void 0}while(t!==void 0);return await d.send(new w({OpenIDConnectProviderArn:e}),{abortSignal:a(r)}),i({deleted:!0,reason:"deleted orphaned provider"})}catch(n){return n instanceof Error&&n.name==="NoSuchEntityException"?i({deleted:!1,reason:"provider not present"}):v(new Error(`Failed to evaluate OIDC provider teardown: ${I(n)}`))}}async function h(d,r){try{if(c(r))return i({status:"aborted"});const e=((await d.send(new l({}),{abortSignal:a(r)})).OpenIDConnectProviderList??[]).map(o=>o.Arn).find(o=>typeof o=="string"&&o.endsWith(C));if(e!==void 0)return i({status:"present",providerArn:e});const t=await d.send(new O({Url:`https://${f}`,ClientIDList:[g],ThumbprintList:[y]}),{abortSignal:a(r)});return i({status:"recreated",...t.OpenIDConnectProviderArn!==void 0&&{providerArn:t.OpenIDConnectProviderArn}})}catch(n){return n instanceof Error&&n.name==="EntityAlreadyExistsException"?i({status:"present"}):v(new Error(`Failed to ensure OIDC provider presence: ${I(n)}`))}}async function F(d,r,n){const e=await h(d,n);if(!e.success){const t=m(e.error.message);s.debug("oidcReconcile","OIDC provider ensure probe failed",{error:t}),r.onLog?.(`Could not verify the Fjall OIDC provider after deploy: ${t}. If scans or deploys later fail with InvalidIdentityToken, re-run this deploy or reconnect the account.`,"warn");return}if(e.data.status==="recreated"){s.info("oidcReconcile","Recreated missing account-global OIDC provider",{providerArn:e.data.providerArn}),r.onLog?.("The Fjall OIDC provider was missing after the stack deploy and has been restored","warn");return}s.debug("oidcReconcile","OIDC provider verified after deploy",{status:e.data.status})}async function _(d,r,n){const e=await A(d,n);if(!e.success){const t=m(e.error.message);s.debug("oidcTeardown","OIDC provider teardown probe failed",{error:t}),r.onLog?.(`OIDC provider cleanup skipped: ${t}`,"warn");return}if(e.data.deleted){s.info("oidcTeardown","Deleted orphaned account-global OIDC provider"),r.onLog?.("Removed the orphaned Fjall OIDC provider","info");return}s.debug("oidcTeardown","OIDC provider retained",{reason:e.data.reason})}export{_ as cleanupOrphanedOidcProvider,A as deleteOidcProviderIfUnreferenced,h as ensureOidcProviderPresent,F as reconcileOidcProviderAfterDeploy};
1
+ import{ListOpenIDConnectProvidersCommand as l,ListRolesCommand as D,CreateOpenIDConnectProviderCommand as O,DeleteOpenIDConnectProviderCommand as w}from"@aws-sdk/client-iam";import{FJALL_OIDC_AUDIENCE as y,FJALL_OIDC_ISSUER_DOMAIN as f,FJALL_OIDC_PLACEHOLDER_THUMBPRINT as A,success as d,failure as v}from"@fjall/generator";import{maskSensitiveOutput as m,getErrorMessage as I}from"@fjall/util";import{logger as s}from"@fjall/util/logger";import{composeSdkAbortSignal as a,isAborted as c}from"./types.js";const C=`:oidc-provider/${f}`;async function g(i,e){try{if(c(e))return d({deleted:!1,reason:"aborted"});const r=((await i.send(new l({}),{abortSignal:a(e)})).OpenIDConnectProviderList??[]).map(o=>o.Arn).find(o=>typeof o=="string"&&o.endsWith(C));if(r===void 0)return d({deleted:!1,reason:"provider not present"});let t;do{if(c(e))return d({deleted:!1,reason:"aborted"});const o=await i.send(new D({Marker:t}),{abortSignal:a(e)});for(const p of o.Roles??[]){const u=p.AssumeRolePolicyDocument;if(typeof u=="string"&&decodeURIComponent(u).includes(r))return d({deleted:!1,reason:`still referenced by role ${p.RoleName??"(unknown)"}`})}t=o.IsTruncated===!0?o.Marker:void 0}while(t!==void 0);return await i.send(new w({OpenIDConnectProviderArn:r}),{abortSignal:a(e)}),d({deleted:!0,reason:"deleted orphaned provider"})}catch(n){return c(e)?d({deleted:!1,reason:"aborted"}):n instanceof Error&&n.name==="NoSuchEntityException"?d({deleted:!1,reason:"provider not present"}):v(new Error(`Failed to evaluate OIDC provider teardown: ${I(n)}`))}}async function h(i,e){try{if(c(e))return d({status:"aborted"});const r=((await i.send(new l({}),{abortSignal:a(e)})).OpenIDConnectProviderList??[]).map(o=>o.Arn).find(o=>typeof o=="string"&&o.endsWith(C));if(r!==void 0)return d({status:"present",providerArn:r});const t=await i.send(new O({Url:`https://${f}`,ClientIDList:[y],ThumbprintList:[A]}),{abortSignal:a(e)});return d({status:"recreated",...t.OpenIDConnectProviderArn!==void 0&&{providerArn:t.OpenIDConnectProviderArn}})}catch(n){return c(e)?d({status:"aborted"}):n instanceof Error&&n.name==="EntityAlreadyExistsException"?d({status:"present"}):v(new Error(`Failed to ensure OIDC provider presence: ${I(n)}`))}}async function F(i,e,n){const r=await h(i,n);if(!r.success){const t=m(r.error.message);s.debug("oidcReconcile","OIDC provider ensure probe failed",{error:t}),e.onLog?.(`Could not verify the Fjall OIDC provider after deploy: ${t}. If scans or deploys later fail with InvalidIdentityToken, re-run this deploy or reconnect the account.`,"warn");return}if(r.data.status==="recreated"){s.info("oidcReconcile","Recreated missing account-global OIDC provider",{providerArn:r.data.providerArn}),e.onLog?.("The Fjall OIDC provider was missing after the stack deploy and has been restored","warn");return}s.debug("oidcReconcile","OIDC provider verified after deploy",{status:r.data.status})}async function _(i,e,n){const r=await g(i,n);if(!r.success){const t=m(r.error.message);s.debug("oidcTeardown","OIDC provider teardown probe failed",{error:t}),e.onLog?.(`OIDC provider cleanup skipped: ${t}`,"warn");return}if(r.data.deleted){s.info("oidcTeardown","Deleted orphaned account-global OIDC provider"),e.onLog?.("Removed the orphaned Fjall OIDC provider","info");return}s.debug("oidcTeardown","OIDC provider retained",{reason:r.data.reason})}export{_ as cleanupOrphanedOidcProvider,g as deleteOidcProviderIfUnreferenced,h as ensureOidcProviderPresent,F as reconcileOidcProviderAfterDeploy};
@@ -85,9 +85,9 @@ export interface StackCompletionResult {
85
85
  */
86
86
  export declare function handleStackCompletion(aws: AwsClientLike, stackName: string, failureReasons: Map<string, string>, eventLogger: EventLogWriter | null, failureAnalyser: EventFailureAnalyser | null, eventHistory: Map<string, ResourceEvent[]>): Promise<StackCompletionResult>;
87
87
  /** Fetch the current status of a CloudFormation stack */
88
- export declare function fetchStackStatus(aws: AwsClientLike, stackName: string): Promise<{
88
+ export declare function fetchStackStatus(aws: AwsClientLike, stackName: string, abortSignal?: AbortSignal): Promise<{
89
89
  status: string;
90
90
  statusReason?: string;
91
91
  } | null>;
92
92
  /** Fetch the latest event for each resource in a stack */
93
- export declare function fetchCurrentResources(aws: AwsClientLike, stackName: string): Promise<ResourceEvent[]>;
93
+ export declare function fetchCurrentResources(aws: AwsClientLike, stackName: string, abortSignal?: AbortSignal): Promise<ResourceEvent[]>;
@@ -1 +1 @@
1
- import{CloudFormationClient as R,DescribeStackEventsCommand as y,DescribeStacksCommand as L}from"@aws-sdk/client-cloudformation";import{logger as T}from"@fjall/util/logger";import{getErrorMessage as f,maskSensitiveOutput as P}from"@fjall/util";import{STACK_NOT_FOUND_PATTERN as S,maskFailureAnalysis as k}from"@fjall/util/aws";import{CF_STACK_RESOURCE_TYPE as g}from"./cloudformationEventTypes.js";import{extractErrorName as A}from"../organisations/types.js";const h=["CREATE_COMPLETE","CREATE_FAILED","DELETE_COMPLETE","DELETE_FAILED","UPDATE_COMPLETE","UPDATE_FAILED","UPDATE_ROLLBACK_COMPLETE","UPDATE_ROLLBACK_FAILED","ROLLBACK_COMPLETE","ROLLBACK_FAILED","IMPORT_COMPLETE","IMPORT_ROLLBACK_COMPLETE","IMPORT_ROLLBACK_FAILED"],_=["CREATE_COMPLETE","UPDATE_COMPLETE","DELETE_COMPLETE","IMPORT_COMPLETE"];function M(t){return h.includes(t)}function b(t){return _.includes(t)}const O=new Set(["AWS::EC2::IPAMPool","AWS::EC2::IPAMPoolCidr","AWS::EC2::IPAM"]);function F(t){return O.has(t)}class ${inProgress=new Map;get size(){return this.inProgress.size}clear(){this.inProgress.clear()}trackEvent(e,i){if(e.status.includes("IN_PROGRESS")){this.inProgress.set(e.logicalId,{resourceType:e.resourceType,startTime:e.timestamp});const o=Array.from(this.inProgress.entries()).map(([n,r])=>`${n} (${r.resourceType.split("::").pop()}, started ${r.startTime.toISOString()})`);T.debug("CloudFormation","IPAM resource started",{logicalId:e.logicalId,resourceType:e.resourceType,concurrentIpamCount:this.inProgress.size,concurrentIpamResources:o}),i&&i.writeEvent(e,{phase:"ipam_concurrency",isMainStack:!0,parentStack:`concurrent=${this.inProgress.size}: ${o.join(", ")}`})}else if(e.status.includes("COMPLETE")||e.status.includes("FAILED")){const o=this.inProgress.has(e.logicalId),n=this.inProgress.get(e.logicalId);this.inProgress.delete(e.logicalId);const r=n?e.timestamp.getTime()-n.startTime.getTime():void 0;if(T.debug("CloudFormation",`IPAM resource ${e.status}`,{logicalId:e.logicalId,resourceType:e.resourceType,status:e.status,statusReason:e.statusReason,durationMs:r,wasTracked:o,remainingIpamCount:this.inProgress.size,remainingIpamResources:Array.from(this.inProgress.keys())}),e.status.includes("FAILED")&&i){const u=Array.from(this.inProgress.entries()).map(([a,c])=>({logicalId:a,resourceType:c.resourceType,startTime:c.startTime.toISOString(),inFlightDurationMs:e.timestamp.getTime()-c.startTime.getTime()}));i.writeEvent(e,{phase:"ipam_failure_snapshot",isMainStack:!0,parentStack:JSON.stringify({failedResource:e.logicalId,reason:e.statusReason,durationMs:r,concurrentIpamAtFailure:u})})}}}}const H=12e4;async function B(t,e,i){try{const o=t.aws.getClient(R);let n,r=!1,u=!1;do{const a=new y({StackName:e,...n?{NextToken:n}:{}}),c=await o.send(a);if(!c.StackEvents)break;for(const s of c.StackEvents){const m=`${s.EventId}`;if(t.seenEventIds.has(m)){u=!0;continue}if(t.seenEventIds.add(m),s.Timestamp!==void 0&&s.Timestamp.getTime()<t.eventCutoffMs){u=!0;continue}if(s.ResourceType===g&&s.LogicalResourceId!==e){const E=s.ResourceStatus||"",p=s.LogicalResourceId||"";E.includes("IN_PROGRESS")?t.activeNestedStacks.set(p,E):(E.includes("COMPLETE")||E.includes("FAILED"))&&t.activeNestedStacks.delete(p)}if(s.LogicalResourceId===e&&s.ResourceType===g){const E=s.ResourceStatus||"";M(E)&&(r=!0)}s.ResourceStatus&&s.ResourceStatus.includes("FAILED")&&s.ResourceStatusReason&&(t.failureReasons.set(s.LogicalResourceId||"unknown",s.ResourceStatusReason),T.debug("CloudFormation",`Captured failure: ${s.LogicalResourceId} - ${s.ResourceStatusReason}`));const l=s.Timestamp===void 0||s.Timestamp.getTime()>=t.tokenLatchCutoffMs,d={logicalId:s.LogicalResourceId||"",physicalId:s.PhysicalResourceId,resourceType:s.ResourceType||"",status:s.ResourceStatus||"",statusReason:s.ResourceStatusReason,timestamp:s.Timestamp||new Date,clientRequestToken:l?s.ClientRequestToken:void 0},I=d.logicalId,C=t.eventHistory.get(I)??[];if(C.push(d),t.eventHistory.set(I,C),t.eventHistory.size>t.maxHistorySize){const E=[...t.eventHistory.keys()].slice(0,t.eventHistory.size-t.maxHistorySize);for(const p of E)t.eventHistory.delete(p)}F(d.resourceType)&&t.ipamTracker.trackEvent(d,t.eventLogger),t.eventLogger&&t.eventLogger.writeEvent(d),T.debug("CloudFormation","pollEvents delivering event",{stackName:e,logicalId:d.logicalId,status:d.status,resourceType:d.resourceType}),i(d)}n=u?void 0:c.NextToken}while(n);return r&&t.activeNestedStacks.size>0?!1:r}catch(o){const n=A(o),r=f(o);return n==="ValidationError"&&r.includes(S)?!1:n==="Throttling"||n==="TooManyRequestsException"||n==="ThrottlingException"?"throttled":(r.includes(S)||T.error("CloudFormation","Unexpected polling error",{error:P(r)}),!1)}}async function W(t,e,i,o,n,r){const u=await D(t,e),a=u?.status||"UNKNOWN",c=a.endsWith("_COMPLETE")&&!a.includes("ROLLBACK")&&!a.includes("FAILED");let s=u?.statusReason;!c&&i.size>0&&(s=(Array.from(i.values())[0]??s)||s);let m=null;if(!c&&n){const l=n.analyseFailure(r,e);m=l===null?null:k(l)}return o&&(o.writeDeploymentEnd(c,a,s),!c&&i.size>0&&o.writeFailureSummary(Array.from(i.entries()).map(([l,d])=>({logicalId:l,reason:d}))),m&&o.writeFailureAnalysis({rootCause:m.rootCause.reason,failedResources:m.affectedResources.map(l=>({logicalId:l.logicalId,resourceType:l.resourceType,reason:l.statusReason||"Unknown reason"})),dependencyChain:m.dependencyChain,remediation:m.remediation})),{success:c,failureMessage:s,analysis:m}}async function D(t,e){try{const i=new L({StackName:e}),r=(await t.getClient(R).send(i)).Stacks?.[0];return r?{status:r.StackStatus||"UNKNOWN",statusReason:r.StackStatusReason}:null}catch(i){return T.debug("CloudFormation","getStackStatus failed",{error:f(i)}),null}}async function q(t,e){const i=[];try{const o=new y({StackName:e}),r=await t.getClient(R).send(o);if(!r.StackEvents)return i;const u=new Map;for(const a of r.StackEvents){const c=a.LogicalResourceId||"";if(c===e&&a.ResourceType===g)continue;const s=u.get(c);(!s||a.Timestamp&&s.timestamp<a.Timestamp)&&u.set(c,{logicalId:c,physicalId:a.PhysicalResourceId,resourceType:a.ResourceType||"",status:a.ResourceStatus||"",statusReason:a.ResourceStatusReason,timestamp:a.Timestamp||new Date,clientRequestToken:a.ClientRequestToken})}return Array.from(u.values())}catch(o){const n=A(o),r=f(o);return n==="ValidationError"&&r.includes(S)||r.includes(S)||T.error("CloudFormation","Error getting current resources",{error:P(f(o))}),i}}export{H as EVENT_CUTOFF_SKEW_MS,$ as IpamConcurrencyTracker,q as fetchCurrentResources,D as fetchStackStatus,W as handleStackCompletion,F as isIpamResource,b as isSuccessState,M as isTerminalState,B as pollStackEvents};
1
+ import{CloudFormationClient as g,DescribeStackEventsCommand as P,DescribeStacksCommand as k}from"@aws-sdk/client-cloudformation";import{logger as T}from"@fjall/util/logger";import{getErrorMessage as f,maskSensitiveOutput as A}from"@fjall/util";import{STACK_NOT_FOUND_PATTERN as S,maskFailureAnalysis as h}from"@fjall/util/aws";import{CF_STACK_RESOURCE_TYPE as R}from"./cloudformationEventTypes.js";import{composeSdkAbortSignal as I,extractErrorName as L}from"../organisations/types.js";const _=["CREATE_COMPLETE","CREATE_FAILED","DELETE_COMPLETE","DELETE_FAILED","UPDATE_COMPLETE","UPDATE_FAILED","UPDATE_ROLLBACK_COMPLETE","UPDATE_ROLLBACK_FAILED","ROLLBACK_COMPLETE","ROLLBACK_FAILED","IMPORT_COMPLETE","IMPORT_ROLLBACK_COMPLETE","IMPORT_ROLLBACK_FAILED"],M=["CREATE_COMPLETE","UPDATE_COMPLETE","DELETE_COMPLETE","IMPORT_COMPLETE"];function O(t){return _.includes(t)}function $(t){return M.includes(t)}const F=new Set(["AWS::EC2::IPAMPool","AWS::EC2::IPAMPoolCidr","AWS::EC2::IPAM"]);function D(t){return F.has(t)}class H{inProgress=new Map;get size(){return this.inProgress.size}clear(){this.inProgress.clear()}trackEvent(s,c){if(s.status.includes("IN_PROGRESS")){this.inProgress.set(s.logicalId,{resourceType:s.resourceType,startTime:s.timestamp});const n=Array.from(this.inProgress.entries()).map(([r,i])=>`${r} (${i.resourceType.split("::").pop()}, started ${i.startTime.toISOString()})`);T.debug("CloudFormation","IPAM resource started",{logicalId:s.logicalId,resourceType:s.resourceType,concurrentIpamCount:this.inProgress.size,concurrentIpamResources:n}),c&&c.writeEvent(s,{phase:"ipam_concurrency",isMainStack:!0,parentStack:`concurrent=${this.inProgress.size}: ${n.join(", ")}`})}else if(s.status.includes("COMPLETE")||s.status.includes("FAILED")){const n=this.inProgress.has(s.logicalId),r=this.inProgress.get(s.logicalId);this.inProgress.delete(s.logicalId);const i=r?s.timestamp.getTime()-r.startTime.getTime():void 0;if(T.debug("CloudFormation",`IPAM resource ${s.status}`,{logicalId:s.logicalId,resourceType:s.resourceType,status:s.status,statusReason:s.statusReason,durationMs:i,wasTracked:n,remainingIpamCount:this.inProgress.size,remainingIpamResources:Array.from(this.inProgress.keys())}),s.status.includes("FAILED")&&c){const a=Array.from(this.inProgress.entries()).map(([l,o])=>({logicalId:l,resourceType:o.resourceType,startTime:o.startTime.toISOString(),inFlightDurationMs:s.timestamp.getTime()-o.startTime.getTime()}));c.writeEvent(s,{phase:"ipam_failure_snapshot",isMainStack:!0,parentStack:JSON.stringify({failedResource:s.logicalId,reason:s.statusReason,durationMs:i,concurrentIpamAtFailure:a})})}}}}const B=12e4;async function W(t,s,c){try{const n=t.aws.getClient(g);let r,i=!1,a=!1;do{const l=new P({StackName:s,...r?{NextToken:r}:{}}),o=await n.send(l,{abortSignal:I(void 0)});if(!o.StackEvents)break;for(const e of o.StackEvents){const u=`${e.EventId}`;if(t.seenEventIds.has(u)){a=!0;continue}if(t.seenEventIds.add(u),e.Timestamp!==void 0&&e.Timestamp.getTime()<t.eventCutoffMs){a=!0;continue}if(e.ResourceType===R&&e.LogicalResourceId!==s){const E=e.ResourceStatus||"",p=e.LogicalResourceId||"";E.includes("IN_PROGRESS")?t.activeNestedStacks.set(p,E):(E.includes("COMPLETE")||E.includes("FAILED"))&&t.activeNestedStacks.delete(p)}if(e.LogicalResourceId===s&&e.ResourceType===R){const E=e.ResourceStatus||"";O(E)&&(i=!0)}e.ResourceStatus&&e.ResourceStatus.includes("FAILED")&&e.ResourceStatusReason&&(t.failureReasons.set(e.LogicalResourceId||"unknown",e.ResourceStatusReason),T.debug("CloudFormation",`Captured failure: ${e.LogicalResourceId} - ${e.ResourceStatusReason}`));const d=e.Timestamp===void 0||e.Timestamp.getTime()>=t.tokenLatchCutoffMs,m={logicalId:e.LogicalResourceId||"",physicalId:e.PhysicalResourceId,resourceType:e.ResourceType||"",status:e.ResourceStatus||"",statusReason:e.ResourceStatusReason,timestamp:e.Timestamp||new Date,clientRequestToken:d?e.ClientRequestToken:void 0},C=m.logicalId,y=t.eventHistory.get(C)??[];if(y.push(m),t.eventHistory.set(C,y),t.eventHistory.size>t.maxHistorySize){const E=[...t.eventHistory.keys()].slice(0,t.eventHistory.size-t.maxHistorySize);for(const p of E)t.eventHistory.delete(p)}D(m.resourceType)&&t.ipamTracker.trackEvent(m,t.eventLogger),t.eventLogger&&t.eventLogger.writeEvent(m),T.debug("CloudFormation","pollEvents delivering event",{stackName:s,logicalId:m.logicalId,status:m.status,resourceType:m.resourceType}),c(m)}r=a?void 0:o.NextToken}while(r);return i&&t.activeNestedStacks.size>0?!1:i}catch(n){const r=L(n),i=f(n);return r==="ValidationError"&&i.includes(S)?!1:r==="Throttling"||r==="TooManyRequestsException"||r==="ThrottlingException"?"throttled":(i.includes(S)||T.error("CloudFormation","Unexpected polling error",{error:A(i)}),!1)}}async function q(t,s,c,n,r,i){const a=await w(t,s),l=a?.status||"UNKNOWN",o=l.endsWith("_COMPLETE")&&!l.includes("ROLLBACK")&&!l.includes("FAILED");let e=a?.statusReason;!o&&c.size>0&&(e=(Array.from(c.values())[0]??e)||e);let u=null;if(!o&&r){const d=r.analyseFailure(i,s);u=d===null?null:h(d)}return n&&(n.writeDeploymentEnd(o,l,e),!o&&c.size>0&&n.writeFailureSummary(Array.from(c.entries()).map(([d,m])=>({logicalId:d,reason:m}))),u&&n.writeFailureAnalysis({rootCause:u.rootCause.reason,failedResources:u.affectedResources.map(d=>({logicalId:d.logicalId,resourceType:d.resourceType,reason:d.statusReason||"Unknown reason"})),dependencyChain:u.dependencyChain,remediation:u.remediation})),{success:o,failureMessage:e,analysis:u}}async function w(t,s,c){try{const n=new k({StackName:s}),a=(await t.getClient(g).send(n,{abortSignal:I(c)})).Stacks?.[0];return a?{status:a.StackStatus||"UNKNOWN",statusReason:a.StackStatusReason}:null}catch(n){return T.debug("CloudFormation","getStackStatus failed",{error:f(n)}),null}}async function V(t,s,c){const n=[];try{const r=new P({StackName:s}),a=await t.getClient(g).send(r,{abortSignal:I(c)});if(!a.StackEvents)return n;const l=new Map;for(const o of a.StackEvents){const e=o.LogicalResourceId||"";if(e===s&&o.ResourceType===R)continue;const u=l.get(e);(!u||o.Timestamp&&u.timestamp<o.Timestamp)&&l.set(e,{logicalId:e,physicalId:o.PhysicalResourceId,resourceType:o.ResourceType||"",status:o.ResourceStatus||"",statusReason:o.ResourceStatusReason,timestamp:o.Timestamp||new Date,clientRequestToken:o.ClientRequestToken})}return Array.from(l.values())}catch(r){const i=L(r),a=f(r);return i==="ValidationError"&&a.includes(S)||a.includes(S)||T.error("CloudFormation","Error getting current resources",{error:A(f(r))}),n}}export{B as EVENT_CUTOFF_SKEW_MS,H as IpamConcurrencyTracker,V as fetchCurrentResources,w as fetchStackStatus,q as handleStackCompletion,D as isIpamResource,$ as isSuccessState,O as isTerminalState,W as pollStackEvents};
@@ -64,8 +64,8 @@ export { decideNextTransition, reconcileTrailMigration, decommissionMemberTrailS
64
64
  export type { MemberTrailFacts, TrailMigrationTransition, TrailMigrationOutcome, DecommissionClients, DecommissionInput, DecommissionOutcome } from "./orchestration/index.js";
65
65
  export { classifyDriftFailure, fetchLastOperationEvents, DriftProbe, clearDriftSuspects, defaultDriftJournalDir, readDriftSuspects, recordDriftSuspects, detectStackDrift, runDriftPreFlight, formatDriftPreFlightBlock, DRIFT_PREFLIGHT_TRIGGER_STATUSES, DRIFT_PREFLIGHT_BUDGET_MS } from "./orchestration/index.js";
66
66
  export type { DriftProbeOptions, DriftProbeRunner, ProbeDriftSuspectsParams, DriftJournalOptions, RecordDriftSuspectsParams, DetectStackDriftDeps, DetectStackDriftParams, StackDriftReport, RunDriftPreFlightParams, DriftPreFlightBlockExtras, DriftPreFlightOutcome } from "./orchestration/index.js";
67
- export { archiveCompletedRemediationJournal, computeRemediationOpId, defaultRemediationJournalDir, findRemediationJournalByOpId, listActiveRemediationOps, listActiveRemediationOpsForContext, readRemediationJournal, sweepExpiredRemediationJournals, writeRemediationJournal, REMEDIATION_JOURNAL_RETENTION_DAYS, captureRemediationForensics, defaultRemediationForensicsDir, applyRetainFlip, composeFlipCapabilities, computeTemplateDigest, deriveRetainFlipTemplate, findMarkedResourcesByOpId, proveFlipMetadataOnly, readRetainFlipState, verifyRetainFlipDiff, FORGET_MARKER_KEY, FORGET_FLIP_SPEC, RECREATE_MARKER_KEY, assessForgetResumability, completeForgetAfterConverge, completeForgetAfterDeploy, formatRecreateInFlightCures, partitionPreFlightByRemediation, runForgetSurgery, synthTemplateDeclaresResource, runRecreateSurgery, snapshotPolicyForType, SNAPSHOT_CAPABLE_RESOURCE_TYPES, runRecreatePreFlight, deriveRemovalTemplate, findRemovalDeletionFailures, proveRemovalTargetsOnly, advertisableDriftVerbs, buildDriftRepairTicket, runDriftRepairGate, formatPinOutcomeDetail, pinProbeCoverage, renderPinReportLines, runPinRemediation, composePostFailureRepairOffer, formatDriftRepairOffer, DriftRepairAvailableError, checkDeployPathStackAvailability, isDeployPathBlockingStatus, StackUnavailableError, assertLeaseBeforeStack, LeaseDeniedError } from "./orchestration/index.js";
68
- export type { RemediationJournalContext, RemediationJournalOptions, CaptureRemediationForensicsParams, ForensicsCaptureOptions, RemediationForensicsBundle, ApplyRetainFlipOutcome, ApplyRetainFlipParams, DeriveRetainFlipParams, FlipDeletionPolicy, FlipProofResult, FlipSpec, RetainFlipDerivation, RetainFlipState, RecreateOrchestrationOptions, RecreateSurgeryParams, RecreateSurgeryReport, RecreatePreFlightStack, RunRecreatePreFlightParams, ProveRemovalTargetsOnlyParams, RemovalDeletionFailure, RemovalDerivation, RemovalProofResult, StrippedExport, CompleteForgetAfterDeployParams, CompleteForgetOutcome, CompleteForgetParams, ForeignMarkerOperation, ForgetOrchestrationOptions, ForgetResumeAssessment, ForgetResumeSource, ForgetSurgeryParams, ForgetSurgeryReport, PreFlightRemediationDeps, PreFlightRemediationPartition, DriftRepairGateOutcome, RunDriftRepairGateParams, ComposePostFailureRepairOfferParams, PinnedProperty, PinProbeCoverage, PinRemediationReport, PinReportOnlyReason, PinResourceOutcome, PinTarget, RunPinRemediationParams } from "./orchestration/index.js";
67
+ export { archiveCompletedRemediationJournal, computeRemediationOpId, defaultRemediationJournalDir, findRemediationJournalByOpId, listActiveRemediationOps, listActiveRemediationOpsForContext, readRemediationJournal, sweepExpiredRemediationJournals, writeRemediationJournal, REMEDIATION_JOURNAL_RETENTION_DAYS, captureRemediationForensics, defaultRemediationForensicsDir, applyRetainFlip, composeFlipCapabilities, computeTemplateDigest, deriveRetainFlipTemplate, findMarkedResourcesByOpId, proveFlipMetadataOnly, readRetainFlipState, verifyRetainFlipDiff, FORGET_MARKER_KEY, FORGET_FLIP_SPEC, RECREATE_MARKER_KEY, assessForgetResumability, completeForgetAfterConverge, completeForgetAfterDeploy, formatRecreateInFlightCures, partitionPreFlightByRemediation, runForgetSurgery, synthTemplateDeclaresResource, runRecreateSurgery, snapshotPolicyForType, SNAPSHOT_CAPABLE_RESOURCE_TYPES, runRecreatePreFlight, deriveRemovalTemplate, findRemovalDeletionFailures, findResourcesPresent, proveRemovalTargetsOnly, advertisableDriftVerbs, buildDriftRepairTicket, runDriftRepairGate, formatPinOutcomeDetail, pinProbeCoverage, renderPinReportLines, runPinRemediation, composePostFailureRepairOffer, formatDriftRepairOffer, DriftRepairAvailableError, checkDeployPathStackAvailability, isDeployPathBlockingStatus, StackUnavailableError, assertLeaseBeforeStack, LeaseDeniedError } from "./orchestration/index.js";
68
+ export type { RemediationJournalContext, RemediationJournalOptions, CaptureRemediationForensicsParams, ForensicsCaptureOptions, RemediationForensicsBundle, ApplyRetainFlipOutcome, ApplyRetainFlipParams, DeriveRetainFlipParams, FlipDeletionPolicy, FlipProofResult, FlipSpec, RetainFlipDerivation, RetainFlipState, RecreateOrchestrationOptions, RecreateSurgeryParams, RecreateSurgeryReport, RecreatePreFlightStack, RunRecreatePreFlightParams, CoRemovedResource, ProveRemovalTargetsOnlyParams, RemovalDeletionFailure, RemovalDerivation, RemovalProofResult, StrippedExport, CompleteForgetAfterDeployParams, CompleteForgetOutcome, CompleteForgetParams, ForeignMarkerOperation, ForgetOrchestrationOptions, ForgetResumeAssessment, ForgetResumeSource, ForgetSurgeryParams, ForgetSurgeryReport, PreFlightRemediationDeps, PreFlightRemediationPartition, DriftRepairGateOutcome, RunDriftRepairGateParams, ComposePostFailureRepairOfferParams, PinnedProperty, PinProbeCoverage, PinRemediationReport, PinReportOnlyReason, PinResourceOutcome, PinTarget, RunPinRemediationParams } from "./orchestration/index.js";
69
69
  export { unlockBucket, unlockQueue } from "./orchestration/index.js";
70
70
  export type { UnlockBucketInput, UnlockBucketReport, UnlockQueueInput, UnlockQueueReport } from "./orchestration/index.js";
71
71
  export { triageBucketPolicy, isEnforceSslStatement, toResourcePolicyStatements, restoreBucketPolicy, synthesiseEnforceSslDocument, ensureEnforceSsl, restoreAndReconcileQuarantinedBucket } from "./orchestration/index.js";
package/dist/src/index.js CHANGED
@@ -1 +1 @@
1
- import{DeploymentEventSchema as t,DEPLOYMENT_EVENT_TYPES as o,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as i,DEPLOYMENT_EVENT_STATUS_REASON_MAX as a,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as s,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as n,CASCADE_PHASES as c,CASCADE_ACCOUNT_STATUSES as E}from"./types/index.js";import{DeployEventSchema as l,StepProgressSchema as p,DeployResourceSchema as T,PlanChangeSchema as A,PlanPropertyChangeSchema as R,ChangeCountsSchema as _,DEPLOY_EVENT_CONTRACT as m,DEPLOY_EVENT_CONTRACT_MAJOR as u,DEPLOY_EVENT_CONTRACT_MINOR as d,SUPPORTED_CONTRACT_MARKERS as P,DEPLOY_EVENT_ID_MAX as O,DEPLOY_EVENT_NAME_MAX as D,DEPLOY_EVENT_MESSAGE_MAX as f,DEPLOY_EVENT_STATUS_REASON_MAX as C,DEPLOY_EVENT_ERROR_MESSAGE_MAX as N,DEPLOY_EVENT_TRAIL_DETAIL_MAX as g,DEPLOY_EVENT_OUTPUT_MAX as L,DEPLOY_EVENT_ARN_MAX as I,DEPLOY_EVENT_URL_MAX as y,STEP_COMPLETE_STATUSES as h,LOG_LEVELS as v,STACK_CLEANUP_PHASES as x,CASCADE_ACCOUNT_PHASES as F,DEPLOY_RESULTS as M,DETECTION_PHASES as U,PHASE_STATUSES as k,BUILDERS as b,CASCADE_OUTCOME_RESULTS as V,PLAN_ACTIONS as Y,REPLACEMENT_MODES as B,APPROVAL_KINDS as G,APPROVAL_DECISIONS as K,ALL_PROGRESS_KINDS as X,createDeployEmitter as H,parseDeployEvent as J,parseDeployContractVersion as w}from"./types/index.js";import{SimpleAwsProvider as Q}from"./aws/index.js";import{checkTargetReadiness as q,describeTargetReadinessReason as Z,buildTargetUnreadyAdvisory as z,buildTargetSetUnreadyAdvisory as $,probeAccountStackExists as ee}from"./aws/index.js";import{checkRegionEnabled as te,regionDisabledMessage as oe}from"./aws/index.js";import{ensureOrganisationExists as ae,describeOrganisation as se,enablePolicyTypes as ne,enableServiceAccess as ce,SERVICE_PRINCIPALS as Ee,enableRamSharing as Se,activateTrustedAccess as le,enableIpamDelegatedAdmin as pe,updateBackupGlobalSettings as Te,listAccounts as Ae,findAccount as Re,createAccount as _e,ensureOrganisationalUnitsExist as me,placeAccountsInOUs as ue,buildAccountToOUMap as de,findDevelopmentOuId as Pe,activateCostAllocationTags as Oe,checkIdentityCentreStatus as De,snapshotIdentityCentre as fe,composeSdkAbortSignal as Ce,extractErrorName as Ne,isAborted as ge,DEFAULT_MAX_PAGES as Le,IDENTITY_STORE_PAGE_SIZE as Ie,drainPages as ye,isOULeaf as he,registerSecurityDelegates as ve,SECURITY_SERVICE_PRINCIPALS as xe,enableCentralisedRootAccess as Fe,ROOT_ACCESS_FEATURES as Me,RootAccessEnablementError as Ue}from"./aws/index.js";import{STEP_IDS as be,STEP_NAMES as Ve,INFRASTRUCTURE_STEP_NAMES as Ye,INFRA_STEP_NAME as Be}from"./types/index.js";import{RemediationVerbSchema as Ke,REMEDIATION_VERB_GLOSS as Xe,DestructionFindingSchema as He,DestructionTicketResourceSchema as Je,DestructionTicketSchema as we,DestructionConsentSchema as je,DestructionOutcomeSchema as Qe,DESTRUCTION_FINDINGS as We,CONSENT_VERDICTS as qe,TICKET_VERDICT_SOURCES as Ze,TicketVerdictSourceSchema as ze}from"./types/index.js";import{DRIFT_VERDICTS as er,DriftVerdictSchema as rr,DriftSuspectSchema as tr,DriftFindingSchema as or,DriftJournalRecordSchema as ir,verbsForDriftVerdict as ar}from"./types/index.js";import{REMEDIATION_PHASES as nr,RemediationPhaseSchema as cr,RemediationTargetSchema as Er,RemediationFlipProofSchema as Sr,RemediationJournalRecordSchema as lr,RemediationVerbWithSurgerySchema as pr,remediationPhaseRank as Tr,remediationPlaceholderPhysicalId as Ar,isRemediationPlaceholderPhysicalId as Rr}from"./types/index.js";import{ProgressReporter as mr,APPLICATION_STACKS as ur,ORGANISATION_TYPES as dr,APPLICATION_DEPLOY_ORDER as Pr,APPLICATION_DESTROY_ORDER as Or,OPENNEXT_DEPLOY_ORDER as Dr,OPENNEXT_DESTROY_ORDER as fr,PARALLEL_DEPLOY_GROUPS as Cr,PARALLEL_DESTROY_GROUPS as Nr,OPENNEXT_PARALLEL_GROUPS as gr,PARALLEL_OPERATION_TYPES as Lr,isApplicationOperation as Ir,isOrganisationOperation as yr,getParallelDeployGroups as hr,getParallelDestroyGroups as vr,getApplicationDeployOrder as xr,getApplicationDestroyOrder as Fr,getApplicationStackName as Mr,getOrganisationStackName as Ur,isApplicationStack as kr,isQuarantineDetail as br,isRetainedBucketsDetail as Vr,getApplicationStepName as Yr,getApplicationStepId as Br,toPascalCase as Gr,isOpenNextPattern as Kr,OPENNEXT_PATTERNS as Xr,STACK_NOT_FOUND_PATTERN as Hr,STACK_FAILED_STATE_PATTERN as Jr,CDK_NO_STACKS_MATCH as wr,INFRASTRUCTURE_FILENAME as jr,ApplicationError as Qr,wrapApplicationError as Wr,stubCallerIdentity as qr}from"./types/index.js";import{deriveResourcesFromManifestStacks as zr}from"./types/detection/patternDetection.js";import{FjallStateFileSchema as et,readStateFile as rt,writeStateFile as tt,createEmptyState as ot,deleteStateFile as it,updateTemplateHash as at,getStateFilePath as st,regionSuffix as nt}from"./types/config/FjallState.js";import{CloudFormationEventMonitor as Et}from"./aws/index.js";import{CdkService as lt,CdkArgumentBuilder as pt,CdkProcessManager as Tt,CdkEventMonitor as At,startStackMonitoring as Rt,DEFAULT_DEPLOY_TIMEOUT_MS as _t,isCdkError as mt,formatInfrastructureError as ut,getStructuralHint as dt,getSourceContext as Pt,hasCdkDifferences as Ot,parseDiffOutput as Dt,CloudFormationService as ft,CloudFormationError as Ct,EcsService as Nt,EcsError as gt,EcsServiceResolver as Lt,TemplateHashService as It,TemplateHashError as yt,CdkContextBuilder as ht,emitProgress as vt,PROGRESS_MESSAGES as xt,parseBuildPhase as Ft,buildStepContextBuildConfig as Mt,convertCloudFormationOutputsToRecord as Ut,ApplicationStackService as kt}from"./services/index.js";import{CdkError as Vt}from"./types/errors/index.js";import{BaseServiceError as Bt,ValidationError as Gt,AuthError as Kt,AwsError as Xt,DeploymentError as Ht,NetworkError as Jt,FileSystemError as wt,ConfigError as jt,toServiceError as Qt}from"./types/errors/index.js";import{filterDangerousEnvVars as qt,maskSensitiveOutput as Zt,parseShellArgs as zt,sleep as $t}from"@fjall/util";import{artefactOutputKey as ro,DeployModeSchema as to,ServiceArtefactSchema as oo,ServiceArtefactsSchema as io}from"@fjall/util";import{hasDockerfile as so}from"./util/dockerfileDetection.js";import{sleepAbortable as co}from"./util/sleepAbortable.js";import{createSequencedCallbacks as So}from"./util/sequencedCallbacks.js";import{fileExists as po}from"@fjall/util/fsHelpers";import{success as Ao,failure as Ro,isSuccess as _o,isFailure as mo}from"@fjall/generator";import{deploy as Po}from"./orchestration/index.js";import{destroy as Do}from"./orchestration/index.js";import{restart as Co,probeSecretsDrift as No,computeSecretsDrift as go,deriveStaleParameters as Lo,extractConsumedSsmParameters as Io}from"./orchestration/index.js";import{partitionAccounts as ho}from"./orchestration/index.js";import{buildRegionList as xo,buildAccountRegionPairs as Fo,cascadeHomeRegion as Mo,cascadeOperationKey as Uo}from"./orchestration/index.js";import{projectScalarSummary as bo,projectAccountRows as Vo}from"./orchestration/index.js";import{reconcileProviderAccounts as Bo,mergeReconciledProviderAccounts as Go}from"./orchestration/index.js";import{decideNextTransition as Xo,reconcileTrailMigration as Ho,decommissionMemberTrailStorage as Jo,ORG_TRAIL_BUCKET_OUTPUT_KEY as wo,TRAIL_BUCKET_OUTPUT_KEY as jo,TRAIL_KEY_ARN_OUTPUT_KEY as Qo}from"./orchestration/index.js";import{classifyDriftFailure as qo,fetchLastOperationEvents as Zo,DriftProbe as zo,clearDriftSuspects as $o,defaultDriftJournalDir as ei,readDriftSuspects as ri,recordDriftSuspects as ti,detectStackDrift as oi,runDriftPreFlight as ii,formatDriftPreFlightBlock as ai,DRIFT_PREFLIGHT_TRIGGER_STATUSES as si,DRIFT_PREFLIGHT_BUDGET_MS as ni}from"./orchestration/index.js";import{archiveCompletedRemediationJournal as Ei,computeRemediationOpId as Si,defaultRemediationJournalDir as li,findRemediationJournalByOpId as pi,listActiveRemediationOps as Ti,listActiveRemediationOpsForContext as Ai,readRemediationJournal as Ri,sweepExpiredRemediationJournals as _i,writeRemediationJournal as mi,REMEDIATION_JOURNAL_RETENTION_DAYS as ui,captureRemediationForensics as di,defaultRemediationForensicsDir as Pi,applyRetainFlip as Oi,composeFlipCapabilities as Di,computeTemplateDigest as fi,deriveRetainFlipTemplate as Ci,findMarkedResourcesByOpId as Ni,proveFlipMetadataOnly as gi,readRetainFlipState as Li,verifyRetainFlipDiff as Ii,FORGET_MARKER_KEY as yi,FORGET_FLIP_SPEC as hi,RECREATE_MARKER_KEY as vi,assessForgetResumability as xi,completeForgetAfterConverge as Fi,completeForgetAfterDeploy as Mi,formatRecreateInFlightCures as Ui,partitionPreFlightByRemediation as ki,runForgetSurgery as bi,synthTemplateDeclaresResource as Vi,runRecreateSurgery as Yi,snapshotPolicyForType as Bi,SNAPSHOT_CAPABLE_RESOURCE_TYPES as Gi,runRecreatePreFlight as Ki,deriveRemovalTemplate as Xi,findRemovalDeletionFailures as Hi,proveRemovalTargetsOnly as Ji,advertisableDriftVerbs as wi,buildDriftRepairTicket as ji,runDriftRepairGate as Qi,formatPinOutcomeDetail as Wi,pinProbeCoverage as qi,renderPinReportLines as Zi,runPinRemediation as zi,composePostFailureRepairOffer as $i,formatDriftRepairOffer as ea,DriftRepairAvailableError as ra,checkDeployPathStackAvailability as ta,isDeployPathBlockingStatus as oa,StackUnavailableError as ia,assertLeaseBeforeStack as aa,LeaseDeniedError as sa}from"./orchestration/index.js";import{unlockBucket as ca,unlockQueue as Ea}from"./orchestration/index.js";import{triageBucketPolicy as la,isEnforceSslStatement as pa,toResourcePolicyStatements as Ta,restoreBucketPolicy as Aa,synthesiseEnforceSslDocument as Ra,ensureEnforceSsl as _a,restoreAndReconcileQuarantinedBucket as ma}from"./orchestration/index.js";import{verifyOrgTrailDelivery as da}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as Oa,isRootTaskPolicyArn as Da,ROOT_TASK_POLICY_ARNS as fa,MAX_ROOT_SESSION_SECONDS as Ca}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as ga,flattenAccountsToEnvironments as La,extractAllAccountNames as Ia,accountsConfigToOUTree as ya,isStringArray as ha,isAccountsConfig as va,isOuOnlyAccountBucket as xa,OU_ONLY_ACCOUNT_BUCKETS as Fa}from"./orchestration/index.js";import{runOpenNextBuild as Ua}from"./orchestration/index.js";import{runOrganisationSetup as ba,ORG_SETUP_PHASES as Va}from"./orchestration/index.js";import{resolveBuildSecrets as Ba,resolveSecretRefValue as Ga,resolveBuildSecretSessionProvider as Ka,sourcedRefsFromBuildArgs as Xa,resolveBuildArgs as Ha,buildBuildSecretSessionPolicy as Ja,buildDeploySessionPolicy as wa,partitionForRegion as ja,validateBuildGroup as Qa}from"./orchestration/index.js";import{FrameworkRegistry as qa}from"./orchestration/index.js";import{openNextBuilder as za,staticSiteBuilder as $a,dockerBuilder as es}from"./orchestration/index.js";import{StepRegistry as ts,getDestroyStepId as os}from"./steps/index.js";import{buildDeployPlan as as,computeDeployPlan as ss,computeAssemblyDigest as ns,digestHead as cs,classifyImpact as Es,derivePropertyChanges as Ss,isDataLoss as ls,isStatefulResourceType as ps,renderPlanSummary as Ts,renderPlanLines as As,toWirePlanChanges as Rs,signApprovalToken as _s,verifyApprovalToken as ms,DEFAULT_APPROVAL_TTL_MS as us,APPROVAL_TOKEN_PATTERN as ds,runApprovalGate as Ps}from"./orchestration/index.js";import{runDestructionGate as Ds,buildDestructionTicket as fs,evaluateDestructionConsents as Cs,computeTicketDigest as Ns,legalRemediationVerbs as gs,executableRemediationVerbs as Ls,advertisableRemediationVerbs as Is,renderDestructionTicketLines as ys,renderConsentVerdictLines as hs,loadDeployPlan as vs,createMemoisedPlanLoader as xs}from"./orchestration/index.js";export{X as ALL_PROGRESS_KINDS,Pr as APPLICATION_DEPLOY_ORDER,Or as APPLICATION_DESTROY_ORDER,ur as APPLICATION_STACKS,K as APPROVAL_DECISIONS,G as APPROVAL_KINDS,ds as APPROVAL_TOKEN_PATTERN,Qr as ApplicationError,kt as ApplicationStackService,Kt as AuthError,Xt as AwsError,b as BUILDERS,Bt as BaseServiceError,F as CASCADE_ACCOUNT_PHASES,E as CASCADE_ACCOUNT_STATUSES,V as CASCADE_OUTCOME_RESULTS,c as CASCADE_PHASES,wr as CDK_NO_STACKS_MATCH,qe as CONSENT_VERDICTS,pt as CdkArgumentBuilder,ht as CdkContextBuilder,Vt as CdkError,At as CdkEventMonitor,Tt as CdkProcessManager,lt as CdkService,_ as ChangeCountsSchema,Ct as CloudFormationError,Et as CloudFormationEventMonitor,ft as CloudFormationService,jt as ConfigError,us as DEFAULT_APPROVAL_TTL_MS,_t as DEFAULT_DEPLOY_TIMEOUT_MS,Le as DEFAULT_MAX_PAGES,s as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,i as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,a as DEPLOYMENT_EVENT_STATUS_REASON_MAX,n as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,o as DEPLOYMENT_EVENT_TYPES,I as DEPLOY_EVENT_ARN_MAX,m as DEPLOY_EVENT_CONTRACT,u as DEPLOY_EVENT_CONTRACT_MAJOR,d as DEPLOY_EVENT_CONTRACT_MINOR,N as DEPLOY_EVENT_ERROR_MESSAGE_MAX,O as DEPLOY_EVENT_ID_MAX,f as DEPLOY_EVENT_MESSAGE_MAX,D as DEPLOY_EVENT_NAME_MAX,L as DEPLOY_EVENT_OUTPUT_MAX,C as DEPLOY_EVENT_STATUS_REASON_MAX,g as DEPLOY_EVENT_TRAIL_DETAIL_MAX,y as DEPLOY_EVENT_URL_MAX,M as DEPLOY_RESULTS,We as DESTRUCTION_FINDINGS,U as DETECTION_PHASES,ni as DRIFT_PREFLIGHT_BUDGET_MS,si as DRIFT_PREFLIGHT_TRIGGER_STATUSES,er as DRIFT_VERDICTS,l as DeployEventSchema,to as DeployModeSchema,T as DeployResourceSchema,Ht as DeploymentError,t as DeploymentEventSchema,je as DestructionConsentSchema,He as DestructionFindingSchema,Qe as DestructionOutcomeSchema,Je as DestructionTicketResourceSchema,we as DestructionTicketSchema,or as DriftFindingSchema,ir as DriftJournalRecordSchema,zo as DriftProbe,ra as DriftRepairAvailableError,tr as DriftSuspectSchema,rr as DriftVerdictSchema,gt as EcsError,Nt as EcsService,Lt as EcsServiceResolver,hi as FORGET_FLIP_SPEC,yi as FORGET_MARKER_KEY,wt as FileSystemError,et as FjallStateFileSchema,qa as FrameworkRegistry,Ie as IDENTITY_STORE_PAGE_SIZE,jr as INFRASTRUCTURE_FILENAME,Ye as INFRASTRUCTURE_STEP_NAMES,Be as INFRA_STEP_NAME,v as LOG_LEVELS,sa as LeaseDeniedError,Ca as MAX_ROOT_SESSION_SECONDS,Jt as NetworkError,Dr as OPENNEXT_DEPLOY_ORDER,fr as OPENNEXT_DESTROY_ORDER,gr as OPENNEXT_PARALLEL_GROUPS,Xr as OPENNEXT_PATTERNS,dr as ORGANISATION_TYPES,Va as ORG_SETUP_PHASES,wo as ORG_TRAIL_BUCKET_OUTPUT_KEY,Fa as OU_ONLY_ACCOUNT_BUCKETS,Cr as PARALLEL_DEPLOY_GROUPS,Nr as PARALLEL_DESTROY_GROUPS,Lr as PARALLEL_OPERATION_TYPES,k as PHASE_STATUSES,Y as PLAN_ACTIONS,xt as PROGRESS_MESSAGES,A as PlanChangeSchema,R as PlanPropertyChangeSchema,mr as ProgressReporter,vi as RECREATE_MARKER_KEY,ui as REMEDIATION_JOURNAL_RETENTION_DAYS,nr as REMEDIATION_PHASES,Xe as REMEDIATION_VERB_GLOSS,B as REPLACEMENT_MODES,Me as ROOT_ACCESS_FEATURES,fa as ROOT_TASK_POLICY_ARNS,Sr as RemediationFlipProofSchema,lr as RemediationJournalRecordSchema,cr as RemediationPhaseSchema,Er as RemediationTargetSchema,Ke as RemediationVerbSchema,pr as RemediationVerbWithSurgerySchema,Ue as RootAccessEnablementError,xe as SECURITY_SERVICE_PRINCIPALS,Ee as SERVICE_PRINCIPALS,Gi as SNAPSHOT_CAPABLE_RESOURCE_TYPES,x as STACK_CLEANUP_PHASES,Jr as STACK_FAILED_STATE_PATTERN,Hr as STACK_NOT_FOUND_PATTERN,h as STEP_COMPLETE_STATUSES,be as STEP_IDS,Ve as STEP_NAMES,P as SUPPORTED_CONTRACT_MARKERS,oo as ServiceArtefactSchema,io as ServiceArtefactsSchema,Q as SimpleAwsProvider,ia as StackUnavailableError,p as StepProgressSchema,ts as StepRegistry,Ze as TICKET_VERDICT_SOURCES,jo as TRAIL_BUCKET_OUTPUT_KEY,Qo as TRAIL_KEY_ARN_OUTPUT_KEY,yt as TemplateHashError,It as TemplateHashService,ze as TicketVerdictSourceSchema,Gt as ValidationError,ya as accountsConfigToOUTree,Oe as activateCostAllocationTags,le as activateTrustedAccess,wi as advertisableDriftVerbs,Is as advertisableRemediationVerbs,Oi as applyRetainFlip,Ei as archiveCompletedRemediationJournal,ro as artefactOutputKey,aa as assertLeaseBeforeStack,xi as assessForgetResumability,Oa as assumeRootForTask,Fo as buildAccountRegionPairs,de as buildAccountToOUMap,Ja as buildBuildSecretSessionPolicy,as as buildDeployPlan,wa as buildDeploySessionPolicy,fs as buildDestructionTicket,ji as buildDriftRepairTicket,xo as buildRegionList,Mt as buildStepContextBuildConfig,$ as buildTargetSetUnreadyAdvisory,z as buildTargetUnreadyAdvisory,di as captureRemediationForensics,Mo as cascadeHomeRegion,Uo as cascadeOperationKey,ta as checkDeployPathStackAvailability,De as checkIdentityCentreStatus,te as checkRegionEnabled,q as checkTargetReadiness,qo as classifyDriftFailure,Es as classifyImpact,$o as clearDriftSuspects,Fi as completeForgetAfterConverge,Mi as completeForgetAfterDeploy,Di as composeFlipCapabilities,$i as composePostFailureRepairOffer,Ce as composeSdkAbortSignal,ns as computeAssemblyDigest,ss as computeDeployPlan,Si as computeRemediationOpId,go as computeSecretsDrift,fi as computeTemplateDigest,Ns as computeTicketDigest,Ut as convertCloudFormationOutputsToRecord,_e as createAccount,H as createDeployEmitter,ot as createEmptyState,xs as createMemoisedPlanLoader,So as createSequencedCallbacks,Xo as decideNextTransition,Jo as decommissionMemberTrailStorage,ei as defaultDriftJournalDir,Pi as defaultRemediationForensicsDir,li as defaultRemediationJournalDir,it as deleteStateFile,Po as deploy,Ss as derivePropertyChanges,Xi as deriveRemovalTemplate,zr as deriveResourcesFromManifestStacks,Ci as deriveRetainFlipTemplate,Lo as deriveStaleParameters,se as describeOrganisation,Z as describeTargetReadinessReason,Do as destroy,oi as detectStackDrift,cs as digestHead,es as dockerBuilder,ye as drainPages,vt as emitProgress,Fe as enableCentralisedRootAccess,pe as enableIpamDelegatedAdmin,ne as enablePolicyTypes,Se as enableRamSharing,ce as enableServiceAccess,_a as ensureEnforceSsl,ae as ensureOrganisationExists,me as ensureOrganisationalUnitsExist,Cs as evaluateDestructionConsents,Ls as executableRemediationVerbs,Ia as extractAllAccountNames,Io as extractConsumedSsmParameters,Ne as extractErrorName,Ro as failure,Zo as fetchLastOperationEvents,po as fileExists,qt as filterDangerousEnvVars,Re as findAccount,Pe as findDevelopmentOuId,Ni as findMarkedResourcesByOpId,pi as findRemediationJournalByOpId,Hi as findRemovalDeletionFailures,La as flattenAccountsToEnvironments,ai as formatDriftPreFlightBlock,ea as formatDriftRepairOffer,ut as formatInfrastructureError,Wi as formatPinOutcomeDetail,Ui as formatRecreateInFlightCures,xr as getApplicationDeployOrder,Fr as getApplicationDestroyOrder,Mr as getApplicationStackName,Br as getApplicationStepId,Yr as getApplicationStepName,os as getDestroyStepId,Ur as getOrganisationStackName,hr as getParallelDeployGroups,vr as getParallelDestroyGroups,Pt as getSourceContext,st as getStateFilePath,dt as getStructuralHint,Ot as hasCdkDifferences,so as hasDockerfile,ge as isAborted,va as isAccountsConfig,Ir as isApplicationOperation,kr as isApplicationStack,mt as isCdkError,ls as isDataLoss,oa as isDeployPathBlockingStatus,pa as isEnforceSslStatement,mo as isFailure,he as isOULeaf,Kr as isOpenNextPattern,yr as isOrganisationOperation,xa as isOuOnlyAccountBucket,br as isQuarantineDetail,Rr as isRemediationPlaceholderPhysicalId,Vr as isRetainedBucketsDetail,Da as isRootTaskPolicyArn,ps as isStatefulResourceType,ha as isStringArray,_o as isSuccess,gs as legalRemediationVerbs,Ae as listAccounts,Ti as listActiveRemediationOps,Ai as listActiveRemediationOpsForContext,vs as loadDeployPlan,Zt as maskSensitiveOutput,Go as mergeReconciledProviderAccounts,za as openNextBuilder,ga as parseAccountsConfiguration,Ft as parseBuildPhase,w as parseDeployContractVersion,J as parseDeployEvent,Dt as parseDiffOutput,zt as parseShellArgs,ho as partitionAccounts,ja as partitionForRegion,ki as partitionPreFlightByRemediation,qi as pinProbeCoverage,ue as placeAccountsInOUs,ee as probeAccountStackExists,No as probeSecretsDrift,Vo as projectAccountRows,bo as projectScalarSummary,gi as proveFlipMetadataOnly,Ji as proveRemovalTargetsOnly,ri as readDriftSuspects,Ri as readRemediationJournal,Li as readRetainFlipState,rt as readStateFile,Bo as reconcileProviderAccounts,Ho as reconcileTrailMigration,ti as recordDriftSuspects,oe as regionDisabledMessage,nt as regionSuffix,ve as registerSecurityDelegates,Tr as remediationPhaseRank,Ar as remediationPlaceholderPhysicalId,hs as renderConsentVerdictLines,ys as renderDestructionTicketLines,Zi as renderPinReportLines,As as renderPlanLines,Ts as renderPlanSummary,Ha as resolveBuildArgs,Ka as resolveBuildSecretSessionProvider,Ba as resolveBuildSecrets,Ga as resolveSecretRefValue,Co as restart,ma as restoreAndReconcileQuarantinedBucket,Aa as restoreBucketPolicy,Ps as runApprovalGate,Ds as runDestructionGate,ii as runDriftPreFlight,Qi as runDriftRepairGate,bi as runForgetSurgery,Ua as runOpenNextBuild,ba as runOrganisationSetup,zi as runPinRemediation,Ki as runRecreatePreFlight,Yi as runRecreateSurgery,_s as signApprovalToken,$t as sleep,co as sleepAbortable,fe as snapshotIdentityCentre,Bi as snapshotPolicyForType,Xa as sourcedRefsFromBuildArgs,Rt as startStackMonitoring,$a as staticSiteBuilder,qr as stubCallerIdentity,Ao as success,_i as sweepExpiredRemediationJournals,Vi as synthTemplateDeclaresResource,Ra as synthesiseEnforceSslDocument,Gr as toPascalCase,Ta as toResourcePolicyStatements,Qt as toServiceError,Rs as toWirePlanChanges,la as triageBucketPolicy,ca as unlockBucket,Ea as unlockQueue,Te as updateBackupGlobalSettings,at as updateTemplateHash,Qa as validateBuildGroup,ar as verbsForDriftVerdict,ms as verifyApprovalToken,da as verifyOrgTrailDelivery,Ii as verifyRetainFlipDiff,Wr as wrapApplicationError,mi as writeRemediationJournal,tt as writeStateFile};
1
+ import{DeploymentEventSchema as t,DEPLOYMENT_EVENT_TYPES as o,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as i,DEPLOYMENT_EVENT_STATUS_REASON_MAX as a,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as s,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as n,CASCADE_PHASES as c,CASCADE_ACCOUNT_STATUSES as E}from"./types/index.js";import{DeployEventSchema as l,StepProgressSchema as p,DeployResourceSchema as T,PlanChangeSchema as A,PlanPropertyChangeSchema as R,ChangeCountsSchema as _,DEPLOY_EVENT_CONTRACT as m,DEPLOY_EVENT_CONTRACT_MAJOR as u,DEPLOY_EVENT_CONTRACT_MINOR as d,SUPPORTED_CONTRACT_MARKERS as P,DEPLOY_EVENT_ID_MAX as O,DEPLOY_EVENT_NAME_MAX as D,DEPLOY_EVENT_MESSAGE_MAX as f,DEPLOY_EVENT_STATUS_REASON_MAX as C,DEPLOY_EVENT_ERROR_MESSAGE_MAX as N,DEPLOY_EVENT_TRAIL_DETAIL_MAX as g,DEPLOY_EVENT_OUTPUT_MAX as L,DEPLOY_EVENT_ARN_MAX as I,DEPLOY_EVENT_URL_MAX as y,STEP_COMPLETE_STATUSES as h,LOG_LEVELS as v,STACK_CLEANUP_PHASES as x,CASCADE_ACCOUNT_PHASES as F,DEPLOY_RESULTS as M,DETECTION_PHASES as U,PHASE_STATUSES as k,BUILDERS as b,CASCADE_OUTCOME_RESULTS as V,PLAN_ACTIONS as Y,REPLACEMENT_MODES as B,APPROVAL_KINDS as G,APPROVAL_DECISIONS as K,ALL_PROGRESS_KINDS as X,createDeployEmitter as H,parseDeployEvent as J,parseDeployContractVersion as w}from"./types/index.js";import{SimpleAwsProvider as Q}from"./aws/index.js";import{checkTargetReadiness as q,describeTargetReadinessReason as Z,buildTargetUnreadyAdvisory as z,buildTargetSetUnreadyAdvisory as $,probeAccountStackExists as ee}from"./aws/index.js";import{checkRegionEnabled as te,regionDisabledMessage as oe}from"./aws/index.js";import{ensureOrganisationExists as ae,describeOrganisation as se,enablePolicyTypes as ne,enableServiceAccess as ce,SERVICE_PRINCIPALS as Ee,enableRamSharing as Se,activateTrustedAccess as le,enableIpamDelegatedAdmin as pe,updateBackupGlobalSettings as Te,listAccounts as Ae,findAccount as Re,createAccount as _e,ensureOrganisationalUnitsExist as me,placeAccountsInOUs as ue,buildAccountToOUMap as de,findDevelopmentOuId as Pe,activateCostAllocationTags as Oe,checkIdentityCentreStatus as De,snapshotIdentityCentre as fe,composeSdkAbortSignal as Ce,extractErrorName as Ne,isAborted as ge,DEFAULT_MAX_PAGES as Le,IDENTITY_STORE_PAGE_SIZE as Ie,drainPages as ye,isOULeaf as he,registerSecurityDelegates as ve,SECURITY_SERVICE_PRINCIPALS as xe,enableCentralisedRootAccess as Fe,ROOT_ACCESS_FEATURES as Me,RootAccessEnablementError as Ue}from"./aws/index.js";import{STEP_IDS as be,STEP_NAMES as Ve,INFRASTRUCTURE_STEP_NAMES as Ye,INFRA_STEP_NAME as Be}from"./types/index.js";import{RemediationVerbSchema as Ke,REMEDIATION_VERB_GLOSS as Xe,DestructionFindingSchema as He,DestructionTicketResourceSchema as Je,DestructionTicketSchema as we,DestructionConsentSchema as je,DestructionOutcomeSchema as Qe,DESTRUCTION_FINDINGS as We,CONSENT_VERDICTS as qe,TICKET_VERDICT_SOURCES as Ze,TicketVerdictSourceSchema as ze}from"./types/index.js";import{DRIFT_VERDICTS as er,DriftVerdictSchema as rr,DriftSuspectSchema as tr,DriftFindingSchema as or,DriftJournalRecordSchema as ir,verbsForDriftVerdict as ar}from"./types/index.js";import{REMEDIATION_PHASES as nr,RemediationPhaseSchema as cr,RemediationTargetSchema as Er,RemediationFlipProofSchema as Sr,RemediationJournalRecordSchema as lr,RemediationVerbWithSurgerySchema as pr,remediationPhaseRank as Tr,remediationPlaceholderPhysicalId as Ar,isRemediationPlaceholderPhysicalId as Rr}from"./types/index.js";import{ProgressReporter as mr,APPLICATION_STACKS as ur,ORGANISATION_TYPES as dr,APPLICATION_DEPLOY_ORDER as Pr,APPLICATION_DESTROY_ORDER as Or,OPENNEXT_DEPLOY_ORDER as Dr,OPENNEXT_DESTROY_ORDER as fr,PARALLEL_DEPLOY_GROUPS as Cr,PARALLEL_DESTROY_GROUPS as Nr,OPENNEXT_PARALLEL_GROUPS as gr,PARALLEL_OPERATION_TYPES as Lr,isApplicationOperation as Ir,isOrganisationOperation as yr,getParallelDeployGroups as hr,getParallelDestroyGroups as vr,getApplicationDeployOrder as xr,getApplicationDestroyOrder as Fr,getApplicationStackName as Mr,getOrganisationStackName as Ur,isApplicationStack as kr,isQuarantineDetail as br,isRetainedBucketsDetail as Vr,getApplicationStepName as Yr,getApplicationStepId as Br,toPascalCase as Gr,isOpenNextPattern as Kr,OPENNEXT_PATTERNS as Xr,STACK_NOT_FOUND_PATTERN as Hr,STACK_FAILED_STATE_PATTERN as Jr,CDK_NO_STACKS_MATCH as wr,INFRASTRUCTURE_FILENAME as jr,ApplicationError as Qr,wrapApplicationError as Wr,stubCallerIdentity as qr}from"./types/index.js";import{deriveResourcesFromManifestStacks as zr}from"./types/detection/patternDetection.js";import{FjallStateFileSchema as et,readStateFile as rt,writeStateFile as tt,createEmptyState as ot,deleteStateFile as it,updateTemplateHash as at,getStateFilePath as st,regionSuffix as nt}from"./types/config/FjallState.js";import{CloudFormationEventMonitor as Et}from"./aws/index.js";import{CdkService as lt,CdkArgumentBuilder as pt,CdkProcessManager as Tt,CdkEventMonitor as At,startStackMonitoring as Rt,DEFAULT_DEPLOY_TIMEOUT_MS as _t,isCdkError as mt,formatInfrastructureError as ut,getStructuralHint as dt,getSourceContext as Pt,hasCdkDifferences as Ot,parseDiffOutput as Dt,CloudFormationService as ft,CloudFormationError as Ct,EcsService as Nt,EcsError as gt,EcsServiceResolver as Lt,TemplateHashService as It,TemplateHashError as yt,CdkContextBuilder as ht,emitProgress as vt,PROGRESS_MESSAGES as xt,parseBuildPhase as Ft,buildStepContextBuildConfig as Mt,convertCloudFormationOutputsToRecord as Ut,ApplicationStackService as kt}from"./services/index.js";import{CdkError as Vt}from"./types/errors/index.js";import{BaseServiceError as Bt,ValidationError as Gt,AuthError as Kt,AwsError as Xt,DeploymentError as Ht,NetworkError as Jt,FileSystemError as wt,ConfigError as jt,toServiceError as Qt}from"./types/errors/index.js";import{filterDangerousEnvVars as qt,maskSensitiveOutput as Zt,parseShellArgs as zt,sleep as $t}from"@fjall/util";import{artefactOutputKey as ro,DeployModeSchema as to,ServiceArtefactSchema as oo,ServiceArtefactsSchema as io}from"@fjall/util";import{hasDockerfile as so}from"./util/dockerfileDetection.js";import{sleepAbortable as co}from"./util/sleepAbortable.js";import{createSequencedCallbacks as So}from"./util/sequencedCallbacks.js";import{fileExists as po}from"@fjall/util/fsHelpers";import{success as Ao,failure as Ro,isSuccess as _o,isFailure as mo}from"@fjall/generator";import{deploy as Po}from"./orchestration/index.js";import{destroy as Do}from"./orchestration/index.js";import{restart as Co,probeSecretsDrift as No,computeSecretsDrift as go,deriveStaleParameters as Lo,extractConsumedSsmParameters as Io}from"./orchestration/index.js";import{partitionAccounts as ho}from"./orchestration/index.js";import{buildRegionList as xo,buildAccountRegionPairs as Fo,cascadeHomeRegion as Mo,cascadeOperationKey as Uo}from"./orchestration/index.js";import{projectScalarSummary as bo,projectAccountRows as Vo}from"./orchestration/index.js";import{reconcileProviderAccounts as Bo,mergeReconciledProviderAccounts as Go}from"./orchestration/index.js";import{decideNextTransition as Xo,reconcileTrailMigration as Ho,decommissionMemberTrailStorage as Jo,ORG_TRAIL_BUCKET_OUTPUT_KEY as wo,TRAIL_BUCKET_OUTPUT_KEY as jo,TRAIL_KEY_ARN_OUTPUT_KEY as Qo}from"./orchestration/index.js";import{classifyDriftFailure as qo,fetchLastOperationEvents as Zo,DriftProbe as zo,clearDriftSuspects as $o,defaultDriftJournalDir as ei,readDriftSuspects as ri,recordDriftSuspects as ti,detectStackDrift as oi,runDriftPreFlight as ii,formatDriftPreFlightBlock as ai,DRIFT_PREFLIGHT_TRIGGER_STATUSES as si,DRIFT_PREFLIGHT_BUDGET_MS as ni}from"./orchestration/index.js";import{archiveCompletedRemediationJournal as Ei,computeRemediationOpId as Si,defaultRemediationJournalDir as li,findRemediationJournalByOpId as pi,listActiveRemediationOps as Ti,listActiveRemediationOpsForContext as Ai,readRemediationJournal as Ri,sweepExpiredRemediationJournals as _i,writeRemediationJournal as mi,REMEDIATION_JOURNAL_RETENTION_DAYS as ui,captureRemediationForensics as di,defaultRemediationForensicsDir as Pi,applyRetainFlip as Oi,composeFlipCapabilities as Di,computeTemplateDigest as fi,deriveRetainFlipTemplate as Ci,findMarkedResourcesByOpId as Ni,proveFlipMetadataOnly as gi,readRetainFlipState as Li,verifyRetainFlipDiff as Ii,FORGET_MARKER_KEY as yi,FORGET_FLIP_SPEC as hi,RECREATE_MARKER_KEY as vi,assessForgetResumability as xi,completeForgetAfterConverge as Fi,completeForgetAfterDeploy as Mi,formatRecreateInFlightCures as Ui,partitionPreFlightByRemediation as ki,runForgetSurgery as bi,synthTemplateDeclaresResource as Vi,runRecreateSurgery as Yi,snapshotPolicyForType as Bi,SNAPSHOT_CAPABLE_RESOURCE_TYPES as Gi,runRecreatePreFlight as Ki,deriveRemovalTemplate as Xi,findRemovalDeletionFailures as Hi,findResourcesPresent as Ji,proveRemovalTargetsOnly as wi,advertisableDriftVerbs as ji,buildDriftRepairTicket as Qi,runDriftRepairGate as Wi,formatPinOutcomeDetail as qi,pinProbeCoverage as Zi,renderPinReportLines as zi,runPinRemediation as $i,composePostFailureRepairOffer as ea,formatDriftRepairOffer as ra,DriftRepairAvailableError as ta,checkDeployPathStackAvailability as oa,isDeployPathBlockingStatus as ia,StackUnavailableError as aa,assertLeaseBeforeStack as sa,LeaseDeniedError as na}from"./orchestration/index.js";import{unlockBucket as Ea,unlockQueue as Sa}from"./orchestration/index.js";import{triageBucketPolicy as pa,isEnforceSslStatement as Ta,toResourcePolicyStatements as Aa,restoreBucketPolicy as Ra,synthesiseEnforceSslDocument as _a,ensureEnforceSsl as ma,restoreAndReconcileQuarantinedBucket as ua}from"./orchestration/index.js";import{verifyOrgTrailDelivery as Pa}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as Da,isRootTaskPolicyArn as fa,ROOT_TASK_POLICY_ARNS as Ca,MAX_ROOT_SESSION_SECONDS as Na}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as La,flattenAccountsToEnvironments as Ia,extractAllAccountNames as ya,accountsConfigToOUTree as ha,isStringArray as va,isAccountsConfig as xa,isOuOnlyAccountBucket as Fa,OU_ONLY_ACCOUNT_BUCKETS as Ma}from"./orchestration/index.js";import{runOpenNextBuild as ka}from"./orchestration/index.js";import{runOrganisationSetup as Va,ORG_SETUP_PHASES as Ya}from"./orchestration/index.js";import{resolveBuildSecrets as Ga,resolveSecretRefValue as Ka,resolveBuildSecretSessionProvider as Xa,sourcedRefsFromBuildArgs as Ha,resolveBuildArgs as Ja,buildBuildSecretSessionPolicy as wa,buildDeploySessionPolicy as ja,partitionForRegion as Qa,validateBuildGroup as Wa}from"./orchestration/index.js";import{FrameworkRegistry as Za}from"./orchestration/index.js";import{openNextBuilder as $a,staticSiteBuilder as es,dockerBuilder as rs}from"./orchestration/index.js";import{StepRegistry as os,getDestroyStepId as is}from"./steps/index.js";import{buildDeployPlan as ss,computeDeployPlan as ns,computeAssemblyDigest as cs,digestHead as Es,classifyImpact as Ss,derivePropertyChanges as ls,isDataLoss as ps,isStatefulResourceType as Ts,renderPlanSummary as As,renderPlanLines as Rs,toWirePlanChanges as _s,signApprovalToken as ms,verifyApprovalToken as us,DEFAULT_APPROVAL_TTL_MS as ds,APPROVAL_TOKEN_PATTERN as Ps,runApprovalGate as Os}from"./orchestration/index.js";import{runDestructionGate as fs,buildDestructionTicket as Cs,evaluateDestructionConsents as Ns,computeTicketDigest as gs,legalRemediationVerbs as Ls,executableRemediationVerbs as Is,advertisableRemediationVerbs as ys,renderDestructionTicketLines as hs,renderConsentVerdictLines as vs,loadDeployPlan as xs,createMemoisedPlanLoader as Fs}from"./orchestration/index.js";export{X as ALL_PROGRESS_KINDS,Pr as APPLICATION_DEPLOY_ORDER,Or as APPLICATION_DESTROY_ORDER,ur as APPLICATION_STACKS,K as APPROVAL_DECISIONS,G as APPROVAL_KINDS,Ps as APPROVAL_TOKEN_PATTERN,Qr as ApplicationError,kt as ApplicationStackService,Kt as AuthError,Xt as AwsError,b as BUILDERS,Bt as BaseServiceError,F as CASCADE_ACCOUNT_PHASES,E as CASCADE_ACCOUNT_STATUSES,V as CASCADE_OUTCOME_RESULTS,c as CASCADE_PHASES,wr as CDK_NO_STACKS_MATCH,qe as CONSENT_VERDICTS,pt as CdkArgumentBuilder,ht as CdkContextBuilder,Vt as CdkError,At as CdkEventMonitor,Tt as CdkProcessManager,lt as CdkService,_ as ChangeCountsSchema,Ct as CloudFormationError,Et as CloudFormationEventMonitor,ft as CloudFormationService,jt as ConfigError,ds as DEFAULT_APPROVAL_TTL_MS,_t as DEFAULT_DEPLOY_TIMEOUT_MS,Le as DEFAULT_MAX_PAGES,s as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,i as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,a as DEPLOYMENT_EVENT_STATUS_REASON_MAX,n as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,o as DEPLOYMENT_EVENT_TYPES,I as DEPLOY_EVENT_ARN_MAX,m as DEPLOY_EVENT_CONTRACT,u as DEPLOY_EVENT_CONTRACT_MAJOR,d as DEPLOY_EVENT_CONTRACT_MINOR,N as DEPLOY_EVENT_ERROR_MESSAGE_MAX,O as DEPLOY_EVENT_ID_MAX,f as DEPLOY_EVENT_MESSAGE_MAX,D as DEPLOY_EVENT_NAME_MAX,L as DEPLOY_EVENT_OUTPUT_MAX,C as DEPLOY_EVENT_STATUS_REASON_MAX,g as DEPLOY_EVENT_TRAIL_DETAIL_MAX,y as DEPLOY_EVENT_URL_MAX,M as DEPLOY_RESULTS,We as DESTRUCTION_FINDINGS,U as DETECTION_PHASES,ni as DRIFT_PREFLIGHT_BUDGET_MS,si as DRIFT_PREFLIGHT_TRIGGER_STATUSES,er as DRIFT_VERDICTS,l as DeployEventSchema,to as DeployModeSchema,T as DeployResourceSchema,Ht as DeploymentError,t as DeploymentEventSchema,je as DestructionConsentSchema,He as DestructionFindingSchema,Qe as DestructionOutcomeSchema,Je as DestructionTicketResourceSchema,we as DestructionTicketSchema,or as DriftFindingSchema,ir as DriftJournalRecordSchema,zo as DriftProbe,ta as DriftRepairAvailableError,tr as DriftSuspectSchema,rr as DriftVerdictSchema,gt as EcsError,Nt as EcsService,Lt as EcsServiceResolver,hi as FORGET_FLIP_SPEC,yi as FORGET_MARKER_KEY,wt as FileSystemError,et as FjallStateFileSchema,Za as FrameworkRegistry,Ie as IDENTITY_STORE_PAGE_SIZE,jr as INFRASTRUCTURE_FILENAME,Ye as INFRASTRUCTURE_STEP_NAMES,Be as INFRA_STEP_NAME,v as LOG_LEVELS,na as LeaseDeniedError,Na as MAX_ROOT_SESSION_SECONDS,Jt as NetworkError,Dr as OPENNEXT_DEPLOY_ORDER,fr as OPENNEXT_DESTROY_ORDER,gr as OPENNEXT_PARALLEL_GROUPS,Xr as OPENNEXT_PATTERNS,dr as ORGANISATION_TYPES,Ya as ORG_SETUP_PHASES,wo as ORG_TRAIL_BUCKET_OUTPUT_KEY,Ma as OU_ONLY_ACCOUNT_BUCKETS,Cr as PARALLEL_DEPLOY_GROUPS,Nr as PARALLEL_DESTROY_GROUPS,Lr as PARALLEL_OPERATION_TYPES,k as PHASE_STATUSES,Y as PLAN_ACTIONS,xt as PROGRESS_MESSAGES,A as PlanChangeSchema,R as PlanPropertyChangeSchema,mr as ProgressReporter,vi as RECREATE_MARKER_KEY,ui as REMEDIATION_JOURNAL_RETENTION_DAYS,nr as REMEDIATION_PHASES,Xe as REMEDIATION_VERB_GLOSS,B as REPLACEMENT_MODES,Me as ROOT_ACCESS_FEATURES,Ca as ROOT_TASK_POLICY_ARNS,Sr as RemediationFlipProofSchema,lr as RemediationJournalRecordSchema,cr as RemediationPhaseSchema,Er as RemediationTargetSchema,Ke as RemediationVerbSchema,pr as RemediationVerbWithSurgerySchema,Ue as RootAccessEnablementError,xe as SECURITY_SERVICE_PRINCIPALS,Ee as SERVICE_PRINCIPALS,Gi as SNAPSHOT_CAPABLE_RESOURCE_TYPES,x as STACK_CLEANUP_PHASES,Jr as STACK_FAILED_STATE_PATTERN,Hr as STACK_NOT_FOUND_PATTERN,h as STEP_COMPLETE_STATUSES,be as STEP_IDS,Ve as STEP_NAMES,P as SUPPORTED_CONTRACT_MARKERS,oo as ServiceArtefactSchema,io as ServiceArtefactsSchema,Q as SimpleAwsProvider,aa as StackUnavailableError,p as StepProgressSchema,os as StepRegistry,Ze as TICKET_VERDICT_SOURCES,jo as TRAIL_BUCKET_OUTPUT_KEY,Qo as TRAIL_KEY_ARN_OUTPUT_KEY,yt as TemplateHashError,It as TemplateHashService,ze as TicketVerdictSourceSchema,Gt as ValidationError,ha as accountsConfigToOUTree,Oe as activateCostAllocationTags,le as activateTrustedAccess,ji as advertisableDriftVerbs,ys as advertisableRemediationVerbs,Oi as applyRetainFlip,Ei as archiveCompletedRemediationJournal,ro as artefactOutputKey,sa as assertLeaseBeforeStack,xi as assessForgetResumability,Da as assumeRootForTask,Fo as buildAccountRegionPairs,de as buildAccountToOUMap,wa as buildBuildSecretSessionPolicy,ss as buildDeployPlan,ja as buildDeploySessionPolicy,Cs as buildDestructionTicket,Qi as buildDriftRepairTicket,xo as buildRegionList,Mt as buildStepContextBuildConfig,$ as buildTargetSetUnreadyAdvisory,z as buildTargetUnreadyAdvisory,di as captureRemediationForensics,Mo as cascadeHomeRegion,Uo as cascadeOperationKey,oa as checkDeployPathStackAvailability,De as checkIdentityCentreStatus,te as checkRegionEnabled,q as checkTargetReadiness,qo as classifyDriftFailure,Ss as classifyImpact,$o as clearDriftSuspects,Fi as completeForgetAfterConverge,Mi as completeForgetAfterDeploy,Di as composeFlipCapabilities,ea as composePostFailureRepairOffer,Ce as composeSdkAbortSignal,cs as computeAssemblyDigest,ns as computeDeployPlan,Si as computeRemediationOpId,go as computeSecretsDrift,fi as computeTemplateDigest,gs as computeTicketDigest,Ut as convertCloudFormationOutputsToRecord,_e as createAccount,H as createDeployEmitter,ot as createEmptyState,Fs as createMemoisedPlanLoader,So as createSequencedCallbacks,Xo as decideNextTransition,Jo as decommissionMemberTrailStorage,ei as defaultDriftJournalDir,Pi as defaultRemediationForensicsDir,li as defaultRemediationJournalDir,it as deleteStateFile,Po as deploy,ls as derivePropertyChanges,Xi as deriveRemovalTemplate,zr as deriveResourcesFromManifestStacks,Ci as deriveRetainFlipTemplate,Lo as deriveStaleParameters,se as describeOrganisation,Z as describeTargetReadinessReason,Do as destroy,oi as detectStackDrift,Es as digestHead,rs as dockerBuilder,ye as drainPages,vt as emitProgress,Fe as enableCentralisedRootAccess,pe as enableIpamDelegatedAdmin,ne as enablePolicyTypes,Se as enableRamSharing,ce as enableServiceAccess,ma as ensureEnforceSsl,ae as ensureOrganisationExists,me as ensureOrganisationalUnitsExist,Ns as evaluateDestructionConsents,Is as executableRemediationVerbs,ya as extractAllAccountNames,Io as extractConsumedSsmParameters,Ne as extractErrorName,Ro as failure,Zo as fetchLastOperationEvents,po as fileExists,qt as filterDangerousEnvVars,Re as findAccount,Pe as findDevelopmentOuId,Ni as findMarkedResourcesByOpId,pi as findRemediationJournalByOpId,Hi as findRemovalDeletionFailures,Ji as findResourcesPresent,Ia as flattenAccountsToEnvironments,ai as formatDriftPreFlightBlock,ra as formatDriftRepairOffer,ut as formatInfrastructureError,qi as formatPinOutcomeDetail,Ui as formatRecreateInFlightCures,xr as getApplicationDeployOrder,Fr as getApplicationDestroyOrder,Mr as getApplicationStackName,Br as getApplicationStepId,Yr as getApplicationStepName,is as getDestroyStepId,Ur as getOrganisationStackName,hr as getParallelDeployGroups,vr as getParallelDestroyGroups,Pt as getSourceContext,st as getStateFilePath,dt as getStructuralHint,Ot as hasCdkDifferences,so as hasDockerfile,ge as isAborted,xa as isAccountsConfig,Ir as isApplicationOperation,kr as isApplicationStack,mt as isCdkError,ps as isDataLoss,ia as isDeployPathBlockingStatus,Ta as isEnforceSslStatement,mo as isFailure,he as isOULeaf,Kr as isOpenNextPattern,yr as isOrganisationOperation,Fa as isOuOnlyAccountBucket,br as isQuarantineDetail,Rr as isRemediationPlaceholderPhysicalId,Vr as isRetainedBucketsDetail,fa as isRootTaskPolicyArn,Ts as isStatefulResourceType,va as isStringArray,_o as isSuccess,Ls as legalRemediationVerbs,Ae as listAccounts,Ti as listActiveRemediationOps,Ai as listActiveRemediationOpsForContext,xs as loadDeployPlan,Zt as maskSensitiveOutput,Go as mergeReconciledProviderAccounts,$a as openNextBuilder,La as parseAccountsConfiguration,Ft as parseBuildPhase,w as parseDeployContractVersion,J as parseDeployEvent,Dt as parseDiffOutput,zt as parseShellArgs,ho as partitionAccounts,Qa as partitionForRegion,ki as partitionPreFlightByRemediation,Zi as pinProbeCoverage,ue as placeAccountsInOUs,ee as probeAccountStackExists,No as probeSecretsDrift,Vo as projectAccountRows,bo as projectScalarSummary,gi as proveFlipMetadataOnly,wi as proveRemovalTargetsOnly,ri as readDriftSuspects,Ri as readRemediationJournal,Li as readRetainFlipState,rt as readStateFile,Bo as reconcileProviderAccounts,Ho as reconcileTrailMigration,ti as recordDriftSuspects,oe as regionDisabledMessage,nt as regionSuffix,ve as registerSecurityDelegates,Tr as remediationPhaseRank,Ar as remediationPlaceholderPhysicalId,vs as renderConsentVerdictLines,hs as renderDestructionTicketLines,zi as renderPinReportLines,Rs as renderPlanLines,As as renderPlanSummary,Ja as resolveBuildArgs,Xa as resolveBuildSecretSessionProvider,Ga as resolveBuildSecrets,Ka as resolveSecretRefValue,Co as restart,ua as restoreAndReconcileQuarantinedBucket,Ra as restoreBucketPolicy,Os as runApprovalGate,fs as runDestructionGate,ii as runDriftPreFlight,Wi as runDriftRepairGate,bi as runForgetSurgery,ka as runOpenNextBuild,Va as runOrganisationSetup,$i as runPinRemediation,Ki as runRecreatePreFlight,Yi as runRecreateSurgery,ms as signApprovalToken,$t as sleep,co as sleepAbortable,fe as snapshotIdentityCentre,Bi as snapshotPolicyForType,Ha as sourcedRefsFromBuildArgs,Rt as startStackMonitoring,es as staticSiteBuilder,qr as stubCallerIdentity,Ao as success,_i as sweepExpiredRemediationJournals,Vi as synthTemplateDeclaresResource,_a as synthesiseEnforceSslDocument,Gr as toPascalCase,Aa as toResourcePolicyStatements,Qt as toServiceError,_s as toWirePlanChanges,pa as triageBucketPolicy,Ea as unlockBucket,Sa as unlockQueue,Te as updateBackupGlobalSettings,at as updateTemplateHash,Wa as validateBuildGroup,ar as verbsForDriftVerdict,us as verifyApprovalToken,Pa as verifyOrgTrailDelivery,Ii as verifyRetainFlipDiff,Wr as wrapApplicationError,mi as writeRemediationJournal,tt as writeStateFile};
@@ -24,7 +24,7 @@ export declare class StackUnavailableError extends BaseServiceError {
24
24
  * Uses the canonical stackStatusMap to determine whether a status
25
25
  * is blocking — specifically `safeToRedeploy === "No"`.
26
26
  */
27
- export declare function checkActiveDeployments(stackNames: string[], cfnService: CloudFormationService): Promise<Result<void>>;
27
+ export declare function checkActiveDeployments(stackNames: string[], cfnService: CloudFormationService, abortSignal?: AbortSignal): Promise<Result<void>>;
28
28
  /**
29
29
  * Deploy-path blocking classification (P0.5). Deliberately stricter than the
30
30
  * destroy guard's `safeToRedeploy === "No"` check:
@@ -1,9 +1,9 @@
1
- import{success as u,failure as c}from"@fjall/generator";import{stackStatusMap as l}from"../aws/utils/stackStatus.js";import{BaseServiceError as f}from"../types/errors/ServiceError.js";class p extends f{stacks;constructor(r,o){super("STACK_UNAVAILABLE",r),this.stacks=o}}async function E(t,r){if(t.length===0)return u(void 0);const o=await Promise.all(t.map(async n=>{const e=await r.getStackStatus(n);return{name:n,result:e}})),a=[];for(const{name:n,result:e}of o){if(!e.success)return c(e.error);const s=e.data;if(s===null||s.status==="DOES_NOT_EXIST")continue;l[s.status]?.safeToRedeploy==="No"&&a.push({name:n,status:s.status})}if(a.length>0){const n=a.map(e=>` ${e.name}: ${e.status}`).join(`
1
+ import{success as u,failure as c}from"@fjall/generator";import{stackStatusMap as l}from"../aws/utils/stackStatus.js";import{BaseServiceError as f}from"../types/errors/ServiceError.js";class d extends f{stacks;constructor(r,o){super("STACK_UNAVAILABLE",r),this.stacks=o}}async function y(t,r,o){if(t.length===0)return u(void 0);const i=await Promise.all(t.map(async n=>{const e=await r.getStackStatus(n,void 0,o);return{name:n,result:e}})),a=[];for(const{name:n,result:e}of i){if(!e.success)return c(e.error);const s=e.data;if(s===null||s.status==="DOES_NOT_EXIST")continue;l[s.status]?.safeToRedeploy==="No"&&a.push({name:n,status:s.status})}if(a.length>0){const n=a.map(e=>` ${e.name}: ${e.status}`).join(`
2
2
  `);return c(new Error(`Cannot proceed while stacks are busy:
3
3
  ${n}
4
4
 
5
- Wait for the in-progress operation to complete, or use --force to override.`))}return u(void 0)}function d(t){return t==="REVIEW_IN_PROGRESS"?!1:t.endsWith("_IN_PROGRESS")||t==="DELETE_FAILED"?!0:l[t]===void 0||t==="UNKNOWN"}function S(t){const r=t.map(a=>` ${a.name}: ${a.status}`).join(`
5
+ Wait for the in-progress operation to complete, or use --force to override.`))}return u(void 0)}function p(t){return t==="REVIEW_IN_PROGRESS"?!1:t.endsWith("_IN_PROGRESS")||t==="DELETE_FAILED"?!0:l[t]===void 0||t==="UNKNOWN"}function S(t){const r=t.map(i=>` ${i.name}: ${i.status}`).join(`
6
6
  `);return`Cannot start this deployment \u2014 ${t.length===1?"a CloudFormation stack is not available":"CloudFormation stacks are not available"}:
7
7
  ${r}
8
8
 
9
- Another operation may be in progress or need attention. Wait for it to finish, then retry. Check progress in the Fjall dashboard.`}async function y(t,r,o){if(t.length===0)return u(void 0);const a=await Promise.all(t.map(async e=>{const s=await r.getStackStatus(e,void 0,o);return{name:e,result:s}})),n=[];for(const{name:e,result:s}of a){if(!s.success)return c(s.error);const i=s.data;i===null||i.status==="DOES_NOT_EXIST"||d(i.status)&&n.push({name:e,status:i.status})}return n.length>0?c(new p(S(n),n)):u(void 0)}export{p as StackUnavailableError,E as checkActiveDeployments,y as checkDeployPathStackAvailability,d as isDeployPathBlockingStatus};
9
+ Another operation may be in progress or need attention. Wait for it to finish, then retry. Check progress in the Fjall dashboard.`}async function b(t,r,o){if(t.length===0)return u(void 0);const i=await Promise.all(t.map(async n=>{const e=await r.getStackStatus(n,void 0,o);return{name:n,result:e}})),a=[];for(const{name:n,result:e}of i){if(!e.success)return c(e.error);const s=e.data;s===null||s.status==="DOES_NOT_EXIST"||p(s.status)&&a.push({name:n,status:s.status})}return a.length>0?c(new d(S(a),a)):u(void 0)}export{d as StackUnavailableError,y as checkActiveDeployments,b as checkDeployPathStackAvailability,p as isDeployPathBlockingStatus};
@@ -1 +1 @@
1
- import{join as z}from"path";import{CloudFormationClient as Se}from"@aws-sdk/client-cloudformation";import{EC2Client as be}from"@aws-sdk/client-ec2";import{success as D,failure as d}from"@fjall/generator";import{logger as M}from"@fjall/util/logger";import{ImageTagSchema as we,getErrorMessage as ce,imageTagParameterName as Te,maskSensitiveOutput as S}from"@fjall/util";import{parseDockerServicesFromManifest as Ee,parseLambdaDockerEntriesFromManifest as Ne}from"@fjall/util/manifest";import{stubCallerIdentity as Pe}from"../../types/deployment/index.js";import{getApplicationDeployOrder as De,getApplicationStackName as C,getApplicationStepName as le,getApplicationStepId as de,APPLICATION_STACKS as P}from"../../types/operations.js";import{CdkContextBuilder as ve}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as Re,bootstrapOrFail as Ce}from"../contextHelpers.js";import{runDetectionPipeline as Ie}from"./detectionPipeline.js";import{STEP_IDS as G,STEP_NAMES as Oe}from"../../types/stepDefinitions.js";import{StepRegistry as Ae}from"../../steps/stepRegistry.js";import{checkTargetReadiness as Le}from"../../aws/targetReadiness.js";import{cascadeHomeRegion as Me}from"../organisation/cascadeHelpers.js";import{withStepLifecycle as Fe}from"../stepLifecycle.js";import{DOCKER_BUILD_STEP_NAME as ue,runDockerBuild as $e}from"./dockerBuildHelper.js";import{getParallelPhase2Stacks as Be,getStackNamesToDeploy as xe,deployParallelPhase as je,deployStackSequential as Ge,runDockerPreCompute as Ue,runLambdaVersionPublish as _e,createBuildCallbacks as He}from"./applicationDeployHelpers.js";import{captureDatabaseConnectionOutputs as Ke,captureServiceTaskDefinitions as We,reconcileDatabaseEndpointChange as qe}from"./databaseEndpointReconcile.js";import{deployCodeOnly as Ve}from"./codeOnlyDeploy.js";import{checkDeployPathStackAvailability as ge}from"../activeDeploymentGuard.js";import{assertLeaseBeforeStack as U}from"./leaseGate.js";import{collectFullDeployArtefacts as ze}from"./artefactCollection.js";import{CfnRegistryService as Je}from"../../services/infrastructure/CfnRegistryService.js";import{ChangeSetProbe as Ye}from"../../services/infrastructure/changeSetProbe.js";import{runApprovalGate as Qe}from"./approvalGate.js";import{buildDestructionTicket as Xe,runDestructionGate as Ze}from"./destructionGate.js";import{DESTRUCTION_RESUME_TTL_MS as et,signApprovalToken as tt}from"./plan/approvalToken.js";import{computeAssemblyDigest as rt}from"./plan/assemblyDigest.js";import{createMemoisedPlanLoader as at}from"./plan/loadDeployPlan.js";import{runDriftPreFlightGate as nt}from"../drift/preFlightGate.js";import{completeForgetAfterDeploy as ot}from"../remediation/forgetResource.js";import{composePostFailureRepairOffer as pe}from"../remediation/postFailureRepairOffer.js";import{renderPinReportLines as it,runPinRemediation as st}from"../remediation/pinRemediation.js";import{runRecreatePreFlight as ct}from"../remediation/recreatePreFlight.js";import{runRecreateSurgery as lt}from"../remediation/recreateResource.js";const F="applicationDeploy";function dt(e){const n=Object.entries(e);if(n.length===0)return;const a={};for(const[t,i]of n){const b=Te(t);a[b]=i}return a}function ut(e){if(e?.mode!==void 0&&e.mode!=="rollback"){if(e.imageTag)return d(new Error(`--image-tag requires rollback mode (explicit mode '${e.mode}' was supplied alongside an image tag)`));if(e.serviceImageTags)return d(new Error(`serviceImageTags requires rollback mode (explicit mode '${e.mode}' was supplied alongside serviceImageTags)`))}if(e?.mode==="rollback"){if(e.imageTag&&e.serviceImageTags)return d(new Error("rollback mode accepts exactly one of --image-tag or serviceImageTags \u2014 they are mutually exclusive"));if(!e.imageTag&&!e.serviceImageTags)return d(new Error("rollback mode requires --image-tag <tag> or serviceImageTags naming the image(s) to roll to"))}if(e?.serviceImageTags!==void 0){if(e.serviceName)return d(new Error("serviceImageTags already names its services \u2014 --service cannot be combined with it"));const n=Object.entries(e.serviceImageTags);if(n.length===0)return d(new Error("serviceImageTags must name at least one service"));for(const[a,t]of n){const i=we.safeParse(t);if(!i.success)return d(new Error(`serviceImageTags.${a} is not a valid image tag: ${i.error.message}`))}}return D(void 0)}function fe(e,n,a){if(e.onStackTargets===void 0||a.length===0)return;const t=n.awsProvider.getAccountId(),i=n.awsProvider.getRegion();e.onStackTargets(a.map(b=>({stackName:b,...t!==""?{accountId:t}:{},...i!==""?{region:i}:{}})))}async function Jt(e,n,a){const{callbacks:t,options:i}=e,b=Date.now(),$=i?.mode??(i?.imageTag||i?.serviceImageTags?"rollback":i?.deployOnly?"code-only":"full");if($==="restart"){const r=new Error('mode "restart" is not a deploy \u2014 call the restart() entry point (fjall rollout) instead');return t.onError?.(r),d(r)}const J=ut(i);if(!J.success){const r=S(J.error.message),o=new Error(r);return t.onError?.(o),d(o)}const B=ve.buildDeploymentContext({deployType:"application",target:a.appName,path:a.path,region:n.awsProvider.getRegion(),callerIdentity:Pe(n.awsProvider.getAccountId()),...Re({orgConfig:e.orgConfig,identity:e.identity,skipOidc:e.options?.skipOidc})},{verbose:i?.verbose,infraOnly:i?.infraOnly},e.orgConfig),w=n.frameworkRegistry.resolve({appPath:a.path});let x;const I=$==="rollback";if(w&&!I){x=w.builder.plan({appPath:a.path},w.detection);const r=He(t),o=await w.builder.build(a.path,x,r,{skipBuild:i?.skipBuild,infraOnly:i?.infraOnly,...e.abortSignal!==void 0&&{abortSignal:e.abortSignal}});if(!o.success){const s=new Error(S(o.error.message));return t.onError?.(s),d(s)}}if($==="code-only"||I){t.onLog?.(I?i?.serviceImageTags?`Rollback mode \u2014 rolling ${Object.keys(i.serviceImageTags).length} service(s) to their release-recorded image tags`:`Rollback mode \u2014 rolling to image tag ${i?.imageTag}`:"Deploy-only mode \u2014 skipping infrastructure pipeline","info");const r=z(a.path,"cdk.out"),o=Ee(r),s=Ne(r),g=o.length>0||s.length>0,c=w?.detection.hasDockerfile===!0,u=g||c;M.debug(F,"Deploy-only branch entered",{mode:$,imageTag:i?.imageTag,serviceImageTags:i?.serviceImageTags,appName:a.appName,appPath:a.path,cdkOutPath:r,dockerProviderAvailable:e.dockerProvider!==void 0,builderName:w?.builder.name,hasDockerfileFromManifest:g,hasDockerfileFromDisk:c,hasDockerfile:u,manifestDockerServiceCount:o.length,manifestDockerPaths:o.map(h=>h.docker.path),manifestLambdaDockerEntryCount:s.length}),!g&&!c&&t.onLog?.("No Dockerfile detected via manifest or appPath \u2014 skipping Docker build. If this app uses a cross-repo Dockerfile, ensure a full deploy has run first to populate cdk.out/fjall-manifest.json.","warn");const m=await ge([C(a.appName,P.COMPUTE)],n.cfnService,e.abortSignal);if(!m.success)return t.onError?.(m.error),d(m.error);fe(t,n,[C(a.appName,P.COMPUTE)]);let l={},k;if(!I&&e.dockerProvider!==void 0&&u){M.debug(F,"Running Docker build before code-only deploy",{source:g?"manifest":"disk"});const h=await $e(e,n,a,t);if(!h.success)return d(h.error);l=h.data.contentHashTagsByService,k=h.data}else M.debug(F,"Skipping Docker build",{reason:I?"rollback":e.dockerProvider===void 0?"no dockerProvider":"no Dockerfile detected"});const y=await U(e.assertLeaseForStack,C(a.appName,P.COMPUTE),e.abortSignal);return y!==void 0?(t.onError?.(y),d(y)):Ve(e,n,a,l,k)}t.onLog?.("Analysing infrastructure\u2026","info");const _=await Ie(a,n,B,t);if(!_.success){const r=new Error(S(_.error.message));return t.onError?.(r),d(r)}const f=_.data;try{await t.onDetectionComplete?.({...f,builderName:w?.builder.name??"unknown"})}catch(r){const o=new Error(S(ce(r)));return t.onError?.(o),d(o)}const me={deploymentType:"application",operation:"deploy",deployOnly:!1,infraOnly:i?.infraOnly??!1,hasDockerfile:f.hasDockerfile,pattern:f.pattern,resources:f.resources,...w&&{builderName:w.builder.name}},Y=Ae.getSteps(me),Q=Y.findIndex(r=>r.id===G.TARGET_READINESS),X=await Fe(t,{stepId:G.TARGET_READINESS,stepName:Oe.TARGET_READINESS,...Q>=0&&{stepIndex:Q,totalSteps:Y.length}},async()=>{if(i?.skipReadinessCheck)return t.onLog?.("Skipping target readiness check (--skip-readiness-check)","warn"),{kind:"skipped",data:void 0};const r=n.awsProvider.getAccountId(),o=e.orgConfig?.providerAccounts.find(u=>u.id===r)?.name,s=n.awsProvider.getCredentials(),g=Me(e.orgConfig),c=await Le({cloudFormation:n.awsProvider.getClient(Se),ec2:new be({region:g,...s!==void 0&&{credentials:s}})},{id:r,...o!==void 0&&{name:o}},n.awsProvider.getRegion(),e.orgConfig,e.abortSignal);return c.success?c.data.ready?{kind:"completed",data:void 0}:{kind:"error",error:new Error(S(c.data.advisory))}:{kind:"error",error:new Error(S(c.error.message))}},e.abortSignal);if(!X.success)return X;const T=x?x.deployOrder:De({pattern:f.pattern,resources:f.resources}),v=T.length,Z=f.hasDockerfile&&e.dockerProvider!==void 0&&T.includes(P.COMPUTE)&&i?.infraOnly!==!0;if(!f.hasDifferences&&!i?.force&&!Z){t.onLog?.("No infrastructure changes detected","info"),t.onLog?.(i?.infraOnly===!0?"Infrastructure-only mode \u2014 application code was not rebuilt. Run with --deploy-only to deploy code changes.":"Nothing to deploy. Run with --deploy-only to redeploy application code.","info");const r=f.hasDockerfile&&e.dockerProvider!==void 0&&T.includes(P.COMPUTE);for(let s=0;s<T.length;s++){const g=T[s];r&&g===P.COMPUTE&&(t.onStepStart?.(G.DOCKER_OPERATIONS,ue),t.onStepComplete?.(G.DOCKER_OPERATIONS,ue,"skipped"));const c=de(g,"deploy"),u=le(g,"deploy");t.onStepStart?.(c,u,s,v),t.onStepComplete?.(c,u,"skipped",s,v)}const o=await n.stackService.resolveWebsiteUrl(a.appName);return D({target:a.appName,deploymentType:"application",outputs:o?{websiteUrl:o}:void 0,noChanges:!0,artefacts:[],durationMs:Date.now()-b})}const H=z(a.path,"cdk.out"),N=xe({deployOrder:T,stackChanges:f.stackChanges,appName:a.appName,force:i?.force===!0,computeBuildPossible:Z});fe(t,n,[...N]);const K=await ge([...N],n.cfnService,e.abortSignal);if(!K.success)return t.onError?.(K.error),d(K.error);const ee=rt(f.currentHashes),W=at({cfnService:n.cfnService,cdkOutPath:H,changedStacks:[...N],assemblyDigest:ee,registry:new Je(n.awsProvider),changeSetProbe:new Ye(n.awsProvider),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}),q=await nt(n.awsProvider,{stackNames:[...N],cdkOutPath:H,cfnService:n.cfnService,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(q.kind==="blocked"){const r=new Error(q.message);return t.onError?.(r),d(r)}const te=q.verifiedAbsentByNecessity??[],re=e.approvalGate!==void 0||i?.approvalToken!==void 0&&i.approvalToken!==""||i?.planOnly===!0;if(re){const r=await Qe({approvalGate:e.approvalGate,options:i??{},target:a.appName,cdkOutPath:H,detection:{stackChanges:f.stackChanges,currentHashes:f.currentHashes},cfnService:n.cfnService,loadPlan:W,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!r.success)return r;const o=r.data;if(o.kind==="rejected")return t.onLog?.(`Deploy rejected: ${S(o.reason)}`,"warn"),D({target:a.appName,deploymentType:"application",rejected:!0,artefacts:[],...o.planDetail!==void 0?{planDetail:o.planDetail}:{},durationMs:Date.now()-b});if(o.kind==="awaiting"){const s=await W(),g=s.success?Xe(s.data,te):void 0;return D({target:a.appName,deploymentType:"application",awaitingApproval:!0,approvalToken:o.approvalToken,assemblyDigest:o.assemblyDigest,planDetail:o.planDetail,...g!==void 0?{destructionTicket:g}:{},artefacts:[],durationMs:Date.now()-b})}}const E=await Ze({loadPlan:W,options:i??{},target:a.appName,callbacks:t,verifiedAbsentByNecessity:te,...e.destructionConsentGate!==void 0?{consentGate:e.destructionConsentGate}:{}});if(!E.success)return t.onError?.(E.error),d(E.error);if(E.data.kind==="withheld"){const r=re?tt({assemblyDigest:ee,ttlMs:et}):void 0;return D({target:a.appName,deploymentType:"application",destructionPending:!0,destructionTicket:E.data.ticket,destructionOutcome:E.data.outcome,destructionHaltReasons:E.data.reasons,...r!==void 0?{destructionResumeToken:r.token,destructionResumeExpiresAt:r.expiresAt}:{},artefacts:[],durationMs:Date.now()-b})}if(E.data.kind==="proceed"){const{ticket:r,verbsByPhysicalName:o}=E.data,s=r.resources.filter(c=>o.get(c.physicalName)==="pin");if(s.length>0){t.onLog?.(`Pin remediation for ${a.appName}: probing live value(s) for ${s.length} consented pin(s) \u2014 deploy stopped for config write-back; nothing was applied`,"warn");const c=await st(n.awsProvider,{targets:s.map(u=>({stack:u.stack,logicalId:u.logicalId,resourceType:u.resourceType,physicalName:u.physicalName,offendingProperties:u.offendingProperties})),...e.infrastructureSource!==void 0?{infrastructureContent:e.infrastructureSource.content,infrastructureFilePath:e.infrastructureSource.filePath}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});for(const u of it(c))t.onLog?.(u,"warn");return s.length<r.resources.length&&t.onLog?.("Remaining consented change(s) were not applied \u2014 the config write-back changes the plan, so they re-consent on the next deploy","warn"),D({target:a.appName,deploymentType:"application",pinPending:!0,pinReport:c,pinDeferredConsents:r.resources.length-s.length,destructionTicket:r,artefacts:[],durationMs:Date.now()-b})}const g=r.resources.filter(c=>c.finding==="pinned-name-replacement"&&o.get(c.physicalName)==="recreate");if(g.length>0){const c=new Map;for(const l of g){const k=c.get(l.stack)??[];k.push(l),c.set(l.stack,k)}const u=await ct(n.awsProvider,{stacks:[...c].map(([l,k])=>({stackName:l,targets:k.map(y=>({logicalId:y.logicalId,resourceType:y.resourceType,physicalId:y.physicalName}))})),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!u.success){const l=new Error(S(u.error.message));return t.onError?.(l),d(l)}const m=[];for(const[l,k]of c){const y=await U(e.assertLeaseForStack,l,e.abortSignal,"destroy");if(y!==void 0)return m.length>0&&t.onLog?.(`Surgery already completed on ${m.join("; ")} \u2014 those resources were removed and re-running the deploy resumes their journals and re-creates them.`,"warn"),t.onError?.(y),d(y);const h=k.map(p=>p.physicalName);t.onLog?.(`Recreate remediation for ${a.appName}: orchestrating the pinned-name replacement of ${h.join(", ")} on ${l}`,"warn");const L=await lt(n.awsProvider,{stackName:l,targets:k.map(p=>({logicalId:p.logicalId,resourceType:p.resourceType,physicalId:p.physicalName})),appName:a.appName,consentedPhysicalNames:h,doneJournalPolicy:"archive-and-restart",plannedReplacementLogicalIds:k.map(p=>p.logicalId),onProgress:p=>t.onLog?.(p,"info"),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!L.success){const p=m.length>0?` Surgery already completed on ${m.join("; ")} \u2014 those resources were removed and re-running the deploy resumes their journals and re-creates them.`:"",j=new Error(S(`${L.error.message}${p}`));return t.onError?.(j),d(j)}m.push(`${l} (${h.join(", ")})`)}}}const ae=await Ce(n,B,t);if(!ae.success)return ae;const ne=C(a.appName,P.DATABASE),V=N.has(ne),ke=V?await Ke(n.cfnService,a.appName):void 0,ye=V?await We(n.ecsResolver,n.ecsService,a.appName):void 0,O={},A=new Map;let oe,ie={};const R=async()=>{!V||!A.has(ne)||await qe({appName:a.appName,connectionOutputsBefore:ke,serviceTaskDefinitionsBefore:ye,services:{cfnService:n.cfnService,ecsService:n.ecsService,ecsResolver:n.ecsResolver},callbacks:t,...e.confirmDatabaseEndpointRestart!==void 0?{confirmRestart:e.confirmDatabaseEndpointRestart}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})};for(let r=0;r<T.length;r++){const o=T[r],s=C(a.appName,o),g=de(o,"deploy"),c=le(o,"deploy");if(!N.has(s)){t.onStepStart?.(g,c,r,v),t.onLog?.(`Skipping ${o} \u2014 no changes detected`,"info"),t.onStepComplete?.(g,c,"skipped",r,v);continue}const u=await U(e.assertLeaseForStack,s,e.abortSignal);if(u!==void 0)return await R(),t.onError?.(u),d(u);const m=Be(T,r,a.appName,N);if(m.length>=2){const p=await je(m,a,n,B,t,r,v,f,O,A);if(!p.success)return await R(),d(await pe(n.awsProvider,{stackNames:m.map(j=>C(a.appName,j)),appName:a.appName,originalError:p.error,cfnService:n.cfnService,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}));r+=m.length-1;continue}const l=await Ue(o,e,n,a,t,f.hasDockerfile);if(l!==null&&!l.success)return await R(),d(l.error);l!==null&&l.success&&(oe=l.data);const k=l!==null&&l.success?l.data.contentHashTagsByService:{},y=dt(k);if(l!==null){const p=await U(e.assertLeaseForStack,s,e.abortSignal);if(p!==void 0)return await R(),t.onError?.(p),d(p)}const h=await Ge(o,n,B,t,r,v,O,y!==void 0?{parameters:y}:void 0);if(!h.success)return await R(),d(await pe(n.awsProvider,{stackNames:[s],appName:a.appName,originalError:h.error,cfnService:n.cfnService,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}));o===P.COMPUTE&&(ie=await _e(a,n,t,k));const L=f.currentHashes.get(s);L&&A.set(s,L)}if(await R(),A.size>0){const r=await n.hashService.updateStateAfterDeploy(a.path,A);if(!r.success){const o=S(r.error.message);M.debug(F,"Failed to update state file",{error:o}),t.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy unchanged stacks: ${o}`,"warn")}}const se=await n.stackService.resolveWebsiteUrl(a.appName);se&&(O.websiteUrl=se);const he=await ze(n,a.appName,oe,t,z(a.path,"cdk.out"),ie);return await ot(n.awsProvider,{stackNames:[...N],appName:a.appName,onLog:(r,o)=>t.onLog?.(r,o),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}).catch(r=>{M.debug(F,"Forget completion sweep failed",{error:S(ce(r))})}),D({target:a.appName,deploymentType:"application",outputs:Object.keys(O).length>0?O:void 0,artefacts:he,durationMs:Date.now()-b})}export{Jt as deployApplication,fe as emitStackTargets};
1
+ import{join as se}from"path";import{CloudFormationClient as he}from"@aws-sdk/client-cloudformation";import{EC2Client as be}from"@aws-sdk/client-ec2";import{success as P,failure as d}from"@fjall/generator";import{logger as M}from"@fjall/util/logger";import{ImageTagSchema as we,getErrorMessage as ce,imageTagParameterName as Te,maskSensitiveOutput as S}from"@fjall/util";import{parseDockerDeclarationsFromManifest as Ee}from"@fjall/util/manifest";import{stubCallerIdentity as Ne}from"../../types/deployment/index.js";import{getApplicationDeployOrder as Pe,getApplicationStackName as C,getApplicationStepName as le,getApplicationStepId as de,APPLICATION_STACKS as N}from"../../types/operations.js";import{CdkContextBuilder as De}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as ve,bootstrapOrFail as Re}from"../contextHelpers.js";import{runDetectionPipeline as Ce}from"./detectionPipeline.js";import{STEP_IDS as U,STEP_NAMES as Ie}from"../../types/stepDefinitions.js";import{StepRegistry as Oe}from"../../steps/stepRegistry.js";import{checkTargetReadiness as Ae}from"../../aws/targetReadiness.js";import{cascadeHomeRegion as Le}from"../organisation/cascadeHelpers.js";import{withStepLifecycle as Me}from"../stepLifecycle.js";import{DOCKER_BUILD_STEP_NAME as ue,runDockerBuild as Be}from"./dockerBuildHelper.js";import{getParallelPhase2Stacks as Fe,getStackNamesToDeploy as $e,deployParallelPhase as xe,deployStackSequential as je,runDockerPreCompute as Ge,runLambdaVersionPublish as Ue,createBuildCallbacks as _e}from"./applicationDeployHelpers.js";import{captureDatabaseConnectionOutputs as He,captureServiceTaskDefinitions as Ke,reconcileDatabaseEndpointChange as We}from"./databaseEndpointReconcile.js";import{deployCodeOnly as qe}from"./codeOnlyDeploy.js";import{checkDeployPathStackAvailability as ge}from"../activeDeploymentGuard.js";import{assertLeaseBeforeStack as _}from"./leaseGate.js";import{collectFullDeployArtefacts as Ve}from"./artefactCollection.js";import{CfnRegistryService as ze}from"../../services/infrastructure/CfnRegistryService.js";import{ChangeSetProbe as Je}from"../../services/infrastructure/changeSetProbe.js";import{runApprovalGate as Ye}from"./approvalGate.js";import{buildDestructionTicket as Qe,runDestructionGate as Xe}from"./destructionGate.js";import{DESTRUCTION_RESUME_TTL_MS as Ze,signApprovalToken as et}from"./plan/approvalToken.js";import{computeAssemblyDigest as tt}from"./plan/assemblyDigest.js";import{createMemoisedPlanLoader as rt}from"./plan/loadDeployPlan.js";import{runDriftPreFlightGate as at}from"../drift/preFlightGate.js";import{completeForgetAfterDeploy as nt}from"../remediation/forgetResource.js";import{composePostFailureRepairOffer as pe}from"../remediation/postFailureRepairOffer.js";import{renderPinReportLines as ot,runPinRemediation as it}from"../remediation/pinRemediation.js";import{runRecreatePreFlight as st}from"../remediation/recreatePreFlight.js";import{runRecreateSurgery as ct}from"../remediation/recreateResource.js";const B="applicationDeploy";function lt(e){const a=Object.entries(e);if(a.length===0)return;const n={};for(const[t,i]of a){const h=Te(t);n[h]=i}return n}function dt(e){if(e?.mode!==void 0&&e.mode!=="rollback"){if(e.imageTag)return d(new Error(`--image-tag requires rollback mode (explicit mode '${e.mode}' was supplied alongside an image tag)`));if(e.serviceImageTags)return d(new Error(`serviceImageTags requires rollback mode (explicit mode '${e.mode}' was supplied alongside serviceImageTags)`))}if(e?.mode==="rollback"){if(e.imageTag&&e.serviceImageTags)return d(new Error("rollback mode accepts exactly one of --image-tag or serviceImageTags \u2014 they are mutually exclusive"));if(!e.imageTag&&!e.serviceImageTags)return d(new Error("rollback mode requires --image-tag <tag> or serviceImageTags naming the image(s) to roll to"))}if(e?.serviceImageTags!==void 0){if(e.serviceName)return d(new Error("serviceImageTags already names its services \u2014 --service cannot be combined with it"));const a=Object.entries(e.serviceImageTags);if(a.length===0)return d(new Error("serviceImageTags must name at least one service"));for(const[n,t]of a){const i=we.safeParse(t);if(!i.success)return d(new Error(`serviceImageTags.${n} is not a valid image tag: ${i.error.message}`))}}return P(void 0)}function fe(e,a,n){if(e.onStackTargets===void 0||n.length===0)return;const t=a.awsProvider.getAccountId(),i=a.awsProvider.getRegion();e.onStackTargets(n.map(h=>({stackName:h,...t!==""?{accountId:t}:{},...i!==""?{region:i}:{}})))}async function zt(e,a,n){const{callbacks:t,options:i}=e,h=Date.now(),F=i?.mode??(i?.imageTag||i?.serviceImageTags?"rollback":i?.deployOnly?"code-only":"full");if(F==="restart"){const r=new Error('mode "restart" is not a deploy \u2014 call the restart() entry point (fjall rollout) instead');return t.onError?.(r),d(r)}const V=dt(i);if(!V.success){const r=S(V.error.message),o=new Error(r);return t.onError?.(o),d(o)}const $=De.buildDeploymentContext({deployType:"application",target:n.appName,path:n.path,region:a.awsProvider.getRegion(),callerIdentity:Ne(a.awsProvider.getAccountId()),...ve({orgConfig:e.orgConfig,identity:e.identity,skipOidc:e.options?.skipOidc})},{verbose:i?.verbose,infraOnly:i?.infraOnly},e.orgConfig),b=a.frameworkRegistry.resolve({appPath:n.path});let z;const I=F==="rollback";if(b&&!I){z=b.builder.plan({appPath:n.path},b.detection);const r=_e(t),o=await b.builder.build(n.path,z,r,{skipBuild:i?.skipBuild,infraOnly:i?.infraOnly,...e.abortSignal!==void 0&&{abortSignal:e.abortSignal}});if(!o.success){const s=new Error(S(o.error.message));return t.onError?.(s),d(s)}}if(F==="code-only"||I){t.onLog?.(I?i?.serviceImageTags?`Rollback mode \u2014 rolling ${Object.keys(i.serviceImageTags).length} service(s) to their release-recorded image tags`:`Rollback mode \u2014 rolling to image tag ${i?.imageTag}`:"Deploy-only mode \u2014 skipping infrastructure pipeline","info");const r=se(n.path,"cdk.out"),o=Ee(r),s=o.declaresBuild,g=b?.detection.hasDockerfile===!0,c=s||g;M.debug(B,"Deploy-only branch entered",{mode:F,imageTag:i?.imageTag,serviceImageTags:i?.serviceImageTags,appName:n.appName,appPath:n.path,cdkOutPath:r,dockerProviderAvailable:e.dockerProvider!==void 0,builderName:b?.builder.name,hasDockerfileFromManifest:s,hasDockerfileFromDisk:g,hasDockerfile:c,manifestDockerServiceCount:o.ecsServices.length,manifestDockerPaths:o.ecsServices.map(p=>p.docker.path),manifestLambdaDockerEntryCount:o.lambdaEntries.length}),!s&&!g&&t.onLog?.("No Dockerfile detected via manifest or appPath \u2014 skipping Docker build. If this app uses a cross-repo Dockerfile, ensure a full deploy has run first to populate cdk.out/fjall-manifest.json.","warn");const u=await ge([C(n.appName,N.COMPUTE)],a.cfnService,e.abortSignal);if(!u.success)return t.onError?.(u.error),d(u.error);fe(t,a,[C(n.appName,N.COMPUTE)]);let y={},l;if(!I&&e.dockerProvider!==void 0&&c){M.debug(B,"Running Docker build before code-only deploy",{source:s?"manifest":"disk"});const p=await Be(e,a,n,t);if(!p.success)return d(p.error);y=p.data.contentHashTagsByService,l=p.data}else M.debug(B,"Skipping Docker build",{reason:I?"rollback":e.dockerProvider===void 0?"no dockerProvider":"no Dockerfile detected"});const k=await _(e.assertLeaseForStack,C(n.appName,N.COMPUTE),e.abortSignal);return k!==void 0?(t.onError?.(k),d(k)):qe(e,a,n,y,l)}t.onLog?.("Analysing infrastructure\u2026","info");const x=await Ce(n,a,$,t,e.abortSignal);if(!x.success){const r=new Error(S(x.error.message),{cause:x.error});return t.onError?.(r),d(r)}const m=x.data;try{await t.onDetectionComplete?.({...m,builderName:b?.builder.name??"unknown"})}catch(r){const o=new Error(S(ce(r)),{cause:r});return t.onError?.(o),d(o)}const me={deploymentType:"application",operation:"deploy",deployOnly:!1,infraOnly:i?.infraOnly??!1,hasDockerfile:m.hasDockerfile,pattern:m.pattern,resources:m.resources,...b&&{builderName:b.builder.name}},J=Oe.getSteps(me),Y=J.findIndex(r=>r.id===U.TARGET_READINESS),Q=await Me(t,{stepId:U.TARGET_READINESS,stepName:Ie.TARGET_READINESS,...Y>=0&&{stepIndex:Y,totalSteps:J.length}},async()=>{if(i?.skipReadinessCheck)return t.onLog?.("Skipping target readiness check (--skip-readiness-check)","warn"),{kind:"skipped",data:void 0};const r=a.awsProvider.getAccountId(),o=e.orgConfig?.providerAccounts.find(u=>u.id===r)?.name,s=a.awsProvider.getCredentials(),g=Le(e.orgConfig),c=await Ae({cloudFormation:a.awsProvider.getClient(he),ec2:new be({region:g,...s!==void 0&&{credentials:s}})},{id:r,...o!==void 0&&{name:o}},a.awsProvider.getRegion(),e.orgConfig,e.abortSignal);return c.success?c.data.ready?{kind:"completed",data:void 0}:{kind:"error",error:new Error(S(c.data.advisory))}:{kind:"error",error:new Error(S(c.error.message),{cause:c.error})}},e.abortSignal);if(!Q.success)return Q;const w=Pe({pattern:m.pattern,resources:m.resources}),D=w.length,X=m.hasDockerfile&&e.dockerProvider!==void 0&&w.includes(N.COMPUTE)&&i?.infraOnly!==!0;if(!m.hasDifferences&&!i?.force&&!X){t.onLog?.("No infrastructure changes detected","info"),t.onLog?.(i?.infraOnly===!0?"Infrastructure-only mode \u2014 application code was not rebuilt. Run with --deploy-only to deploy code changes.":"Nothing to deploy. Run with --deploy-only to redeploy application code.","info");const r=m.hasDockerfile&&e.dockerProvider!==void 0&&w.includes(N.COMPUTE);for(let s=0;s<w.length;s++){const g=w[s];r&&g===N.COMPUTE&&(t.onStepStart?.(U.DOCKER_OPERATIONS,ue),t.onStepComplete?.(U.DOCKER_OPERATIONS,ue,"skipped"));const c=de(g,"deploy"),u=le(g,"deploy");t.onStepStart?.(c,u,s,D),t.onStepComplete?.(c,u,"skipped",s,D)}const o=await a.stackService.resolveWebsiteUrl(n.appName);return P({target:n.appName,deploymentType:"application",outputs:o?{websiteUrl:o}:void 0,noChanges:!0,artefacts:[],durationMs:Date.now()-h})}const j=se(n.path,"cdk.out"),E=$e({deployOrder:w,stackChanges:m.stackChanges,appName:n.appName,force:i?.force===!0,computeBuildPossible:X});fe(t,a,[...E]);const H=await ge([...E],a.cfnService,e.abortSignal);if(!H.success)return t.onError?.(H.error),d(H.error);const Z=tt(m.currentHashes),K=rt({cfnService:a.cfnService,cdkOutPath:j,changedStacks:[...E],assemblyDigest:Z,registry:new ze(a.awsProvider),changeSetProbe:new Je(a.awsProvider),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}),W=await at(a.awsProvider,{stackNames:[...E],cdkOutPath:j,cfnService:a.cfnService,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(W.kind==="blocked"){const r=new Error(W.message);return t.onError?.(r),d(r)}const ee=W.verifiedAbsentByNecessity??[],te=e.approvalGate!==void 0||i?.approvalToken!==void 0&&i.approvalToken!==""||i?.planOnly===!0;if(te){const r=await Ye({approvalGate:e.approvalGate,options:i??{},target:n.appName,cdkOutPath:j,detection:{stackChanges:m.stackChanges,currentHashes:m.currentHashes},cfnService:a.cfnService,loadPlan:K,callbacks:t,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!r.success)return r;const o=r.data;if(o.kind==="rejected")return t.onLog?.(`Deploy rejected: ${S(o.reason)}`,"warn"),P({target:n.appName,deploymentType:"application",rejected:!0,artefacts:[],...o.planDetail!==void 0?{planDetail:o.planDetail}:{},durationMs:Date.now()-h});if(o.kind==="awaiting"){const s=await K(),g=s.success?Qe(s.data,ee):void 0;return P({target:n.appName,deploymentType:"application",awaitingApproval:!0,approvalToken:o.approvalToken,assemblyDigest:o.assemblyDigest,planDetail:o.planDetail,...g!==void 0?{destructionTicket:g}:{},artefacts:[],durationMs:Date.now()-h})}}const T=await Xe({loadPlan:K,options:i??{},target:n.appName,callbacks:t,verifiedAbsentByNecessity:ee,...e.destructionConsentGate!==void 0?{consentGate:e.destructionConsentGate}:{}});if(!T.success)return t.onError?.(T.error),d(T.error);if(T.data.kind==="withheld"){const r=te?et({assemblyDigest:Z,ttlMs:Ze}):void 0;return P({target:n.appName,deploymentType:"application",destructionPending:!0,destructionTicket:T.data.ticket,destructionOutcome:T.data.outcome,destructionHaltReasons:T.data.reasons,...r!==void 0?{destructionResumeToken:r.token,destructionResumeExpiresAt:r.expiresAt}:{},artefacts:[],durationMs:Date.now()-h})}if(T.data.kind==="proceed"){const{ticket:r,verbsByPhysicalName:o}=T.data,s=r.resources.filter(c=>o.get(c.physicalName)==="pin");if(s.length>0){t.onLog?.(`Pin remediation for ${n.appName}: probing live value(s) for ${s.length} consented pin(s) \u2014 deploy stopped for config write-back; nothing was applied`,"warn");const c=await it(a.awsProvider,{targets:s.map(u=>({stack:u.stack,logicalId:u.logicalId,resourceType:u.resourceType,physicalName:u.physicalName,offendingProperties:u.offendingProperties})),...e.infrastructureSource!==void 0?{infrastructureContent:e.infrastructureSource.content,infrastructureFilePath:e.infrastructureSource.filePath}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});for(const u of ot(c))t.onLog?.(u,"warn");return s.length<r.resources.length&&t.onLog?.("Remaining consented change(s) were not applied \u2014 the config write-back changes the plan, so they re-consent on the next deploy","warn"),P({target:n.appName,deploymentType:"application",pinPending:!0,pinReport:c,pinDeferredConsents:r.resources.length-s.length,destructionTicket:r,artefacts:[],durationMs:Date.now()-h})}const g=r.resources.filter(c=>c.finding==="pinned-name-replacement"&&o.get(c.physicalName)==="recreate");if(g.length>0){const c=new Map;for(const l of g){const k=c.get(l.stack)??[];k.push(l),c.set(l.stack,k)}const u=await st(a.awsProvider,{stacks:[...c].map(([l,k])=>({stackName:l,targets:k.map(p=>({logicalId:p.logicalId,resourceType:p.resourceType,physicalId:p.physicalName}))})),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!u.success){const l=new Error(S(u.error.message),{cause:u.error});return t.onError?.(l),d(l)}const y=[];for(const[l,k]of c){const p=await _(e.assertLeaseForStack,l,e.abortSignal,"destroy");if(p!==void 0)return y.length>0&&t.onLog?.(`Surgery already completed on ${y.join("; ")} \u2014 those resources were removed and re-running the deploy resumes their journals and re-creates them.`,"warn"),t.onError?.(p),d(p);const R=k.map(f=>f.physicalName);t.onLog?.(`Recreate remediation for ${n.appName}: orchestrating the pinned-name replacement of ${R.join(", ")} on ${l}`,"warn");const L=await ct(a.awsProvider,{stackName:l,targets:k.map(f=>({logicalId:f.logicalId,resourceType:f.resourceType,physicalId:f.physicalName})),appName:n.appName,consentedPhysicalNames:R,doneJournalPolicy:"archive-and-restart",plannedReplacementLogicalIds:k.map(f=>f.logicalId),onProgress:f=>t.onLog?.(f,"info"),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}});if(!L.success){const f=y.length>0?` Surgery already completed on ${y.join("; ")} \u2014 those resources were removed and re-running the deploy resumes their journals and re-creates them.`:"",G=new Error(S(`${L.error.message}${f}`));return t.onError?.(G),d(G)}y.push(`${l} (${R.join(", ")})`)}}}const re=await Re(a,$,t);if(!re.success)return re;const ae=C(n.appName,N.DATABASE),q=E.has(ae),ke=q?await He(a.cfnService,n.appName,e.abortSignal):void 0,ye=q?await Ke(a.ecsResolver,a.ecsService,n.appName,e.abortSignal):void 0,O={},A=new Map;let ne,oe={};const v=async()=>{!q||!A.has(ae)||await We({appName:n.appName,connectionOutputsBefore:ke,serviceTaskDefinitionsBefore:ye,services:{cfnService:a.cfnService,ecsService:a.ecsService,ecsResolver:a.ecsResolver},callbacks:t,...e.confirmDatabaseEndpointRestart!==void 0?{confirmRestart:e.confirmDatabaseEndpointRestart}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}})};for(let r=0;r<w.length;r++){const o=w[r],s=C(n.appName,o),g=de(o,"deploy"),c=le(o,"deploy");if(!E.has(s)){t.onStepStart?.(g,c,r,D),t.onLog?.(`Skipping ${o} \u2014 no changes detected`,"info"),t.onStepComplete?.(g,c,"skipped",r,D);continue}const u=await _(e.assertLeaseForStack,s,e.abortSignal);if(u!==void 0)return await v(),t.onError?.(u),d(u);const y=Fe(w,r,n.appName,E);if(y.length>=2){const f=await xe(y,n,a,$,t,r,D,m,O,A);if(!f.success)return await v(),d(await pe(a.awsProvider,{stackNames:y.map(G=>C(n.appName,G)),appName:n.appName,originalError:f.error,cfnService:a.cfnService,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}));r+=y.length-1;continue}const l=await Ge(o,e,a,n,t,m.hasDockerfile);if(l!==null&&!l.success)return await v(),d(l.error);l!==null&&l.success&&(ne=l.data);const k=l!==null&&l.success?l.data.contentHashTagsByService:{},p=lt(k);if(l!==null){const f=await _(e.assertLeaseForStack,s,e.abortSignal);if(f!==void 0)return await v(),t.onError?.(f),d(f)}const R=await je(o,a,$,t,r,D,O,p!==void 0||e.abortSignal!==void 0?{...p!==void 0?{parameters:p}:{},...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}:void 0);if(!R.success)return await v(),d(await pe(a.awsProvider,{stackNames:[s],appName:n.appName,originalError:R.error,cfnService:a.cfnService,...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}));o===N.COMPUTE&&(oe=await Ue(n,a,t,k,e.abortSignal));const L=m.currentHashes.get(s);L&&A.set(s,L)}if(await v(),A.size>0){const r=await a.hashService.updateStateAfterDeploy(n.path,A);if(!r.success){const o=S(r.error.message);M.debug(B,"Failed to update state file",{error:o}),t.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy unchanged stacks: ${o}`,"warn")}}const ie=await a.stackService.resolveWebsiteUrl(n.appName);ie&&(O.websiteUrl=ie);const Se=await Ve(a,n.appName,ne,t,j,oe,e.abortSignal);return await nt(a.awsProvider,{stackNames:[...E],appName:n.appName,onLog:(r,o)=>t.onLog?.(r,o),...e.abortSignal!==void 0?{abortSignal:e.abortSignal}:{}}).catch(r=>{M.debug(B,"Forget completion sweep failed",{error:S(ce(r))})}),P({target:n.appName,deploymentType:"application",outputs:Object.keys(O).length>0?O:void 0,artefacts:Se,durationMs:Date.now()-h})}export{zt as deployApplication,fe as emitStackTargets};
@@ -37,6 +37,7 @@ export declare function getParallelPhase2Stacks(deployOrder: readonly Applicatio
37
37
  export declare function deployParallelPhase(stacks: ApplicationStack[], operation: ApplicationOperation, services: DeployServices, context: DeploymentContext, callbacks: DeployCallbacks, startIndex: number, totalSteps: number, detection: DetectionResult, allOutputs: Record<string, string>, deployedHashes: Map<string, string>): Promise<Result<void>>;
38
38
  interface DeployStackSequentialOptions {
39
39
  parameters?: Record<string, string>;
40
+ abortSignal?: AbortSignal;
40
41
  }
41
42
  /**
42
43
  * Deploy a single stack with step lifecycle events and output collection.
@@ -72,7 +73,7 @@ export declare function runDockerPreCompute(stack: ApplicationStack, params: Dep
72
73
  * discovery: a publish failure degrades (warns, omits that function from the
73
74
  * returned map) rather than failing a deploy that already succeeded.
74
75
  */
75
- export declare function runLambdaVersionPublish(operation: ApplicationOperation, services: DeployServices, callbacks: DeployCallbacks, contentHashTagsByService: Record<string, string>): Promise<Record<string, PublishedLambdaVersion>>;
76
+ export declare function runLambdaVersionPublish(operation: ApplicationOperation, services: DeployServices, callbacks: DeployCallbacks, contentHashTagsByService: Record<string, string>, abortSignal?: AbortSignal): Promise<Record<string, PublishedLambdaVersion>>;
76
77
  /**
77
78
  * Bridge DeployCallbacks to BuildCallbacks.
78
79
  * Fires both legacy OpenNext-specific callbacks and generic build callbacks
@@ -1,4 +1,4 @@
1
- import{join as b}from"node:path";import{success as h,failure as P}from"@fjall/generator";import{maskSensitiveOutput as y}from"@fjall/util";import{parseLambdaDockerEntriesFromManifest as A}from"@fjall/util/manifest";import{isAborted as B}from"../../aws/organisations/types.js";import{APPLICATION_STACKS as E,getApplicationStackName as N,getApplicationStepName as O,getApplicationStepId as w,PARALLEL_DEPLOY_GROUPS as R}from"../../types/operations.js";import{emitProgress as $}from"../../services/supporting/helpers.js";import{forwardOutput as k,forwardResourceProgress as j}from"../contextHelpers.js";import{emptyBuildProducts as D,runDockerBuild as I}from"./dockerBuildHelper.js";import{runWelcomeImageSetup as T}from"./welcomeImageHelper.js";import{withStepLifecycle as _}from"../stepLifecycle.js";function z(e){const r=new Set;for(const n of e.deployOrder){const i=N(e.appName,n),o=e.stackChanges.get(i)??!0,a=n===E.COMPUTE&&e.computeBuildPossible;(o||e.force||a)&&r.add(i)}return r}function J(e,r,n,i){const o=new Set(R.PHASE_2.stacks),a=[];for(let s=r;s<e.length&&o.has(e[s]);s++)a.push(e[s]);if(a.length<2)return[];const u=a.filter(s=>i.has(N(n,s)));return u.length>=2?u:[]}async function Q(e,r,n,i,o,a,u,s,p,f){for(let t=0;t<e.length;t++){const d=e[t],c=w(d,"deploy"),m=O(d,"deploy");o.onStepStart?.(c,m,a+t,u)}$(o,"Deploying infrastructure in parallel\u2026"),o.onParallelPhaseStart?.(e,"Storage and database resources (parallel)");const l=await n.stackService.deployStacksInParallel(e,i,{onOutput:k(o),onResourceProgress:(t,d)=>{o.onResourceProgress?.(t),d&&o.onParallelStackResourceProgress?.(d,t)},onStackComplete:(t,d,c,m)=>{const S=w(t,"deploy"),L=O(t,"deploy"),x=a+e.indexOf(t),C=B(n.abortSignal);o.onStepComplete?.(S,L,d?"completed":C?"cancelled":"error",x,u),!d&&m&&!C&&o.onError?.(new Error(y(m.message)))}});if(!l.success)return o.onParallelPhaseComplete?.([]),P(l.error);const g=l.data.filter(t=>!t.success);if(o.onParallelPhaseComplete?.(l.data.map(t=>({stack:t.stack,success:t.success,error:t.error}))),g.length>0){const t=g.map(c=>c.stack).join(", "),d=g.map(c=>`${c.stack}: ${y(c.error?.message??"Unknown error")}`).join(`
2
- `);return P(new Error(`Failed to deploy stacks: ${t}
1
+ import{join as O}from"node:path";import{success as P,failure as S}from"@fjall/generator";import{maskSensitiveOutput as y}from"@fjall/util";import{parseLambdaDockerEntriesFromManifest as B}from"@fjall/util/manifest";import{isAborted as L}from"../../aws/organisations/types.js";import{APPLICATION_STACKS as C,getApplicationStackName as w,getApplicationStepName as N,getApplicationStepId as b,PARALLEL_DEPLOY_GROUPS as $}from"../../types/operations.js";import{emitProgress as R}from"../../services/supporting/helpers.js";import{forwardOutput as k,forwardResourceProgress as T}from"../contextHelpers.js";import{emptyBuildProducts as j,runDockerBuild as D}from"./dockerBuildHelper.js";import{runWelcomeImageSetup as I}from"./welcomeImageHelper.js";import{withStepLifecycle as _}from"../stepLifecycle.js";function z(e){const n=new Set;for(const s of e.deployOrder){const i=w(e.appName,s),r=e.stackChanges.get(i)??!0,a=s===C.COMPUTE&&e.computeBuildPossible;(r||e.force||a)&&n.add(i)}return n}function J(e,n,s,i){const r=new Set($.PHASE_2.stacks),a=[];for(let o=n;o<e.length&&r.has(e[o]);o++)a.push(e[o]);if(a.length<2)return[];const c=a.filter(o=>i.has(w(s,o)));return c.length>=2?c:[]}async function Q(e,n,s,i,r,a,c,o,f,l){for(let t=0;t<e.length;t++){const d=e[t],p=b(d,"deploy"),m=N(d,"deploy");r.onStepStart?.(p,m,a+t,c)}R(r,"Deploying infrastructure in parallel\u2026"),r.onParallelPhaseStart?.(e,"Storage and database resources (parallel)");const u=await s.stackService.deployStacksInParallel(e,i,{onOutput:k(r),onResourceProgress:(t,d)=>{r.onResourceProgress?.(t),d&&r.onParallelStackResourceProgress?.(d,t)},onStackComplete:(t,d,p,m)=>{const h=b(t,"deploy"),x=N(t,"deploy"),A=a+e.indexOf(t),E=L(s.abortSignal);r.onStepComplete?.(h,x,d?"completed":E?"cancelled":"error",A,c),!d&&m&&!E&&r.onError?.(new Error(y(m.message)))}});if(!u.success)return r.onParallelPhaseComplete?.([]),S(u.error);const g=u.data.filter(t=>!t.success);if(r.onParallelPhaseComplete?.(u.data.map(t=>({stack:t.stack,success:t.success,error:t.error}))),g.length>0){const t=g.map(p=>p.stack).join(", "),d=g.map(p=>`${p.stack}: ${y(p.error?.message??"Unknown error")}`).join(`
2
+ `);return S(new Error(`Failed to deploy stacks: ${t}
3
3
 
4
- ${d}`))}for(const t of l.data){if(t.success&&t.outputs)for(const[m,S]of Object.entries(t.outputs))p[m]=String(S);const d=N(r.appName,t.stack),c=s.currentHashes.get(d);c&&f.set(d,c)}return h(void 0)}async function X(e,r,n,i,o,a,u,s){const p=w(e,"deploy"),f=O(e,"deploy");return _(i,{stepId:p,stepName:f,stepIndex:o,totalSteps:a},async()=>{const l=await r.stackService.deployStack(e,n,{onOutput:k(i),onResourceProgress:j(i)},s?.parameters!==void 0?{parameters:s.parameters}:void 0);if(!l.success)return{kind:"error",error:l.error};if(l.data.outputs)for(const[g,t]of Object.entries(l.data.outputs))u[g]=String(t);return{kind:"completed",data:void 0}},r.abortSignal)}async function Z(e,r,n,i,o,a){if(e!==E.COMPUTE||!r.dockerProvider)return null;if(a){const s=await I(r,n,i,o);return s.success?h(s.data):P(s.error)}const u=await T(r,n,i,o);return u.success?h(D()):P(u.error)}async function ee(e,r,n,i){if(Object.keys(i).length===0)return{};const o=b(e.path,"cdk.out"),u=A(o).filter(p=>i[p.imageKey]!==void 0);if(u.length===0)return{};const s={};for(const p of u){const f=await r.lambdaService.publishVersion(p.name);if(!f.success){n.onLog?.(`Published image for Lambda '${p.name}', but publishing a new version failed: ${y(f.error.message)}. The function's $LATEST code is up to date; only the published-version record is affected.`,"warn");continue}s[p.name]=f.data}return s}function te(e){return{onBuildStart:r=>{e.onOpenNextBuildStart?.(),e.onLog?.(`${r} build started`,"info")},onBuildProgress:(r,n)=>{e.onOpenNextProgress?.(n)},onBuildComplete:r=>{e.onOpenNextBuildComplete?.(),e.onLog?.(`${r} build complete`,"info")},onBuildError:(r,n)=>{e.onOpenNextBuildError?.(n)}}}export{te as createBuildCallbacks,Q as deployParallelPhase,X as deployStackSequential,J as getParallelPhase2Stacks,z as getStackNamesToDeploy,Z as runDockerPreCompute,ee as runLambdaVersionPublish};
4
+ ${d}`))}for(const t of u.data){if(t.success&&t.outputs)for(const[m,h]of Object.entries(t.outputs))f[m]=String(h);const d=w(n.appName,t.stack),p=o.currentHashes.get(d);p&&l.set(d,p)}return P(void 0)}async function X(e,n,s,i,r,a,c,o){const f=b(e,"deploy"),l=N(e,"deploy");return _(i,{stepId:f,stepName:l,stepIndex:r,totalSteps:a},async()=>{const u=await n.stackService.deployStack(e,s,{onOutput:k(i),onResourceProgress:T(i)},o?.parameters!==void 0||o?.abortSignal!==void 0?{...o?.parameters!==void 0?{parameters:o.parameters}:{},...o?.abortSignal!==void 0?{abortSignal:o.abortSignal}:{}}:void 0);if(!u.success)return{kind:"error",error:u.error};if(u.data.outputs)for(const[g,t]of Object.entries(u.data.outputs))c[g]=String(t);return{kind:"completed",data:void 0}},n.abortSignal)}async function Z(e,n,s,i,r,a){if(e!==C.COMPUTE||!n.dockerProvider)return null;if(a){const o=await D(n,s,i,r);return o.success?P(o.data):S(o.error)}const c=await I(n,s,i,r);return c.success?P(j()):S(c.error)}async function ee(e,n,s,i,r){if(Object.keys(i).length===0)return{};const a=O(e.path,"cdk.out"),o=B(a).filter(l=>i[l.imageKey]!==void 0);if(o.length===0)return{};const f={};for(const l of o){if(L(r)){s.onLog?.(`Skipping the Lambda version publish for '${l.name}' \u2014 the deployment was cancelled. The function's $LATEST code is up to date; only the published-version record is affected.`,"warn");continue}const u=await n.lambdaService.publishVersion(l.name,r);if(!u.success){s.onLog?.(`Published image for Lambda '${l.name}', but publishing a new version failed: ${y(u.error.message)}. The function's $LATEST code is up to date; only the published-version record is affected.`,"warn");continue}f[l.name]=u.data}return f}function te(e){return{onBuildStart:n=>{e.onOpenNextBuildStart?.(),e.onLog?.(`${n} build started`,"info")},onBuildProgress:(n,s)=>{e.onOpenNextProgress?.(s)},onBuildComplete:n=>{e.onOpenNextBuildComplete?.(),e.onLog?.(`${n} build complete`,"info")},onBuildError:(n,s)=>{e.onOpenNextBuildError?.(s)}}}export{te as createBuildCallbacks,Q as deployParallelPhase,X as deployStackSequential,J as getParallelPhase2Stacks,z as getStackNamesToDeploy,Z as runDockerPreCompute,ee as runLambdaVersionPublish};
@@ -1 +1 @@
1
- import{success as w,failure as N}from"@fjall/generator";import{getErrorMessage as S}from"@fjall/util";import{logger as y}from"@fjall/util/logger";import{getApplicationDestroyOrder as b,getApplicationStackName as x,getApplicationStepName as h,getApplicationStepId as P}from"../../types/operations.js";import{emitStackTargets as D}from"./applicationDeploy.js";import{stubCallerIdentity as L}from"../../types/deployment/index.js";import{deriveResourcesFromManifestStacks as R}from"../../types/detection/patternDetection.js";import{CdkContextBuilder as A}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as F}from"../contextHelpers.js";import{deleteStateFile as I,readStateFile as O}from"../../types/config/FjallState.js";async function J(a,s,r){const{callbacks:t}=a,k=Date.now(),m=s.frameworkRegistry.resolve({appPath:r.path})?.detection.pattern??null;let d;try{const e=await O(r.path);if(e!==null){const o=Object.keys(e.templateHashes);o.length>0&&(d=R(o))}}catch(e){y.debug("applicationDestroy","Could not read state file for resource detection",{error:S(e)}),t.onLog?.("Could not read state file for resource detection \u2014 falling back to pattern detection","warn")}const C=A.buildDeploymentContext({deployType:"application",target:r.appName,path:r.path,region:s.awsProvider.getRegion(),callerIdentity:L(s.awsProvider.getAccountId()),...F({orgConfig:a.orgConfig,identity:a.identity})},{verbose:a.options?.verbose},a.orgConfig),p=b({pattern:m,resources:d}),l=p.length;t.onLog?.(`Destroying ${r.appName} (${l} stacks, ${m??"standard"} pattern)`,"info"),D(t,s,p.map(e=>x(r.appName,e)));const f=[],u=[],g=await s.stackService.destroyAllStacks(C,{onOutput:e=>{t.onOutput?.(e)},onLog:t.onLog,onStackCleanupProgress:t.onStackCleanupProgress,onResourceProgress:(e,o)=>{t.onResourceProgress?.(e),o&&t.onParallelStackResourceProgress?.(o,e)},onStackStart:(e,o)=>{const n=P(e,"destroy"),i=h(e,"destroy"),c=p.indexOf(e);t.onStepStart?.(n,i,c,l)},onStackComplete:async(e,o)=>{const n=P(e,"destroy"),i=h(e,"destroy"),c=p.indexOf(e);o.success?o.data?.skipped?(u.push(o.data.stackName||e),t.onStepComplete?.(n,i,"skipped",c,l)):(f.push(o.data?.stackName||e),t.onStepComplete?.(n,i,"completed",c,l)):(t.onStepComplete?.(n,i,"error",c,l),t.onError?.(o.error))},onParallelPhaseStart:(e,o)=>{t.onLog?.(`Parallel phase: ${o}`,"info"),t.onParallelPhaseStart?.(e,o)},onParallelPhaseComplete:e=>{const o=e.filter(n=>!n.success);o.length>0&&t.onLog?.(`Parallel phase completed with ${o.length} failure(s)`,"warn"),t.onParallelPhaseComplete?.(e)}},d,a.abortSignal,a.assertLeaseForStack);if(!g.success)return t.onError?.(g.error),N(g.error);try{await I(r.path)}catch(e){y.debug("applicationDestroy","Failed to delete state file (non-critical)",{error:S(e)}),t.onLog?.("Failed to delete state file (non-critical)","warn")}return w({target:r.appName,deploymentType:"application",stacksDestroyed:f,skippedStacks:u,durationMs:Date.now()-k})}export{J as destroyApplication};
1
+ import{success as x,failure as y}from"@fjall/generator";import{getErrorMessage as P}from"@fjall/util";import{logger as k}from"@fjall/util/logger";import{getApplicationDestroyOrder as D,getApplicationStackName as F,getApplicationStepName as C,getApplicationStepId as w}from"../../types/operations.js";import{emitStackTargets as L}from"./applicationDeploy.js";import{runDestroyPreFlight as R}from"./destroyPreFlight.js";import{stubCallerIdentity as A}from"../../types/deployment/index.js";import{deriveResourcesFromManifestStacks as I}from"../../types/detection/patternDetection.js";import{CdkContextBuilder as O}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as $}from"../contextHelpers.js";import{deleteStateFile as v,readStateFile as E}from"../../types/config/FjallState.js";async function V(r,s,a){const{callbacks:t}=r,b=Date.now(),f=s.frameworkRegistry.resolve({appPath:a.path})?.detection.pattern??null;let d;try{const e=await E(a.path);if(e!==null){const o=Object.keys(e.templateHashes);o.length>0&&(d=I(o))}}catch(e){k.debug("applicationDestroy","Could not read state file for resource detection",{error:P(e)}),t.onLog?.("Could not read state file for resource detection \u2014 falling back to pattern detection","warn")}const N=O.buildDeploymentContext({deployType:"application",target:a.appName,path:a.path,region:s.awsProvider.getRegion(),callerIdentity:A(s.awsProvider.getAccountId()),...$({orgConfig:r.orgConfig,identity:r.identity})},{verbose:r.options?.verbose},r.orgConfig),p=D({pattern:f,resources:d}),l=p.length;t.onLog?.(`Destroying ${a.appName} (${l} stacks, ${f??"standard"} pattern)`,"info");const u=p.map(e=>F(a.appName,e));L(t,s,u);const g=await R(s.awsProvider,{stackNames:u,abortSignal:r.abortSignal});if(!g.success)return t.onError?.(g.error),y(g.error);const S=[],h=[],m=await s.stackService.destroyAllStacks(N,{onOutput:e=>{t.onOutput?.(e)},onLog:t.onLog,onStackCleanupProgress:t.onStackCleanupProgress,onResourceProgress:(e,o)=>{t.onResourceProgress?.(e),o&&t.onParallelStackResourceProgress?.(o,e)},onStackStart:(e,o)=>{const n=w(e,"destroy"),i=C(e,"destroy"),c=p.indexOf(e);t.onStepStart?.(n,i,c,l)},onStackComplete:async(e,o)=>{const n=w(e,"destroy"),i=C(e,"destroy"),c=p.indexOf(e);o.success?o.data?.skipped?(h.push(o.data.stackName||e),t.onStepComplete?.(n,i,"skipped",c,l)):(S.push(o.data?.stackName||e),t.onStepComplete?.(n,i,"completed",c,l)):(t.onStepComplete?.(n,i,"error",c,l),t.onError?.(o.error))},onParallelPhaseStart:(e,o)=>{t.onLog?.(`Parallel phase: ${o}`,"info"),t.onParallelPhaseStart?.(e,o)},onParallelPhaseComplete:e=>{const o=e.filter(n=>!n.success);o.length>0&&t.onLog?.(`Parallel phase completed with ${o.length} failure(s)`,"warn"),t.onParallelPhaseComplete?.(e)}},d,r.abortSignal,r.assertLeaseForStack);if(!m.success)return t.onError?.(m.error),y(m.error);try{await v(a.path)}catch(e){k.debug("applicationDestroy","Failed to delete state file (non-critical)",{error:P(e)}),t.onLog?.("Failed to delete state file (non-critical)","warn")}return x({target:a.appName,deploymentType:"application",stacksDestroyed:S,skippedStacks:h,durationMs:Date.now()-b})}export{V as destroyApplication};
@@ -20,6 +20,7 @@ import type { PublishedLambdaVersion } from "../../services/infrastructure/Lambd
20
20
  * `image` build keys (several Lambda functions may share one key). Keys that
21
21
  * match a container-Lambda manifest entry are expanded into one artefact PER
22
22
  * ACTUAL FUNCTION NAME (there is no ECS task-definition/live-service concept
23
- * for them); every other key is treated as an ECS service, unchanged.
23
+ * for them); keys naming an ECS manifest service emit an ECS artefact — and
24
+ * a key that is both (a deliberately shared build) emits both kinds.
24
25
  */
25
- export declare function collectFullDeployArtefacts(services: DeployServices, appName: string, build: DockerBuildProducts | undefined, callbacks: DeployCallbacks, cdkOutPath: string, publishedLambdaVersions?: Record<string, PublishedLambdaVersion>): Promise<ServiceArtefact[]>;
26
+ export declare function collectFullDeployArtefacts(services: DeployServices, appName: string, build: DockerBuildProducts | undefined, callbacks: DeployCallbacks, cdkOutPath: string, publishedLambdaVersions?: Record<string, PublishedLambdaVersion>, abortSignal?: AbortSignal): Promise<ServiceArtefact[]>;
@@ -1 +1 @@
1
- import{maskSensitiveOutput as N}from"@fjall/util";import{parseLambdaDockerEntriesFromManifest as b}from"@fjall/util/manifest";import{logger as h}from"@fjall/util/logger";import{extractEcsServiceName as D}from"../../aws/utils/arnParser.js";import{deriveEcrRepositoryArn as k}from"./codeOnlyDeploy.js";const w="artefactCollection";async function O(s,t,n,r,o,c={}){if(n===void 0||n.repoUri===void 0)return[];const i=Object.entries(n.contentHashTagsByService);if(i.length===0)return[];const d=n.repoUri,e=k(d),u=await L(s,t,r),g=new Map;for(const a of b(o)){const f=g.get(a.imageKey)??[];f.push(a.name),g.set(a.imageKey,f)}const v=[];for(const[a,f]of i){const m=n.imageDigestsByService[a],A=g.get(a);if(A!==void 0){for(const S of A){const p=c[S];v.push({serviceName:S,imageTag:f,imageUri:`${d}:${f}`,...m!==void 0?{imageDigest:m}:{},...e!==""?{ecrRepositoryArn:e}:{},...p!==void 0?{functionArn:p.functionArn,publishedVersion:p.version}:{}})}continue}const l=C(a,u);v.push({serviceName:l?.ecsServiceName??a,imageTag:f,imageUri:`${d}:${f}`,...m!==void 0?{imageDigest:m}:{},...e!==""?{ecrRepositoryArn:e}:{},...l?.taskDefinitionArn!==void 0?{taskDefinitionArn:l.taskDefinitionArn}:{}})}return v}async function L(s,t,n){try{const r=await s.ecsResolver.getDeployableClusterAndServices(t);if(!r.success)return y(n,t,r.error.message),[];const{clusterArn:o,serviceArns:c}=r.data;if(!o||c.length===0)return h.debug(w,"No deployable ECS services discovered",{appName:t}),[];const i=await s.ecsService.describeServices(o,c);if(!i.success)return y(n,t,i.error.message),c.map(e=>D(e)).filter(e=>e!==void 0&&e!=="").map(e=>({ecsServiceName:e}));const d=[];for(const e of i.data){const u=e.serviceName??(e.serviceArn!==void 0?D(e.serviceArn):void 0);u===void 0||u===""||d.push({ecsServiceName:u,...e.taskDefinition!==void 0?{taskDefinitionArn:e.taskDefinition}:{}})}return d}catch(r){return y(n,t,r instanceof Error?r.message:String(r)),[]}}function C(s,t){const n=s.toLowerCase(),r=t.find(i=>i.ecsServiceName.toLowerCase()===n);if(r)return r;const o=t.filter(i=>i.ecsServiceName.toLowerCase().includes(n));if(o.length===1)return o[0];const c=o.filter(i=>i.ecsServiceName.toLowerCase().endsWith(`-${n}`));if(c.length===1)return c[0]}function y(s,t,n){const r=N(n);h.debug(w,"Post-deploy artefact resolution degraded",{appName:t,error:r}),s.onLog?.(`Deploy succeeded, but resolving live task definitions for release artefacts failed: ${r}. Artefacts are recorded without task definition ARNs.`,"warn")}export{O as collectFullDeployArtefacts};
1
+ import{maskSensitiveOutput as L}from"@fjall/util";import{parseDockerServicesFromManifest as b,parseLambdaDockerEntriesFromManifest as C}from"@fjall/util/manifest";import{logger as D}from"@fjall/util/logger";import{extractEcsServiceName as w}from"../../aws/utils/arnParser.js";import{deriveEcrRepositoryArn as E}from"./codeOnlyDeploy.js";const N="artefactCollection";async function K(c,i,n,o,r,a={},t){if(n===void 0||n.repoUri===void 0)return[];const d=Object.entries(n.contentHashTagsByService);if(d.length===0)return[];const u=n.repoUri,e=E(u),m=await $(c,i,o,t),v=new Map;for(const s of C(r)){const f=v.get(s.imageKey)??[];f.push(s.name),v.set(s.imageKey,f)}const k=new Set(b(r).map(s=>s.name)),l=[];for(const[s,f]of d){const g=n.imageDigestsByService[s],S=v.get(s);if(S!==void 0){for(const h of S){const y=a[h];l.push({serviceName:h,imageTag:f,imageUri:`${u}:${f}`,...g!==void 0?{imageDigest:g}:{},...e!==""?{ecrRepositoryArn:e}:{},...y!==void 0?{functionArn:y.functionArn,publishedVersion:y.version}:{}})}if(!k.has(s))continue}const p=R(s,m);l.push({serviceName:p?.ecsServiceName??s,imageTag:f,imageUri:`${u}:${f}`,...g!==void 0?{imageDigest:g}:{},...e!==""?{ecrRepositoryArn:e}:{},...p?.taskDefinitionArn!==void 0?{taskDefinitionArn:p.taskDefinitionArn}:{}})}return l}async function $(c,i,n,o){try{const r=await c.ecsResolver.getDeployableClusterAndServices(i,o);if(!r.success)return A(n,i,r.error.message),[];const{clusterArn:a,serviceArns:t}=r.data;if(!a||t.length===0)return D.debug(N,"No deployable ECS services discovered",{appName:i}),[];const d=await c.ecsService.describeServices(a,t,o);if(!d.success)return A(n,i,d.error.message),t.map(e=>w(e)).filter(e=>e!==void 0&&e!=="").map(e=>({ecsServiceName:e}));const u=[];for(const e of d.data){const m=e.serviceName??(e.serviceArn!==void 0?w(e.serviceArn):void 0);m===void 0||m===""||u.push({ecsServiceName:m,...e.taskDefinition!==void 0?{taskDefinitionArn:e.taskDefinition}:{}})}return u}catch(r){return A(n,i,r instanceof Error?r.message:String(r)),[]}}function R(c,i){const n=c.toLowerCase(),o=i.find(t=>t.ecsServiceName.toLowerCase()===n);if(o)return o;const r=i.filter(t=>t.ecsServiceName.toLowerCase().includes(n));if(r.length===1)return r[0];const a=r.filter(t=>t.ecsServiceName.toLowerCase().endsWith(`-${n}`));if(a.length===1)return a[0]}function A(c,i,n){const o=L(n);D.debug(N,"Post-deploy artefact resolution degraded",{appName:i,error:o}),c.onLog?.(`Deploy succeeded, but resolving live task definitions for release artefacts failed: ${o}. Artefacts are recorded without task definition ARNs.`,"warn")}export{K as collectFullDeployArtefacts};
@@ -40,28 +40,6 @@ export declare function lookupContentHashTag(manifestService: ManifestDockerServ
40
40
  * caller surfaces a warning on multi-service stacks.
41
41
  */
42
42
  export declare function rebaseRollbackTagForService(suppliedTag: string, serviceName: string, allServiceNames: readonly string[]): string;
43
- /**
44
- * Converge the Compute stack's `<Service>ImageTag` CfnParameters to the tags
45
- * actually rolled (F4b). A rollback mutates ECS (or a Lambda function)
46
- * directly, bypassing CloudFormation; without this, the stack's declared
47
- * parameters stay at their pre-rollback values and the next full deploy
48
- * re-applies them, silently reverting the rollback. Runs for BOTH rollback
49
- * surfaces (the `serviceImageTags` map and the legacy single `--image-tag`);
50
- * never for a plain code-only deploy (no rollback tag exists there). Exported
51
- * so `lambdaCodeOnlyRollout.ts`'s rollback paths can feed their rolled
52
- * `imageKey`s into the SAME batched reconcile call as the ECS entries —
53
- * `rolledServices` is keyed generically (`serviceName` doubles as `imageKey`
54
- * for a Lambda entry, since that's the CfnParameter key
55
- * `imageTagParameterName` derives from).
56
- *
57
- * Best-effort: the services are already rolled by the time this runs, so a
58
- * reconcile failure must not fail the deploy — it surfaces a prominent
59
- * warning instead.
60
- */
61
- export declare function reconcileImageTagParameters(services: DeployServices, appName: string, rolledServices: ReadonlyArray<{
62
- serviceName: string;
63
- imageTag: string;
64
- }>, callbacks: DeployParams["callbacks"], abortSignal?: AbortSignal): Promise<void>;
65
43
  /**
66
44
  * Code-only deployment orchestrator.
67
45
  *
@@ -1 +1 @@
1
- import{join as q}from"path";import{success as te,failure as z}from"@fjall/generator";import{logger as A}from"@fjall/util/logger";import{artefactOutputKey as M,imageTagParameterName as re,maskSensitiveOutput as N}from"@fjall/util";import{parseDockerServicesFromManifest as ne,parseLambdaDockerEntriesFromManifest as ae}from"@fjall/util/manifest";import{APPLICATION_STACKS as G,getApplicationStackName as ie,getApplicationStepId as oe,getApplicationStepName as se}from"../../types/operations.js";import{extractEcsServiceName as P}from"../../aws/utils/arnParser.js";import{isAborted as H}from"../../aws/organisations/types.js";import{stripTagOrDigest as ce}from"../../services/infrastructure/EcrImageInspectorService.js";import{withStepLifecycle as ge}from"../stepLifecycle.js";import{registerAndRollTaskDefinition as de}from"./taskDefinitionRoll.js";import{ecrRepoUri as le}from"./dockerBuildHelper.js";import{matchesServiceName as J,matchServiceImageTagsToLiveServices as me,preflightResolveServiceImageTagDigests as fe,resolveServiceTaskDefinition as ue}from"./serviceImageTagsRollback.js";import{rolloutLambdaImageTag as pe,rolloutLambdaPrimary as he,rolloutLambdaServiceImageTags as ve}from"./lambdaCodeOnlyRollout.js";const C="codeOnlyDeploy";function ke(t,r){if(t)return r[t.name]}function $e(t,r){const e=r.toLowerCase();return t.find(a=>a.name.toLowerCase()===e)??t.find(a=>e.includes(a.name.toLowerCase()))}function ye(t,r,e){const a=r.toLowerCase(),l=t.toLowerCase(),n=e.map(o=>o.toLowerCase()).filter(o=>o!==""&&l.startsWith(`${o}-`)).sort((o,f)=>f.length-o.length)[0];if(n===void 0||n===a)return t;const m=t.slice(n.length);return`${a}${m}`}const we=0,De=1;function Q(t,r,e,a,l){a[M(t,"TaskDefinition")]=e.taskDefinitionArn,a[M(t,"PreviousTaskDefinition")]=e.previousTaskDefinitionArn,a[M(t,"ImageTag")]=r,a[M(t,"ImageUri")]=e.imageUri,a[M(t,"EcrRepositoryArn")]=e.ecrRepositoryArn,e.imageDigest!==void 0&&(a[M(t,"ImageDigest")]=e.imageDigest),l.push({serviceName:t,imageTag:r,imageUri:e.imageUri,taskDefinitionArn:e.taskDefinitionArn,previousTaskDefinitionArn:e.previousTaskDefinitionArn,...e.imageDigest!==void 0?{imageDigest:e.imageDigest}:{},...e.ecrRepositoryArn!==""?{ecrRepositoryArn:e.ecrRepositoryArn}:{}})}async function x(t,r,e,a,l){if(e.length===0)return;const n=ie(r,G.COMPUTE),m={};for(const{serviceName:f,imageTag:w}of e)m[re(f)]=w;const o=await t.cfnService.updateStackParameters(n,m,l);if(!o.success){a.onLog?.(`Rollback succeeded but the CloudFormation ImageTag parameter reconcile failed \u2014 the next full deploy may revert this rollback. Reason: ${N(o.error.message)}`,"warn");return}o.data.skippedKeys.length>0&&(a.onLog?.(`Rollback succeeded but ${o.data.skippedKeys.length} ImageTag parameter(s) were not found on stack ${n} (${o.data.skippedKeys.join(", ")}) \u2014 the next full deploy may revert those services`,"warn"),A.debug(C,"ImageTag reconcile skipped stale parameters",{stackName:n,skippedKeys:o.data.skippedKeys}))}function V(t,r,e,a,l){if(e)return{kind:"error",error:e};if(t.kind==="error")return r.failures.length>0?{kind:"error",error:new Error(`${t.error.message}; Lambda rollout failures: ${r.failures.join("; ")}`)}:t;if(r.failures.length>0)return{kind:"error",error:new Error(`Lambda rollout failures: ${r.failures.join("; ")}`)};const n=t.data,m={...n.outputs??{},...r.outputs};return{kind:"completed",data:{target:a.appName,deploymentType:"application",outputs:Object.keys(m).length>0?m:void 0,artefacts:[...n.artefacts,...r.artefacts],durationMs:Date.now()-l}}}async function je(t,r,e,a,l){const{callbacks:n,options:m}=t,o=Date.now(),f=oe(G.COMPUTE,"deploy"),w=se(G.COMPUTE,"deploy");return ge(n,{stepId:f,stepName:w,stepIndex:we,totalSteps:De},async()=>{const g=m?.imageTag,h=m?.serviceImageTags;g?n.onLog?.(`Rolling to supplied image tag ${g}`,"info"):h&&n.onLog?.(`Rolling ${Object.keys(h).length} service(s) to their release-recorded image tags`,"info");const v=ne(q(e.path,"cdk.out"));A.debug(C,"Code-only rollout starting",{explicitRollbackTag:g,serviceImageTags:h,workingDirectory:t.workingDirectory,contentHashTagsByService:a,manifestServiceCount:v.length,manifestServices:v.map(s=>({name:s.name,target:s.docker.target}))}),n.onLog?.("Discovering ECS cluster and services\u2026","info");const $=await r.ecsResolver.getDeployableClusterAndServices(e.appName);if(!$.success)return A.debug(C,"ECS discovery failed",{appName:e.appName,error:N($.error.message)}),{kind:"error",error:$.error};const{clusterArn:c,serviceArns:i}=$.data;A.debug(C,"ECS discovery complete",{appName:e.appName,clusterArn:c,serviceCount:i.length,serviceArns:i});const y=ae(q(e.path,"cdk.out")),D=Array.from(new Set(y.map(s=>s.imageKey))),k=c!==void 0&&i.length>0,R=y.length>0;if(!k&&!R){const s=`No deployable ECS services or container-image Lambda functions found for ${e.appName}`;return n.onLog?.(s,"warn"),{kind:"skipped",data:{target:e.appName,deploymentType:"application",durationMs:Date.now()-o,noChanges:!0,artefacts:[]}}}const u=c??"";if(h!==void 0){const s=k?await Se(r,e,u,i,h,n,t.abortSignal,o):{kind:"completed",data:{target:e.appName,deploymentType:"application",artefacts:[],durationMs:Date.now()-o}},{outcome:p,error:d}=await ve(r,e,h,n,t.abortSignal);return p.rolledImageKeys.length>0&&await x(r,e.appName,p.rolledImageKeys,n,t.abortSignal),V(s,p,d,e,o)}const E=m?.serviceName?.toLowerCase(),I=E===""?void 0:E,T=I?i.filter(s=>J(P(s)??"",I)):i;if(I){const s=y.some(p=>J(p.name,I));if(T.length===0&&!s){const p=[...i.map(d=>P(d)??"unknown"),...y.map(d=>d.name)];return{kind:"error",error:new Error(`Service '${I}' not found. Available: ${p.join(", ")||"none"}`)}}}const K={},O=[],L=[],U=[...i.map(s=>P(s)).filter(s=>s!==void 0&&s!==""),...D];for(let s=0;s<T.length;s++){if(H(t.abortSignal))return{kind:"error",error:new Error(`Rollout cancelled after ${O.length}/${T.length} services`)};const p=T[s];if(!p)continue;const d=P(p)??`service-${s+1}`,ee=`[${s+1}/${T.length}] ${d}`,F=$e(v,d),_=ke(F,a);let b,X;if(g!==void 0)b=ye(g,d,U),b!==g?(X=g,n.onLog?.(`Re-based image tag ${g} \u2192 ${b} for ${d}`,"info")):U.length>1&&!g.toLowerCase().startsWith(`${d.toLowerCase()}-`)&&n.onLog?.(`Image tag ${g} has no recognised service prefix; applying verbatim to ${d} \u2014 confirm it points at this service's image`,"warn");else if(_!==void 0)b=_;else{const Y=`No image available to deploy for ${d}: no content-hash tag was produced this run. Run a full deploy to build the image, or pass --image-tag <tag> to roll a specific existing image.`;n.onLog?.(Y,"warn"),L.push(`${d}: ${Y}`);continue}A.debug(C,"Starting service rollout",{serviceName:d,serviceArn:p,imageTag:b,explicitRollbackTag:g,contentHashTag:_,manifestServiceMatched:F?.name,dockerTarget:F?.docker.target,index:s,total:T.length}),n.onECSUpdate?.(`${ee}: rolling out image tag ${b}`,d);const S=await Z(r,u,p,d,b,n,X,void 0,t.abortSignal);if(A.debug(C,"Service rollout completed",{serviceName:d,success:S.success,...S.success?{taskDefinitionArn:S.data.taskDefinitionArn,imageDigest:S.data.imageDigest,durationMs:S.data.durationMs}:{error:N(S.error.message)}}),!S.success){L.push(`${d}: ${N(S.error.message)}`);continue}Q(d,b,S.data,K,O)}const B=Date.now()-o;if(L.length>0){const s=T.length-L.length,p=T.length,d=L.length===p?`All ${p} ECS service rollouts failed: ${L.join("; ")}`:`Partial rollout: ${s}/${p} services succeeded. Failures: ${L.join("; ")}`;return{kind:"error",error:new Error(d)}}g!==void 0&&await x(r,e.appName,O.map(s=>({serviceName:s.serviceName,imageTag:s.imageTag})),n,t.abortSignal);const W={kind:"completed",data:{target:e.appName,deploymentType:"application",outputs:Object.keys(K).length>0?K:void 0,artefacts:O,durationMs:B}};if(!R)return W;const j=g!==void 0?await pe(r,e,g,U,n,I,t.abortSignal):await he(r,e,a,l?.imageDigestsByService??{},l?.repoUri??le(r.awsProvider.getAccountId(),r.awsProvider.getRegion(),e.appName),n,I,t.abortSignal);return g!==void 0&&j.rolledImageKeys.length>0&&await x(r,e.appName,j.rolledImageKeys,n,t.abortSignal),V(W,j,void 0,e,o)},t.abortSignal)}async function Se(t,r,e,a,l,n,m,o){const f=me(a,l);for(const c of f.unmatchedLiveServiceNames)n.onLog?.(`Service ${c} is not part of this release \u2014 leaving it untouched`,"warn");for(const c of f.staleMapKeys)n.onLog?.(`Service ${c} from the release no longer exists in the stack`,"warn");if(f.matched.length===0)return{kind:"error",error:new Error("None of the services in serviceImageTags matched a live ECS service in this stack \u2014 nothing to roll")};const w=await fe(t,e,f.matched,m);if(!w.success)return{kind:"error",error:w.error};const g={},h=[],v=[];for(let c=0;c<f.matched.length;c++){if(H(m))return{kind:"error",error:new Error(`Rollout cancelled after ${h.length}/${f.matched.length} services`)};const i=f.matched[c];if(!i)continue;const y=`[${c+1}/${f.matched.length}] ${i.serviceName}`,D=w.data.get(i.serviceArn);if(D===void 0){v.push(`${i.serviceName}: pre-flight digest missing after a successful pre-flight`);continue}A.debug(C,"Starting service rollout (serviceImageTags)",{serviceName:i.serviceName,serviceArn:i.serviceArn,imageTag:i.tag,mapKey:i.mapKey,index:c,total:f.matched.length}),n.onECSUpdate?.(`${y}: rolling out image tag ${i.tag}`,i.serviceName);const k=await Z(t,e,i.serviceArn,i.serviceName,i.tag,n,void 0,D,m);if(A.debug(C,"Service rollout completed (serviceImageTags)",{serviceName:i.serviceName,success:k.success,...k.success?{taskDefinitionArn:k.data.taskDefinitionArn,imageDigest:k.data.imageDigest,durationMs:k.data.durationMs}:{error:N(k.error.message)}}),!k.success){v.push(`${i.serviceName}: ${N(k.error.message)}`);continue}Q(i.serviceName,i.tag,k.data,g,h)}const $=Date.now()-o;if(v.length>0){const c=f.matched.length-v.length,i=f.matched.length,y=v.length===i?`All ${i} ECS service rollouts failed: ${v.join("; ")}`:`Partial rollout: ${c}/${i} services succeeded. Failures: ${v.join("; ")}`;return{kind:"error",error:new Error(y)}}return await x(t,r.appName,h.map(c=>({serviceName:c.serviceName,imageTag:c.imageTag})),n,m),{kind:"completed",data:{target:r.appName,deploymentType:"application",outputs:Object.keys(g).length>0?g:void 0,artefacts:h,durationMs:$}}}async function Z(t,r,e,a,l,n,m,o,f){const w=Date.now();let g,h,v,$,c;if(o!==void 0)g=o.taskDefinition.previousTaskDefArn,h=o.taskDefinition.taskDefinition,v=o.taskDefinition.containerDefinitions,$=o.taskDefinition.repoUri,c=o.imageDigest;else{const u=await ue(t,r,e,a);if(!u.success)return z(u.error);g=u.data.previousTaskDefArn,h=u.data.taskDefinition,v=u.data.containerDefinitions,$=u.data.repoUri;const E=await t.ecrImageInspector.getImageDigest($,l,f);if(E.success)c=E.data;else{if(m!==void 0)return z(new Error(`Re-based image tag '${l}' (from supplied '${m}') was not found in ECR for ${a}: ${N(E.error.message)}. The supplied tag's build has no image for ${a} \u2014 supply that service's own tag, or pass --service to roll a single service.`));n.onLog?.(`Could not resolve image digest for ${a} (${N(E.error.message)}); falling back to tag pinning`,"warn")}}const i=u=>c!==void 0?`${u}@${c}`:`${u}:${l}`,y=v.map(u=>u.image?{...u,image:i(ce(u.image))}:u),D=await de(t,{clusterArn:r,serviceArn:e,serviceName:a,taskDefinition:h,containerDefinitions:y,previousTaskDefArn:g,...c!==void 0?{imageDigest:c}:{},startedAtMs:w},n);if(!D.success)return z(D.error);const k=`${$}:${l}`,R=Te($);return te({taskDefinitionArn:D.data.newTaskDefArn,previousTaskDefinitionArn:g,imageUri:k,ecrRepositoryArn:R,imageDigest:c,durationMs:D.data.durationMs})}function Te(t){const r=t.match(/^(\d{12})\.dkr\.ecr\.([a-z0-9-]+)\.amazonaws\.com\/(.+)$/);if(!r)return"";const[,e,a,l]=r;return`arn:aws:ecr:${a}:${e}:repository/${l}`}export{je as deployCodeOnly,Te as deriveEcrRepositoryArn,ke as lookupContentHashTag,ye as rebaseRollbackTagForService,x as reconcileImageTagParameters};
1
+ import{join as J}from"path";import{success as Q,failure as z}from"@fjall/generator";import{logger as b}from"@fjall/util/logger";import{artefactOutputKey as P,imageTagParameterName as re,maskSensitiveOutput as A}from"@fjall/util";import{parseDockerServicesFromManifest as ae,parseLambdaDockerEntriesFromManifest as ne}from"@fjall/util/manifest";import{APPLICATION_STACKS as G,getApplicationStackName as ie,getApplicationStepId as oe,getApplicationStepName as se}from"../../types/operations.js";import{extractEcsServiceName as j}from"../../aws/utils/arnParser.js";import{isAborted as V}from"../../aws/organisations/types.js";import{stripTagOrDigest as ce}from"../../services/infrastructure/EcrImageInspectorService.js";import{withStepLifecycle as ge}from"../stepLifecycle.js";import{registerAndRollTaskDefinition as le}from"./taskDefinitionRoll.js";import{ecrRepoUri as de}from"./dockerBuildHelper.js";import{matchesServiceName as me,matchServiceImageTagsToLiveServices as fe,preflightResolveServiceImageTagDigests as ue,resolveServiceTaskDefinition as pe}from"./serviceImageTagsRollback.js";import{executeLambdaServiceImageTagsRollout as he,matchesLambdaFunctionName as ve,preflightLambdaServiceImageTags as ke,rolloutLambdaImageTag as $e,rolloutLambdaPrimary as we}from"./lambdaCodeOnlyRollout.js";const N="codeOnlyDeploy";function ye(t,r){if(t)return r[t.name]}function Se(t,r){const e=r.toLowerCase();return t.find(a=>a.name.toLowerCase()===e)??t.find(a=>e.includes(a.name.toLowerCase()))}function De(t,r,e){const a=r.toLowerCase(),l=t.toLowerCase(),n=e.map(s=>s.toLowerCase()).filter(s=>s!==""&&l.startsWith(`${s}-`)).sort((s,v)=>v.length-s.length)[0];if(n===void 0||n===a)return t;const h=t.slice(n.length);return`${a}${h}`}const Te=0,be=1;function Z(t,r,e,a,l){a[P(t,"TaskDefinition")]=e.taskDefinitionArn,a[P(t,"PreviousTaskDefinition")]=e.previousTaskDefinitionArn,a[P(t,"ImageTag")]=r,a[P(t,"ImageUri")]=e.imageUri,a[P(t,"EcrRepositoryArn")]=e.ecrRepositoryArn,e.imageDigest!==void 0&&(a[P(t,"ImageDigest")]=e.imageDigest),l.push({serviceName:t,imageTag:r,imageUri:e.imageUri,taskDefinitionArn:e.taskDefinitionArn,previousTaskDefinitionArn:e.previousTaskDefinitionArn,...e.imageDigest!==void 0?{imageDigest:e.imageDigest}:{},...e.ecrRepositoryArn!==""?{ecrRepositoryArn:e.ecrRepositoryArn}:{}})}async function W(t,r,e,a,l){if(e.length===0)return;const n=ie(r,G.COMPUTE),h={};for(const{serviceName:v,imageTag:S}of e)h[re(v)]=S;const s=await t.cfnService.updateStackParameters(n,h,l);if(!s.success){a.onLog?.(`Rollback succeeded but the CloudFormation ImageTag parameter reconcile failed \u2014 the next full deploy may revert this rollback. Reason: ${A(s.error.message)}`,"warn");return}s.data.skippedKeys.length>0&&(a.onLog?.(`Rollback succeeded but ${s.data.skippedKeys.length} ImageTag parameter(s) were not found on stack ${n} (${s.data.skippedKeys.join(", ")}) \u2014 the next full deploy may revert those services`,"warn"),b.debug(N,"ImageTag reconcile skipped stale parameters",{stackName:n,skippedKeys:s.data.skippedKeys}))}function B(t,r,e,a){if(t.kind==="error")return r.failures.length>0?{kind:"error",error:new Error(`${t.error.message}; Lambda rollout failures: ${r.failures.join("; ")}`)}:t;if(r.failures.length>0)return{kind:"error",error:new Error(`Lambda rollout failures: ${r.failures.join("; ")}`)};const l=t.data,n={...l.outputs??{},...r.outputs};return{kind:"completed",data:{target:e.appName,deploymentType:"application",outputs:Object.keys(n).length>0?n:void 0,artefacts:[...l.artefacts,...r.artefacts],durationMs:Date.now()-a}}}async function ze(t,r,e,a,l){const{callbacks:n,options:h}=t,s=Date.now(),v=oe(G.COMPUTE,"deploy"),S=se(G.COMPUTE,"deploy");return ge(n,{stepId:v,stepName:S,stepIndex:Te,totalSteps:be},async()=>{const c=h?.imageTag,$=h?.serviceImageTags;c?n.onLog?.(`Rolling to supplied image tag ${c}`,"info"):$&&n.onLog?.(`Rolling ${Object.keys($).length} service(s) to their release-recorded image tags`,"info");const u=ae(J(e.path,"cdk.out"));b.debug(N,"Code-only rollout starting",{explicitRollbackTag:c,serviceImageTags:$,workingDirectory:t.workingDirectory,contentHashTagsByService:a,manifestServiceCount:u.length,manifestServices:u.map(i=>({name:i.name,target:i.docker.target}))}),n.onLog?.("Discovering ECS cluster and services\u2026","info");const o=await r.ecsResolver.getDeployableClusterAndServices(e.appName,t.abortSignal);if(!o.success)return b.debug(N,"ECS discovery failed",{appName:e.appName,error:A(o.error.message)}),{kind:"error",error:o.error};const{clusterArn:p,serviceArns:k}=o.data;b.debug(N,"ECS discovery complete",{appName:e.appName,clusterArn:p,serviceCount:k.length,serviceArns:k});const f=ne(J(e.path,"cdk.out")),M=Array.from(new Set(f.map(i=>i.imageKey))),x=p!==void 0&&k.length>0,U=f.length>0;if(!x&&!U){const i=`No deployable ECS services or container-image Lambda functions found for ${e.appName}`;return n.onLog?.(i,"warn"),{kind:"skipped",data:{target:e.appName,deploymentType:"application",durationMs:Date.now()-s,noChanges:!0,artefacts:[]}}}const d=p??"";if($!==void 0){const i=fe(x?k:[],$),m=await ke(r,e,$,t.abortSignal);if(!m.success)return{kind:"error",error:m.error};const g=new Set(m.data.matched.map(w=>w.entry.name));for(const w of i.unmatchedLiveServiceNames)n.onLog?.(`Service ${w} is not part of this release \u2014 leaving it untouched`,"warn");for(const w of i.staleMapKeys)g.has(w)||n.onLog?.(`Service ${w} from the release no longer exists in the stack`,"warn");if(i.matched.length===0&&g.size===0)return{kind:"error",error:new Error("None of the services in serviceImageTags matched a live ECS service or container-image Lambda function in this stack \u2014 nothing to roll")};const O=i.matched.length>0?await ue(r,d,i.matched,t.abortSignal):Q(new Map);if(!O.success)return{kind:"error",error:O.error};const I=i.matched.length>0?await Ae(r,e,d,i.matched,O.data,n,t.abortSignal,s):{kind:"completed",data:{target:e.appName,deploymentType:"application",artefacts:[],durationMs:Date.now()-s}},R=await he(r,m.data,n,t.abortSignal),y=[...I.kind==="completed"?I.data.artefacts.map(w=>({serviceName:w.serviceName,imageTag:w.imageTag})):[],...R.rolledImageKeys];return await W(r,e.appName,y,n,t.abortSignal),B(I,R,e,s)}const C=h?.serviceName?.toLowerCase(),L=C===""?void 0:C,T=L?k.filter(i=>me(j(i)??"",L)):k;if(L){const i=f.some(m=>ve(m.name,L));if(T.length===0&&!i){const m=[...k.map(g=>j(g)??"unknown"),...f.map(g=>g.name)];return{kind:"error",error:new Error(`Service '${L}' not found. Available: ${m.join(", ")||"none"}`)}}}const F={},K=[],E=[],_=[...k.map(i=>j(i)).filter(i=>i!==void 0&&i!==""),...M];for(let i=0;i<T.length;i++){if(V(t.abortSignal))return{kind:"error",error:new Error(`Rollout cancelled after ${K.length}/${T.length} services`)};const m=T[i];if(!m)continue;const g=j(m)??`service-${i+1}`,O=`[${i+1}/${T.length}] ${g}`,I=Se(u,g),R=ye(I,a);let y,w;if(c!==void 0)y=De(c,g,_),y!==c?(w=c,n.onLog?.(`Re-based image tag ${c} \u2192 ${y} for ${g}`,"info")):_.length>1&&!c.toLowerCase().startsWith(`${g.toLowerCase()}-`)&&n.onLog?.(`Image tag ${c} has no recognised service prefix; applying verbatim to ${g} \u2014 confirm it points at this service's image`,"warn");else if(R!==void 0)y=R;else{const H=`No image available to deploy for ${g}: no content-hash tag was produced this run. Run a full deploy to build the image, or pass --image-tag <tag> to roll a specific existing image.`;n.onLog?.(H,"warn"),E.push(`${g}: ${H}`);continue}b.debug(N,"Starting service rollout",{serviceName:g,serviceArn:m,imageTag:y,explicitRollbackTag:c,contentHashTag:R,manifestServiceMatched:I?.name,dockerTarget:I?.docker.target,index:i,total:T.length}),n.onECSUpdate?.(`${O}: rolling out image tag ${y}`,g);const D=await ee(r,d,m,g,y,n,w,void 0,t.abortSignal);if(b.debug(N,"Service rollout completed",{serviceName:g,success:D.success,...D.success?{taskDefinitionArn:D.data.taskDefinitionArn,imageDigest:D.data.imageDigest,durationMs:D.data.durationMs}:{error:A(D.error.message)}}),!D.success){E.push(`${g}: ${A(D.error.message)}`);continue}Z(g,y,D.data,F,K)}const te=Date.now()-s;if(E.length>0){const i=T.length-E.length,m=T.length,g=E.length===m?`All ${m} ECS service rollouts failed: ${E.join("; ")}`:`Partial rollout: ${i}/${m} services succeeded. Failures: ${E.join("; ")}`;return{kind:"error",error:new Error(g)}}const X=K.map(i=>({serviceName:i.serviceName,imageTag:i.imageTag})),Y={kind:"completed",data:{target:e.appName,deploymentType:"application",outputs:Object.keys(F).length>0?F:void 0,artefacts:K,durationMs:te}};if(!U)return c!==void 0&&await W(r,e.appName,X,n,t.abortSignal),Y;const q=c!==void 0?await $e(r,e,c,_,n,L,t.abortSignal):await we(r,e,a,l?.imageDigestsByService??{},l?.repoUri??de(r.awsProvider.getAccountId(),r.awsProvider.getRegion(),e.appName),n,L,t.abortSignal);return c!==void 0&&await W(r,e.appName,[...X,...q.rolledImageKeys],n,t.abortSignal),B(Y,q,e,s)},t.abortSignal)}async function Ae(t,r,e,a,l,n,h,s){const v={},S=[],c=[];for(let u=0;u<a.length;u++){if(V(h))return{kind:"error",error:new Error(`Rollout cancelled after ${S.length}/${a.length} services`)};const o=a[u];if(!o)continue;const p=`[${u+1}/${a.length}] ${o.serviceName}`,k=l.get(o.serviceArn);if(k===void 0){c.push(`${o.serviceName}: pre-flight digest missing after a successful pre-flight`);continue}b.debug(N,"Starting service rollout (serviceImageTags)",{serviceName:o.serviceName,serviceArn:o.serviceArn,imageTag:o.tag,mapKey:o.mapKey,index:u,total:a.length}),n.onECSUpdate?.(`${p}: rolling out image tag ${o.tag}`,o.serviceName);const f=await ee(t,e,o.serviceArn,o.serviceName,o.tag,n,void 0,k,h);if(b.debug(N,"Service rollout completed (serviceImageTags)",{serviceName:o.serviceName,success:f.success,...f.success?{taskDefinitionArn:f.data.taskDefinitionArn,imageDigest:f.data.imageDigest,durationMs:f.data.durationMs}:{error:A(f.error.message)}}),!f.success){c.push(`${o.serviceName}: ${A(f.error.message)}`);continue}Z(o.serviceName,o.tag,f.data,v,S)}const $=Date.now()-s;if(c.length>0){const u=a.length-c.length,o=a.length,p=c.length===o?`All ${o} ECS service rollouts failed: ${c.join("; ")}`:`Partial rollout: ${u}/${o} services succeeded. Failures: ${c.join("; ")}`;return{kind:"error",error:new Error(p)}}return{kind:"completed",data:{target:r.appName,deploymentType:"application",outputs:Object.keys(v).length>0?v:void 0,artefacts:S,durationMs:$}}}async function ee(t,r,e,a,l,n,h,s,v){const S=Date.now();let c,$,u,o,p;if(s!==void 0)c=s.taskDefinition.previousTaskDefArn,$=s.taskDefinition.taskDefinition,u=s.taskDefinition.containerDefinitions,o=s.taskDefinition.repoUri,p=s.imageDigest;else{const d=await pe(t,r,e,a,v);if(!d.success)return z(d.error);c=d.data.previousTaskDefArn,$=d.data.taskDefinition,u=d.data.containerDefinitions,o=d.data.repoUri;const C=await t.ecrImageInspector.getImageDigest(o,l,v);if(C.success)p=C.data;else{if(h!==void 0)return z(new Error(`Re-based image tag '${l}' (from supplied '${h}') was not found in ECR for ${a}: ${A(C.error.message)}. The supplied tag's build has no image for ${a} \u2014 supply that service's own tag, or pass --service to roll a single service.`));n.onLog?.(`Could not resolve image digest for ${a} (${A(C.error.message)}); falling back to tag pinning`,"warn")}}const k=d=>p!==void 0?`${d}@${p}`:`${d}:${l}`,f=u.map(d=>d.image?{...d,image:k(ce(d.image))}:d),M=await le(t,{clusterArn:r,serviceArn:e,serviceName:a,taskDefinition:$,containerDefinitions:f,previousTaskDefArn:c,...p!==void 0?{imageDigest:p}:{},startedAtMs:S},n,v);if(!M.success)return z(M.error);const x=`${o}:${l}`,U=Ne(o);return Q({taskDefinitionArn:M.data.newTaskDefArn,previousTaskDefinitionArn:c,imageUri:x,ecrRepositoryArn:U,imageDigest:p,durationMs:M.data.durationMs})}function Ne(t){const r=t.match(/^(\d{12})\.dkr\.ecr\.([a-z0-9-]+)\.amazonaws\.com\/(.+)$/);if(!r)return"";const[,e,a,l]=r;return`arn:aws:ecr:${a}:${e}:repository/${l}`}export{ze as deployCodeOnly,Ne as deriveEcrRepositoryArn,ye as lookupContentHashTag,De as rebaseRollbackTagForService};
@@ -10,7 +10,7 @@ import type { EcsServiceResolver } from "../../services/infrastructure/EcsServic
10
10
  * warn that endpoint stability could not be verified rather than silently
11
11
  * treating a failed read as "no endpoints".
12
12
  */
13
- export declare function captureDatabaseConnectionOutputs(cfnService: CloudFormationService, appName: string): Promise<Record<string, string> | undefined>;
13
+ export declare function captureDatabaseConnectionOutputs(cfnService: CloudFormationService, appName: string, abortSignal?: AbortSignal): Promise<Record<string, string> | undefined>;
14
14
  /**
15
15
  * Snapshot each live ECS service's current task-definition ARN before the
16
16
  * stack loop runs. The post-deploy reconcile compares these against the
@@ -26,7 +26,7 @@ export declare function captureDatabaseConnectionOutputs(cfnService: CloudFormat
26
26
  * both restart without the baseline — an extra roll is harmless, a missed one
27
27
  * is not.
28
28
  */
29
- export declare function captureServiceTaskDefinitions(ecsResolver: EcsServiceResolver, ecsService: EcsService, appName: string): Promise<Record<string, string> | undefined>;
29
+ export declare function captureServiceTaskDefinitions(ecsResolver: EcsServiceResolver, ecsService: EcsService, appName: string, abortSignal?: AbortSignal): Promise<Record<string, string> | undefined>;
30
30
  export interface DatabaseEndpointReconcileParams {
31
31
  appName: string;
32
32
  /** Pre-deploy connection-output capture; `undefined` when the read failed. */