@fjall/deploy-core 2.23.1 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/.minified +1 -1
  2. package/dist/src/aws/index.d.ts +2 -2
  3. package/dist/src/aws/index.js +1 -1
  4. package/dist/src/aws/organisations/identityCentreSnapshot.d.ts +47 -0
  5. package/dist/src/aws/organisations/identityCentreSnapshot.js +1 -0
  6. package/dist/src/aws/organisations/index.d.ts +5 -1
  7. package/dist/src/aws/organisations/index.js +1 -1
  8. package/dist/src/aws/organisations/pagination.d.ts +28 -0
  9. package/dist/src/aws/organisations/pagination.js +1 -0
  10. package/dist/src/index.d.ts +9 -5
  11. package/dist/src/index.js +1 -1
  12. package/dist/src/orchestration/application/applicationDeploy.js +1 -1
  13. package/dist/src/orchestration/application/applicationDeployHelpers.d.ts +11 -12
  14. package/dist/src/orchestration/application/applicationDeployHelpers.js +2 -2
  15. package/dist/src/orchestration/application/approvalGate.d.ts +3 -1
  16. package/dist/src/orchestration/application/approvalGate.js +1 -1
  17. package/dist/src/orchestration/application/artefactCollection.d.ts +18 -0
  18. package/dist/src/orchestration/application/artefactCollection.js +1 -0
  19. package/dist/src/orchestration/application/buildSecretSession.d.ts +8 -0
  20. package/dist/src/orchestration/application/buildSecretSession.js +1 -1
  21. package/dist/src/orchestration/application/codeOnlyDeploy.d.ts +13 -0
  22. package/dist/src/orchestration/application/codeOnlyDeploy.js +1 -1
  23. package/dist/src/orchestration/application/deploySessionPolicy.d.ts +46 -0
  24. package/dist/src/orchestration/application/deploySessionPolicy.js +1 -0
  25. package/dist/src/orchestration/application/dockerBuildHelper.d.ts +21 -5
  26. package/dist/src/orchestration/application/dockerBuildHelper.js +1 -1
  27. package/dist/src/orchestration/application/serviceImageTagsRollback.d.ts +56 -0
  28. package/dist/src/orchestration/application/serviceImageTagsRollback.js +1 -0
  29. package/dist/src/orchestration/application/taskDefinitionRoll.d.ts +33 -0
  30. package/dist/src/orchestration/application/taskDefinitionRoll.js +1 -0
  31. package/dist/src/orchestration/deploy.js +1 -1
  32. package/dist/src/orchestration/dockerInterface.d.ts +5 -2
  33. package/dist/src/orchestration/index.d.ts +5 -0
  34. package/dist/src/orchestration/index.js +1 -1
  35. package/dist/src/orchestration/organisationDeploy/orgCascadeDeploy.js +1 -1
  36. package/dist/src/orchestration/organisationDeploy/singleComponentDeploy.js +1 -1
  37. package/dist/src/orchestration/restart/restartApplication.d.ts +69 -0
  38. package/dist/src/orchestration/restart/restartApplication.js +1 -0
  39. package/dist/src/orchestration/restart/secretsDrift.d.ts +54 -0
  40. package/dist/src/orchestration/restart/secretsDrift.js +1 -0
  41. package/dist/src/services/infrastructure/CdkCommandRunner.js +2 -2
  42. package/dist/src/services/infrastructure/CdkService.d.ts +1 -1
  43. package/dist/src/services/infrastructure/CdkService.js +2 -2
  44. package/dist/src/services/infrastructure/CdkServiceTypes.d.ts +9 -0
  45. package/dist/src/services/infrastructure/CloudFormationService.d.ts +17 -0
  46. package/dist/src/services/infrastructure/CloudFormationService.js +1 -1
  47. package/dist/src/services/infrastructure/EcrImageInspectorService.d.ts +11 -1
  48. package/dist/src/services/infrastructure/EcrImageInspectorService.js +1 -1
  49. package/dist/src/services/infrastructure/SsmParameterMetadataService.d.ts +23 -0
  50. package/dist/src/services/infrastructure/SsmParameterMetadataService.js +1 -0
  51. package/dist/src/types/approval.d.ts +15 -0
  52. package/dist/src/types/index.d.ts +1 -1
  53. package/dist/src/types/params.d.ts +39 -1
  54. package/package.json +5 -4
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 174 files minified at 2026-07-02T12:17:52.811Z
1
+ 183 files minified at 2026-07-06T11:56:38.163Z
@@ -6,7 +6,7 @@ export { buildTargetSetUnreadyAdvisory } from "./targetSetAdvisory.js";
6
6
  export type { TargetSetUnreadyAdvisoryParams } from "./targetSetAdvisory.js";
7
7
  export { checkRegionEnabled, regionDisabledMessage } from "./regions/regionOptStatus.js";
8
8
  export type { RegionAvailability } from "./regions/regionOptStatus.js";
9
- export { ensureOrganisationExists, describeOrganisation, enablePolicyTypes, enableServiceAccess, SERVICE_PRINCIPALS, enableRamSharing, activateTrustedAccess, enableIpamDelegatedAdmin, updateBackupGlobalSettings, listAccounts, findAccount, createAccount, ensureOrganisationalUnitsExist, placeAccountsInOUs, buildAccountToOUMap, activateCostAllocationTags, checkIdentityCentreStatus, extractErrorName, isOULeaf, registerSecurityDelegates, SECURITY_SERVICE_PRINCIPALS, enableCentralisedRootAccess, ROOT_ACCESS_FEATURES, RootAccessEnablementError } from "./organisations/index.js";
10
- export type { OrgDetails, OUMap, OUTree, AccountPlacementResult, AccountInfo, IdentityCentreStatus, BackupGlobalSettings, CostAllocationTag, CreateAccountResult, RootAccessFeature, RootAccessEnablementSummary } from "./organisations/index.js";
9
+ export { ensureOrganisationExists, describeOrganisation, enablePolicyTypes, enableServiceAccess, SERVICE_PRINCIPALS, enableRamSharing, activateTrustedAccess, enableIpamDelegatedAdmin, updateBackupGlobalSettings, listAccounts, findAccount, createAccount, ensureOrganisationalUnitsExist, placeAccountsInOUs, buildAccountToOUMap, activateCostAllocationTags, checkIdentityCentreStatus, snapshotIdentityCentre, composeSdkAbortSignal, extractErrorName, isAborted, isOULeaf, DEFAULT_MAX_PAGES, IDENTITY_STORE_PAGE_SIZE, drainPages, registerSecurityDelegates, SECURITY_SERVICE_PRINCIPALS, enableCentralisedRootAccess, ROOT_ACCESS_FEATURES, RootAccessEnablementError } from "./organisations/index.js";
10
+ export type { OrgDetails, OUMap, OUTree, AccountPlacementResult, AccountInfo, DrainPagesOptions, PagedResult, IdentityCentreStatus, IdentityCentreSnapshot, IdentityCentreSnapshotGroup, IdentityCentreSnapshotOptions, IdentityCentreSnapshotResult, IdentityCentreSnapshotUser, BackupGlobalSettings, CostAllocationTag, CreateAccountResult, RootAccessFeature, RootAccessEnablementSummary } from "./organisations/index.js";
11
11
  export { CloudFormationEventMonitor } from "./utils/cloudformationEvents.js";
12
12
  export type { AwsClientLike, EventLogWriter, EventFailureAnalyser, EventLogWriterFactory, EventMonitorDeps } from "./utils/cloudformationEvents.js";
@@ -1 +1 @@
1
- import{SimpleAwsProvider as a}from"./SimpleAwsProvider.js";import{checkTargetReadiness as s,describeTargetReadinessReason as o,buildTargetUnreadyAdvisory as n,probeAccountStackExists as i}from"./targetReadiness.js";import{buildTargetSetUnreadyAdvisory as l}from"./targetSetAdvisory.js";import{checkRegionEnabled as A,regionDisabledMessage as u}from"./regions/regionOptStatus.js";import{ensureOrganisationExists as E,describeOrganisation as S,enablePolicyTypes as b,enableServiceAccess as p,SERVICE_PRINCIPALS as R,enableRamSharing as m,activateTrustedAccess as C,enableIpamDelegatedAdmin as T,updateBackupGlobalSettings as x,listAccounts as I,findAccount as f,createAccount as y,ensureOrganisationalUnitsExist as O,placeAccountsInOUs as U,buildAccountToOUMap as v,activateCostAllocationTags as P,checkIdentityCentreStatus as k,extractErrorName as _,isOULeaf as h,registerSecurityDelegates as D,SECURITY_SERVICE_PRINCIPALS as L,enableCentralisedRootAccess as M,ROOT_ACCESS_FEATURES as N,RootAccessEnablementError as F}from"./organisations/index.js";import{CloudFormationEventMonitor as w}from"./utils/cloudformationEvents.js";export{w as CloudFormationEventMonitor,N as ROOT_ACCESS_FEATURES,F as RootAccessEnablementError,L as SECURITY_SERVICE_PRINCIPALS,R as SERVICE_PRINCIPALS,a as SimpleAwsProvider,P as activateCostAllocationTags,C as activateTrustedAccess,v as buildAccountToOUMap,l as buildTargetSetUnreadyAdvisory,n as buildTargetUnreadyAdvisory,k as checkIdentityCentreStatus,A as checkRegionEnabled,s as checkTargetReadiness,y as createAccount,S as describeOrganisation,o as describeTargetReadinessReason,M as enableCentralisedRootAccess,T as enableIpamDelegatedAdmin,b as enablePolicyTypes,m as enableRamSharing,p as enableServiceAccess,E as ensureOrganisationExists,O as ensureOrganisationalUnitsExist,_ as extractErrorName,f as findAccount,h as isOULeaf,I as listAccounts,U as placeAccountsInOUs,i as probeAccountStackExists,u as regionDisabledMessage,D as registerSecurityDelegates,x as updateBackupGlobalSettings};
1
+ import{SimpleAwsProvider as a}from"./SimpleAwsProvider.js";import{checkTargetReadiness as s,describeTargetReadinessReason as o,buildTargetUnreadyAdvisory as n,probeAccountStackExists as i}from"./targetReadiness.js";import{buildTargetSetUnreadyAdvisory as d}from"./targetSetAdvisory.js";import{checkRegionEnabled as A,regionDisabledMessage as E}from"./regions/regionOptStatus.js";import{ensureOrganisationExists as g,describeOrganisation as b,enablePolicyTypes as u,enableServiceAccess as p,SERVICE_PRINCIPALS as R,enableRamSharing as T,activateTrustedAccess as m,enableIpamDelegatedAdmin as I,updateBackupGlobalSettings as C,listAccounts as x,findAccount as _,createAccount as y,ensureOrganisationalUnitsExist as O,placeAccountsInOUs as P,buildAccountToOUMap as U,activateCostAllocationTags as f,checkIdentityCentreStatus as v,snapshotIdentityCentre as k,composeSdkAbortSignal as h,extractErrorName as D,isAborted as L,isOULeaf as M,DEFAULT_MAX_PAGES as N,IDENTITY_STORE_PAGE_SIZE as F,drainPages as G,registerSecurityDelegates as V,SECURITY_SERVICE_PRINCIPALS as Y,enableCentralisedRootAccess as w,ROOT_ACCESS_FEATURES as B,RootAccessEnablementError as X}from"./organisations/index.js";import{CloudFormationEventMonitor as j}from"./utils/cloudformationEvents.js";export{j as CloudFormationEventMonitor,N as DEFAULT_MAX_PAGES,F as IDENTITY_STORE_PAGE_SIZE,B as ROOT_ACCESS_FEATURES,X as RootAccessEnablementError,Y as SECURITY_SERVICE_PRINCIPALS,R as SERVICE_PRINCIPALS,a as SimpleAwsProvider,f as activateCostAllocationTags,m as activateTrustedAccess,U as buildAccountToOUMap,d as buildTargetSetUnreadyAdvisory,n as buildTargetUnreadyAdvisory,v as checkIdentityCentreStatus,A as checkRegionEnabled,s as checkTargetReadiness,h as composeSdkAbortSignal,y as createAccount,b as describeOrganisation,o as describeTargetReadinessReason,G as drainPages,w as enableCentralisedRootAccess,I as enableIpamDelegatedAdmin,u as enablePolicyTypes,T as enableRamSharing,p as enableServiceAccess,g as ensureOrganisationExists,O as ensureOrganisationalUnitsExist,D as extractErrorName,_ as findAccount,L as isAborted,M as isOULeaf,x as listAccounts,P as placeAccountsInOUs,i as probeAccountStackExists,E as regionDisabledMessage,V as registerSecurityDelegates,k as snapshotIdentityCentre,C as updateBackupGlobalSettings};
@@ -0,0 +1,47 @@
1
+ import { type IdentitystoreClient } from "@aws-sdk/client-identitystore";
2
+ import { type SSOAdminClient } from "@aws-sdk/client-sso-admin";
3
+ import { type Result } from "@fjall/generator";
4
+ /**
5
+ * Read-only Identity Centre snapshot for post-deploy consumers (the webapp
6
+ * deployment worker persists it to map org members to AWS access by email).
7
+ * Design: aiDocs/designs/2026-07-04-org-user-management-design.md § W6.
8
+ */
9
+ export interface IdentityCentreSnapshotUser {
10
+ userId: string;
11
+ userName?: string;
12
+ email?: string;
13
+ displayName?: string;
14
+ }
15
+ export interface IdentityCentreSnapshotGroup {
16
+ groupId: string;
17
+ displayName?: string;
18
+ description?: string;
19
+ memberUserIds: string[];
20
+ }
21
+ export interface IdentityCentreSnapshot {
22
+ instanceArn: string;
23
+ identityStoreId: string;
24
+ users: IdentityCentreSnapshotUser[];
25
+ groups: IdentityCentreSnapshotGroup[];
26
+ /** True when any listing stopped at the page budget — counts understate. */
27
+ truncated: boolean;
28
+ }
29
+ export type IdentityCentreSnapshotResult = {
30
+ status: "no-instance";
31
+ } | {
32
+ status: "captured";
33
+ snapshot: IdentityCentreSnapshot;
34
+ };
35
+ export interface IdentityCentreSnapshotOptions {
36
+ abortSignal?: AbortSignal;
37
+ /** Page budget per listing call family. Default: DEFAULT_MAX_PAGES in pagination.ts (~1000 items at 50/page). */
38
+ maxPages?: number;
39
+ }
40
+ /**
41
+ * Capture the live Identity Centre state: instance, users (with emails),
42
+ * groups, and group memberships. All reads are paginated under a page budget
43
+ * and abort-composed; truncation is reported, never silent. Zero instances is
44
+ * a first-class outcome ("no-instance"), not an error — orgs without Identity
45
+ * Centre enabled are expected.
46
+ */
47
+ export declare function snapshotIdentityCentre(ssoAdminClient: SSOAdminClient, identitystoreClient: IdentitystoreClient, options?: IdentityCentreSnapshotOptions): Promise<Result<IdentityCentreSnapshotResult>>;
@@ -0,0 +1 @@
1
+ import{ListGroupMembershipsCommand as N,ListGroupsCommand as M,ListUsersCommand as w}from"@aws-sdk/client-identitystore";import{ListInstancesCommand as x}from"@aws-sdk/client-sso-admin";import{success as g,failure as o}from"@fjall/generator";import{getErrorMessage as T,maskSensitiveOutput as U}from"@fjall/util";import{composeSdkAbortSignal as u,isAborted as h}from"./types.js";import{IDENTITY_STORE_PAGE_SIZE as p,drainPages as f}from"./pagination.js";function m(c,s){return new Error(`Failed to ${c}: ${U(T(s))}`)}async function L(c,s,n={}){let y,a;try{const r=((await c.send(new x({}),{abortSignal:u(n.abortSignal)})).Instances??[])[0];if(r?.InstanceArn===void 0||r.IdentityStoreId===void 0)return g({status:"no-instance"});y=r.InstanceArn,a=r.IdentityStoreId}catch(t){return o(m("list Identity Centre instances",t))}let l;try{l=await f(async t=>{const r=await s.send(new w({IdentityStoreId:a,MaxResults:p,...t!==void 0&&{NextToken:t}}),{abortSignal:u(n.abortSignal)});return{items:(r.Users??[]).flatMap(e=>e.UserId===void 0?[]:[{userId:e.UserId,...e.UserName!==void 0&&{userName:e.UserName},...e.Emails?.[0]?.Value!==void 0&&{email:e.Emails[0].Value},...e.DisplayName!==void 0&&{displayName:e.DisplayName}}]),nextToken:r.NextToken}},n)}catch(t){return o(m("list identity store users",t))}let I;try{I=await f(async t=>{const r=await s.send(new M({IdentityStoreId:a,MaxResults:p,...t!==void 0&&{NextToken:t}}),{abortSignal:u(n.abortSignal)});return{items:(r.Groups??[]).flatMap(e=>e.GroupId===void 0?[]:[{groupId:e.GroupId,...e.DisplayName!==void 0&&{displayName:e.DisplayName},...e.Description!==void 0&&{description:e.Description}}]),nextToken:r.NextToken}},n)}catch(t){return o(m("list identity store groups",t))}const S=[];let i=!1;for(const t of I.items){if(h(n.abortSignal)){i=!0;break}let r;try{r=await f(async e=>{const b=await s.send(new N({IdentityStoreId:a,GroupId:t.groupId,MaxResults:p,...e!==void 0&&{NextToken:e}}),{abortSignal:u(n.abortSignal)});return{items:(b.GroupMemberships??[]).flatMap(d=>d.MemberId!==void 0&&"UserId"in d.MemberId&&d.MemberId.UserId!==void 0?[d.MemberId.UserId]:[]),nextToken:b.NextToken}},n)}catch(e){return o(m(`list memberships for group "${t.displayName??t.groupId}"`,e))}i=i||r.truncated,S.push({...t,memberUserIds:r.items})}return g({status:"captured",snapshot:{instanceArn:y,identityStoreId:a,users:l.items,groups:S,truncated:l.truncated||I.truncated||i}})}export{L as snapshotIdentityCentre};
@@ -1,5 +1,7 @@
1
1
  export type { OrgDetails, OUMap, OUTree, AccountPlacementResult, AccountInfo, IdentityCentreStatus } from "./types.js";
2
- export { extractErrorName, isOULeaf } from "./types.js";
2
+ export { composeSdkAbortSignal, extractErrorName, isAborted, isOULeaf } from "./types.js";
3
+ export { DEFAULT_MAX_PAGES, IDENTITY_STORE_PAGE_SIZE, drainPages } from "./pagination.js";
4
+ export type { DrainPagesOptions, PagedResult } from "./pagination.js";
3
5
  export type { BackupGlobalSettings } from "./backup.js";
4
6
  export type { CostAllocationTag } from "./costAllocation.js";
5
7
  export type { CreateAccountResult } from "./accounts.js";
@@ -15,5 +17,7 @@ export { listAccounts, findAccount, createAccount } from "./accounts.js";
15
17
  export { ensureOrganisationalUnitsExist, placeAccountsInOUs, buildAccountToOUMap } from "./organisationalUnits.js";
16
18
  export { activateCostAllocationTags } from "./costAllocation.js";
17
19
  export { checkIdentityCentreStatus } from "./identityCentre.js";
20
+ export { snapshotIdentityCentre } from "./identityCentreSnapshot.js";
21
+ export type { IdentityCentreSnapshot, IdentityCentreSnapshotGroup, IdentityCentreSnapshotOptions, IdentityCentreSnapshotResult, IdentityCentreSnapshotUser } from "./identityCentreSnapshot.js";
18
22
  export { registerSecurityDelegates, SECURITY_SERVICE_PRINCIPALS } from "./delegatedAdmin.js";
19
23
  export { enableCentralisedRootAccess, ROOT_ACCESS_FEATURES, RootAccessEnablementError } from "./rootAccess.js";
@@ -1 +1 @@
1
- import{extractErrorName as r,isOULeaf as o}from"./types.js";import{ensureOrganisationExists as s,describeOrganisation as c}from"./organisation.js";import{enablePolicyTypes as i}from"./policies.js";import{enableServiceAccess as m,SERVICE_PRINCIPALS as l}from"./serviceAccess.js";import{enableRamSharing as f}from"./ram.js";import{activateTrustedAccess as u}from"./trustedAccess.js";import{enableIpamDelegatedAdmin as S}from"./ipam.js";import{updateBackupGlobalSettings as I}from"./backup.js";import{listAccounts as b,findAccount as d,createAccount as g}from"./accounts.js";import{ensureOrganisationalUnitsExist as T,placeAccountsInOUs as U,buildAccountToOUMap as P}from"./organisationalUnits.js";import{activateCostAllocationTags as y}from"./costAllocation.js";import{checkIdentityCentreStatus as L}from"./identityCentre.js";import{registerSecurityDelegates as h,SECURITY_SERVICE_PRINCIPALS as k}from"./delegatedAdmin.js";import{enableCentralisedRootAccess as V,ROOT_ACCESS_FEATURES as B,RootAccessEnablementError as F}from"./rootAccess.js";export{B as ROOT_ACCESS_FEATURES,F as RootAccessEnablementError,k as SECURITY_SERVICE_PRINCIPALS,l as SERVICE_PRINCIPALS,y as activateCostAllocationTags,u as activateTrustedAccess,P as buildAccountToOUMap,L as checkIdentityCentreStatus,g as createAccount,c as describeOrganisation,V as enableCentralisedRootAccess,S as enableIpamDelegatedAdmin,i as enablePolicyTypes,f as enableRamSharing,m as enableServiceAccess,s as ensureOrganisationExists,T as ensureOrganisationalUnitsExist,r as extractErrorName,d as findAccount,o as isOULeaf,b as listAccounts,U as placeAccountsInOUs,h as registerSecurityDelegates,I as updateBackupGlobalSettings};
1
+ import{composeSdkAbortSignal as r,extractErrorName as o,isAborted as a,isOULeaf as s}from"./types.js";import{DEFAULT_MAX_PAGES as c,IDENTITY_STORE_PAGE_SIZE as i,drainPages as p}from"./pagination.js";import{ensureOrganisationExists as A,describeOrganisation as l}from"./organisation.js";import{enablePolicyTypes as E}from"./policies.js";import{enableServiceAccess as S,SERVICE_PRINCIPALS as I}from"./serviceAccess.js";import{enableRamSharing as u}from"./ram.js";import{activateTrustedAccess as g}from"./trustedAccess.js";import{enableIpamDelegatedAdmin as R}from"./ipam.js";import{updateBackupGlobalSettings as _}from"./backup.js";import{listAccounts as P,findAccount as U,createAccount as y}from"./accounts.js";import{ensureOrganisationalUnitsExist as L,placeAccountsInOUs as N,buildAccountToOUMap as h}from"./organisationalUnits.js";import{activateCostAllocationTags as v}from"./costAllocation.js";import{checkIdentityCentreStatus as F}from"./identityCentre.js";import{snapshotIdentityCentre as V}from"./identityCentreSnapshot.js";import{registerSecurityDelegates as B,SECURITY_SERVICE_PRINCIPALS as X}from"./delegatedAdmin.js";import{enableCentralisedRootAccess as j,ROOT_ACCESS_FEATURES as q,RootAccessEnablementError as w}from"./rootAccess.js";export{c as DEFAULT_MAX_PAGES,i as IDENTITY_STORE_PAGE_SIZE,q as ROOT_ACCESS_FEATURES,w as RootAccessEnablementError,X as SECURITY_SERVICE_PRINCIPALS,I as SERVICE_PRINCIPALS,v as activateCostAllocationTags,g as activateTrustedAccess,h as buildAccountToOUMap,F as checkIdentityCentreStatus,r as composeSdkAbortSignal,y as createAccount,l as describeOrganisation,p as drainPages,j as enableCentralisedRootAccess,R as enableIpamDelegatedAdmin,E as enablePolicyTypes,u as enableRamSharing,S as enableServiceAccess,A as ensureOrganisationExists,L as ensureOrganisationalUnitsExist,o as extractErrorName,U as findAccount,a as isAborted,s as isOULeaf,P as listAccounts,N as placeAccountsInOUs,B as registerSecurityDelegates,V as snapshotIdentityCentre,_ as updateBackupGlobalSettings};
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Canonical pagination helpers for identity-store style AWS list APIs.
3
+ * Shared by the Identity Centre snapshot (deploy-core) and the CLI
4
+ * identity-store lister — the page size and page budget are coupled
5
+ * values that must move together, so both consumers import from here.
6
+ */
7
+ export declare const DEFAULT_MAX_PAGES = 20;
8
+ /** MaxResults sent on every identity-store list call (~1000 items under the default page budget). */
9
+ export declare const IDENTITY_STORE_PAGE_SIZE = 50;
10
+ export interface PagedResult<T> {
11
+ items: T[];
12
+ /** True when the abort signal fired or the page budget ran out. */
13
+ truncated: boolean;
14
+ }
15
+ export interface DrainPagesOptions {
16
+ abortSignal?: AbortSignal;
17
+ /** Page budget per listing call. Default {@link DEFAULT_MAX_PAGES}. */
18
+ maxPages?: number;
19
+ }
20
+ /**
21
+ * Drain a paginated listing under a page budget with a per-page abort
22
+ * pre-check. Truncation (budget exhausted or abort) is reported, never
23
+ * silent.
24
+ */
25
+ export declare function drainPages<T>(fetchPage: (nextToken: string | undefined) => Promise<{
26
+ items: T[];
27
+ nextToken: string | undefined;
28
+ }>, options?: DrainPagesOptions): Promise<PagedResult<T>>;
@@ -0,0 +1 @@
1
+ import{isAborted as i}from"./types.js";const c=20,d=50;async function x(o,n={}){const s=n.maxPages??c,e=[];let t,a=0;do{if(i(n.abortSignal)||a>=s)return{items:e,truncated:!0};const r=await o(t);e.push(...r.items),t=r.nextToken,a+=1}while(t!==void 0);return{items:e,truncated:!1}}export{c as DEFAULT_MAX_PAGES,d as IDENTITY_STORE_PAGE_SIZE,x as drainPages};
@@ -15,15 +15,15 @@ export { DeploymentEventSchema, DEPLOYMENT_EVENT_TYPES, DEPLOYMENT_EVENT_RESOURC
15
15
  export type { DeploymentEvent, DeploymentEventType, DeploymentEventResourceCategory, DeploymentEventCascadePhase, DeploymentEventCascadeAccountStatus } from "./types/index.js";
16
16
  export { DeployEventSchema, StepProgressSchema, DeployResourceSchema, PlanChangeSchema, PlanPropertyChangeSchema, ChangeCountsSchema, DEPLOY_EVENT_CONTRACT, DEPLOY_EVENT_CONTRACT_MAJOR, DEPLOY_EVENT_CONTRACT_MINOR, SUPPORTED_CONTRACT_MARKERS, DEPLOY_EVENT_ID_MAX, DEPLOY_EVENT_NAME_MAX, DEPLOY_EVENT_MESSAGE_MAX, DEPLOY_EVENT_STATUS_REASON_MAX, DEPLOY_EVENT_ERROR_MESSAGE_MAX, DEPLOY_EVENT_TRAIL_DETAIL_MAX, DEPLOY_EVENT_OUTPUT_MAX, DEPLOY_EVENT_ARN_MAX, DEPLOY_EVENT_URL_MAX, STEP_COMPLETE_STATUSES, LOG_LEVELS, STACK_CLEANUP_PHASES, CASCADE_ACCOUNT_PHASES, DEPLOY_RESULTS, DETECTION_PHASES, PHASE_STATUSES, BUILDERS, CASCADE_OUTCOME_RESULTS, PLAN_ACTIONS, REPLACEMENT_MODES, APPROVAL_KINDS, APPROVAL_DECISIONS, ALL_PROGRESS_KINDS, createDeployEmitter, parseDeployEvent, parseDeployContractVersion } from "./types/index.js";
17
17
  export type { DeployEvent, ProgressKind, StepProgress, DeployResource, PlanChange, PlanPropertyChange, ChangeCounts, PlanAction, ReplacementMode, ApprovalKind, ApprovalDecision, DeployRunResult, DeployEmitter, CreateDeployEmitterOptions, ParsedDeployEvent, StackCleanupPhase, CascadeAccountPhase, LogLevel } from "./types/index.js";
18
- export type { AwsCredentials, DeployIdentity, ScopedBuildSecretSessionMinter, DeployCallbacks, StepCompleteStatus, StackCleanupQuarantineDetail, StackCleanupRetainedBucketsDetail, ProgressEvent, ProgressEventType, ResourceEvent, AwsAuthResult, CascadeDeploymentResult, CascadePhase, BuildPushStartEvent, BuildPushProgressEvent, BuildPushCompleteEvent, TaskDefRegisteredEvent, ECSCompleteEvent, MigrationsStartEvent, MigrationsCompleteEvent, TrailMigrationPhase, TrailMigrationStatus, TrailMigrationPhaseEvent, ApiClientInterface, EntitlementsData, DeployParams, DeployOptions, DeploymentType, DeployResult, DestroyParams, DestroyOptions, DestroyResult, ApprovalGate, ApprovalRequest, GateResolution, OrgConfig, ProviderAccount, RootAccessManagementMode, SSOSession, Entitlements } from "./types/index.js";
18
+ export type { AwsCredentials, DeployIdentity, ScopedBuildSecretSessionMinter, DeployCallbacks, StepCompleteStatus, StackCleanupQuarantineDetail, StackCleanupRetainedBucketsDetail, ProgressEvent, ProgressEventType, ResourceEvent, AwsAuthResult, CascadeDeploymentResult, CascadePhase, BuildPushStartEvent, BuildPushProgressEvent, BuildPushCompleteEvent, TaskDefRegisteredEvent, ECSCompleteEvent, MigrationsStartEvent, MigrationsCompleteEvent, TrailMigrationPhase, TrailMigrationStatus, TrailMigrationPhaseEvent, ApiClientInterface, EntitlementsData, DeployParams, DeployOptions, DeploymentType, DeployResult, DestroyParams, DestroyOptions, DestroyResult, ApprovalGate, ApprovalGatePlanDetail, ApprovalRequest, GateResolution, OrgConfig, ProviderAccount, RootAccessManagementMode, SSOSession, Entitlements } from "./types/index.js";
19
19
  export type { AwsProvider, AwsProviderCredentials, AwsSdkClientConstructor } from "./aws/index.js";
20
20
  export { SimpleAwsProvider } from "./aws/index.js";
21
21
  export { checkTargetReadiness, describeTargetReadinessReason, buildTargetUnreadyAdvisory, buildTargetSetUnreadyAdvisory, probeAccountStackExists } from "./aws/index.js";
22
22
  export type { TargetReadinessAccount, TargetReadinessClients, TargetReadinessReason, TargetReadinessVerdict, TargetSetUnreadyAdvisoryParams } from "./aws/index.js";
23
23
  export { checkRegionEnabled, regionDisabledMessage } from "./aws/index.js";
24
24
  export type { RegionAvailability } from "./aws/index.js";
25
- export { ensureOrganisationExists, describeOrganisation, enablePolicyTypes, enableServiceAccess, SERVICE_PRINCIPALS, enableRamSharing, activateTrustedAccess, enableIpamDelegatedAdmin, updateBackupGlobalSettings, listAccounts, findAccount, createAccount, ensureOrganisationalUnitsExist, placeAccountsInOUs, buildAccountToOUMap, activateCostAllocationTags, checkIdentityCentreStatus, extractErrorName, isOULeaf, registerSecurityDelegates, SECURITY_SERVICE_PRINCIPALS, enableCentralisedRootAccess, ROOT_ACCESS_FEATURES, RootAccessEnablementError } from "./aws/index.js";
26
- export type { OrgDetails, OUMap, OUTree, AccountPlacementResult, AccountInfo, IdentityCentreStatus, BackupGlobalSettings, CostAllocationTag, CreateAccountResult, RootAccessFeature, RootAccessEnablementSummary } from "./aws/index.js";
25
+ export { ensureOrganisationExists, describeOrganisation, enablePolicyTypes, enableServiceAccess, SERVICE_PRINCIPALS, enableRamSharing, activateTrustedAccess, enableIpamDelegatedAdmin, updateBackupGlobalSettings, listAccounts, findAccount, createAccount, ensureOrganisationalUnitsExist, placeAccountsInOUs, buildAccountToOUMap, activateCostAllocationTags, checkIdentityCentreStatus, snapshotIdentityCentre, composeSdkAbortSignal, extractErrorName, isAborted, DEFAULT_MAX_PAGES, IDENTITY_STORE_PAGE_SIZE, drainPages, isOULeaf, registerSecurityDelegates, SECURITY_SERVICE_PRINCIPALS, enableCentralisedRootAccess, ROOT_ACCESS_FEATURES, RootAccessEnablementError } from "./aws/index.js";
26
+ export type { OrgDetails, OUMap, OUTree, AccountPlacementResult, AccountInfo, DrainPagesOptions, PagedResult, IdentityCentreStatus, IdentityCentreSnapshot, IdentityCentreSnapshotGroup, IdentityCentreSnapshotOptions, IdentityCentreSnapshotResult, IdentityCentreSnapshotUser, BackupGlobalSettings, CostAllocationTag, CreateAccountResult, RootAccessFeature, RootAccessEnablementSummary } from "./aws/index.js";
27
27
  export { STEP_IDS, STEP_NAMES, INFRASTRUCTURE_STEP_NAMES, INFRA_STEP_NAME } from "./types/index.js";
28
28
  export type { StepId, InfrastructureStepName, StepDefinition, StepDeploymentType, Operation, StepContext } from "./types/index.js";
29
29
  export type { DeploymentContext, StepOutput, ApplicationDeploymentContext, CallerIdentity, StackOutput, StackOutputsRecord, ValidationResult, DetectionResult, ProgressCallbacks, ApplicationStack, OrganisationType, DeploymentOperation, ApplicationOperation, OrganisationOperation, DeployOrderOptions, ParallelDeployGroupKey, ParallelDestroyGroupKey, OpenNextPattern, AppResourceFlags, ParallelDeploymentResult, ParallelDeployGroup, ParallelOperation, ParallelOperationType, ParallelOperationState, ApplicationErrorType, StackDeploymentData, StackDeploymentOptions, ApplicationDeploymentData, ApplicationDestructionData, FjallStateFile, TemplateHashEntry } from "./types/index.js";
@@ -35,13 +35,17 @@ export type { CdkContext, CdkOptions, CdkOutput, CheckDifferencesResult, CdkServ
35
35
  export { CdkError } from "./types/errors/index.js";
36
36
  export { type ServiceErrorDetails, type ServiceError, BaseServiceError, ValidationError, AuthError, AwsError, DeploymentError, NetworkError, FileSystemError, ConfigError, toServiceError } from "./types/errors/index.js";
37
37
  export { filterDangerousEnvVars, maskSensitiveOutput, parseShellArgs, sleep } from "@fjall/util";
38
+ export { artefactOutputKey, DeployModeSchema, ServiceArtefactSchema, ServiceArtefactsSchema, type ArtefactOutputField, type DeployMode, type ServiceArtefact, type ServiceArtefacts } from "@fjall/util";
38
39
  export { hasDockerfile } from "./util/dockerfileDetection.js";
40
+ export { sleepAbortable } from "./util/sleepAbortable.js";
39
41
  export { createSequencedCallbacks } from "./util/sequencedCallbacks.js";
40
42
  export type { CallbackMetadata, SequencedCallbackEvent, SequencedCallbacksResult } from "./util/sequencedCallbacks.js";
41
43
  export { fileExists } from "@fjall/util/fsHelpers";
42
44
  export { type Result, success, failure, isSuccess, isFailure } from "@fjall/generator";
43
45
  export { deploy } from "./orchestration/index.js";
44
46
  export { destroy } from "./orchestration/index.js";
47
+ export { restart, probeSecretsDrift, computeSecretsDrift, deriveStaleParameters, extractConsumedSsmParameters } from "./orchestration/index.js";
48
+ export type { RestartParams, RestartResult, SecretsDriftProbeParams, ApplicationSecretsDrift, ServiceSecretsDrift, StaleParameter } from "./orchestration/index.js";
45
49
  export { partitionAccounts } from "./orchestration/index.js";
46
50
  export { buildRegionList, buildAccountRegionPairs, cascadeHomeRegion, cascadeOperationKey } from "./orchestration/index.js";
47
51
  export type { AccountRegionPair } from "./orchestration/index.js";
@@ -64,8 +68,8 @@ export type { AccountsConfig } from "./orchestration/index.js";
64
68
  export { runOpenNextBuild } from "./orchestration/index.js";
65
69
  export { runOrganisationSetup, ORG_SETUP_PHASES } from "./orchestration/index.js";
66
70
  export type { OrgSetupPhase, OrgSetupCallbacks, OrgSetupConfig, OrgSetupResult, DockerProvider, DockerProgressCallback, DockerBuildParams, DockerBuildResult, ResolvedBuildSecret, ResolvedBuildSecrets, ECRInitParams, ECRInitResult, TagImagesParams, TagImagesResult, TagByDigestParams, DomainDeployProvider, DomainConfig, DomainDeployResult, DeployServices } from "./orchestration/index.js";
67
- export { resolveBuildSecrets, resolveSecretRefValue, resolveBuildSecretSessionProvider, sourcedRefsFromBuildArgs, resolveBuildArgs, buildBuildSecretSessionPolicy, partitionForRegion, validateBuildGroup } from "./orchestration/index.js";
68
- export type { ResolveBuildArgsContext, ResolveBuildArgsResult, SourcedBuildArgResolver, BuildSecretRef, BuildSecretSessionContext, ValidateBuildGroupInput, BuildGroupMemberInputs } from "./orchestration/index.js";
71
+ export { resolveBuildSecrets, resolveSecretRefValue, resolveBuildSecretSessionProvider, sourcedRefsFromBuildArgs, resolveBuildArgs, buildBuildSecretSessionPolicy, buildDeploySessionPolicy, partitionForRegion, validateBuildGroup } from "./orchestration/index.js";
72
+ export type { ResolveBuildArgsContext, ResolveBuildArgsResult, SourcedBuildArgResolver, BuildSecretRef, BuildSecretSessionContext, DeploySessionContext, ValidateBuildGroupInput, BuildGroupMemberInputs } from "./orchestration/index.js";
69
73
  export type { FrameworkBuilder, FrameworkDetection, BuildPlan, BuildCommand, BuildCallbacks, DetectionContext, BuildOptions } from "./types/index.js";
70
74
  export { FrameworkRegistry, type ResolvedBuilder } from "./orchestration/index.js";
71
75
  export { openNextBuilder, dockerBuilder } 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 E,DEPLOYMENT_EVENT_STATUS_REASON_MAX as a,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as i,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as s,CASCADE_PHASES as S,CASCADE_ACCOUNT_STATUSES as n}from"./types/index.js";import{DeployEventSchema as A,StepProgressSchema as T,DeployResourceSchema as _,PlanChangeSchema as l,PlanPropertyChangeSchema as p,ChangeCountsSchema as O,DEPLOY_EVENT_CONTRACT as P,DEPLOY_EVENT_CONTRACT_MAJOR as R,DEPLOY_EVENT_CONTRACT_MINOR as u,SUPPORTED_CONTRACT_MARKERS as m,DEPLOY_EVENT_ID_MAX as C,DEPLOY_EVENT_NAME_MAX as N,DEPLOY_EVENT_MESSAGE_MAX as d,DEPLOY_EVENT_STATUS_REASON_MAX as D,DEPLOY_EVENT_ERROR_MESSAGE_MAX as L,DEPLOY_EVENT_TRAIL_DETAIL_MAX as g,DEPLOY_EVENT_OUTPUT_MAX as f,DEPLOY_EVENT_ARN_MAX as I,DEPLOY_EVENT_URL_MAX as x,STEP_COMPLETE_STATUSES as U,LOG_LEVELS as y,STACK_CLEANUP_PHASES as M,CASCADE_ACCOUNT_PHASES as v,DEPLOY_RESULTS as k,DETECTION_PHASES as Y,PHASE_STATUSES as V,BUILDERS as h,CASCADE_OUTCOME_RESULTS as F,PLAN_ACTIONS as B,REPLACEMENT_MODES as b,APPROVAL_KINDS as G,APPROVAL_DECISIONS as K,ALL_PROGRESS_KINDS as X,createDeployEmitter as H,parseDeployEvent as w,parseDeployContractVersion as j}from"./types/index.js";import{SimpleAwsProvider as q}from"./aws/index.js";import{checkTargetReadiness as W,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 ie,enablePolicyTypes as se,enableServiceAccess as Se,SERVICE_PRINCIPALS as ne,enableRamSharing as ce,activateTrustedAccess as Ae,enableIpamDelegatedAdmin as Te,updateBackupGlobalSettings as _e,listAccounts as le,findAccount as pe,createAccount as Oe,ensureOrganisationalUnitsExist as Pe,placeAccountsInOUs as Re,buildAccountToOUMap as ue,activateCostAllocationTags as me,checkIdentityCentreStatus as Ce,extractErrorName as Ne,isOULeaf as de,registerSecurityDelegates as De,SECURITY_SERVICE_PRINCIPALS as Le,enableCentralisedRootAccess as ge,ROOT_ACCESS_FEATURES as fe,RootAccessEnablementError as Ie}from"./aws/index.js";import{STEP_IDS as Ue,STEP_NAMES as ye,INFRASTRUCTURE_STEP_NAMES as Me,INFRA_STEP_NAME as ve}from"./types/index.js";import{ProgressReporter as Ye,APPLICATION_STACKS as Ve,ORGANISATION_TYPES as he,APPLICATION_DEPLOY_ORDER as Fe,APPLICATION_DESTROY_ORDER as Be,OPENNEXT_DEPLOY_ORDER as be,OPENNEXT_DESTROY_ORDER as Ge,PARALLEL_DEPLOY_GROUPS as Ke,PARALLEL_DESTROY_GROUPS as Xe,OPENNEXT_PARALLEL_GROUPS as He,PARALLEL_OPERATION_TYPES as we,isApplicationOperation as je,isOrganisationOperation as Qe,getParallelDeployGroups as qe,getParallelDestroyGroups as Je,getApplicationDeployOrder as We,getApplicationDestroyOrder as ze,getApplicationStackName as Ze,getOrganisationStackName as $e,isApplicationStack as er,isQuarantineDetail as rr,isRetainedBucketsDetail as tr,getApplicationStepName as or,getApplicationStepId as Er,toPascalCase as ar,isOpenNextPattern as ir,OPENNEXT_PATTERNS as sr,deriveResourcesFromManifestStacks as Sr,STACK_NOT_FOUND_PATTERN as nr,STACK_FAILED_STATE_PATTERN as cr,CDK_NO_STACKS_MATCH as Ar,INFRASTRUCTURE_FILENAME as Tr,ApplicationError as _r,wrapApplicationError as lr,FjallStateFileSchema as pr,readStateFile as Or,writeStateFile as Pr,createEmptyState as Rr,deleteStateFile as ur,updateTemplateHash as mr,getStateFilePath as Cr,stubCallerIdentity as Nr}from"./types/index.js";import{CloudFormationEventMonitor as Dr}from"./aws/index.js";import{CdkService as gr,CdkArgumentBuilder as fr,CdkProcessManager as Ir,CdkEventMonitor as xr,startStackMonitoring as Ur,DEFAULT_DEPLOY_TIMEOUT_MS as yr,isCdkError as Mr,formatInfrastructureError as vr,getStructuralHint as kr,getSourceContext as Yr,hasCdkDifferences as Vr,parseDiffOutput as hr,CloudFormationService as Fr,CloudFormationError as Br,EcsService as br,EcsError as Gr,EcsServiceResolver as Kr,TemplateHashService as Xr,TemplateHashError as Hr,CdkContextBuilder as wr,emitProgress as jr,PROGRESS_MESSAGES as Qr,parseBuildPhase as qr,buildStepContextBuildConfig as Jr,convertCloudFormationOutputsToRecord as Wr,ApplicationStackService as zr}from"./services/index.js";import{CdkError as $r}from"./types/errors/index.js";import{BaseServiceError as rt,ValidationError as tt,AuthError as ot,AwsError as Et,DeploymentError as at,NetworkError as it,FileSystemError as st,ConfigError as St,toServiceError as nt}from"./types/errors/index.js";import{filterDangerousEnvVars as At,maskSensitiveOutput as Tt,parseShellArgs as _t,sleep as lt}from"@fjall/util";import{hasDockerfile as Ot}from"./util/dockerfileDetection.js";import{createSequencedCallbacks as Rt}from"./util/sequencedCallbacks.js";import{fileExists as mt}from"@fjall/util/fsHelpers";import{success as Nt,failure as dt,isSuccess as Dt,isFailure as Lt}from"@fjall/generator";import{deploy as ft}from"./orchestration/index.js";import{destroy as xt}from"./orchestration/index.js";import{partitionAccounts as yt}from"./orchestration/index.js";import{buildRegionList as vt,buildAccountRegionPairs as kt,cascadeHomeRegion as Yt,cascadeOperationKey as Vt}from"./orchestration/index.js";import{projectScalarSummary as Ft,projectAccountRows as Bt}from"./orchestration/index.js";import{reconcileProviderAccounts as Gt,mergeReconciledProviderAccounts as Kt}from"./orchestration/index.js";import{decideNextTransition as Ht,reconcileTrailMigration as wt,decommissionMemberTrailStorage as jt,ORG_TRAIL_BUCKET_OUTPUT_KEY as Qt,TRAIL_BUCKET_OUTPUT_KEY as qt,TRAIL_KEY_ARN_OUTPUT_KEY as Jt}from"./orchestration/index.js";import{unlockBucket as zt,unlockQueue as Zt}from"./orchestration/index.js";import{triageBucketPolicy as eo,isEnforceSslStatement as ro,toResourcePolicyStatements as to,restoreBucketPolicy as oo,synthesiseEnforceSslDocument as Eo,ensureEnforceSsl as ao,restoreAndReconcileQuarantinedBucket as io}from"./orchestration/index.js";import{verifyOrgTrailDelivery as So}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as co,isRootTaskPolicyArn as Ao,ROOT_TASK_POLICY_ARNS as To,MAX_ROOT_SESSION_SECONDS as _o}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as po,flattenAccountsToEnvironments as Oo,extractAllAccountNames as Po,accountsConfigToOUTree as Ro,isStringArray as uo,isAccountsConfig as mo,isOuOnlyAccountBucket as Co,OU_ONLY_ACCOUNT_BUCKETS as No}from"./orchestration/index.js";import{runOpenNextBuild as Lo}from"./orchestration/index.js";import{runOrganisationSetup as fo,ORG_SETUP_PHASES as Io}from"./orchestration/index.js";import{resolveBuildSecrets as Uo,resolveSecretRefValue as yo,resolveBuildSecretSessionProvider as Mo,sourcedRefsFromBuildArgs as vo,resolveBuildArgs as ko,buildBuildSecretSessionPolicy as Yo,partitionForRegion as Vo,validateBuildGroup as ho}from"./orchestration/index.js";import{FrameworkRegistry as Bo}from"./orchestration/index.js";import{openNextBuilder as Go,dockerBuilder as Ko}from"./orchestration/index.js";import{StepRegistry as Ho,getDestroyStepId as wo}from"./steps/index.js";import{buildDeployPlan as Qo,computeDeployPlan as qo,computeAssemblyDigest as Jo,digestHead as Wo,classifyImpact as zo,derivePropertyChanges as Zo,isDataLoss as $o,isStatefulResourceType as eE,renderPlanSummary as rE,renderPlanLines as tE,toWirePlanChanges as oE,signApprovalToken as EE,verifyApprovalToken as aE,DEFAULT_APPROVAL_TTL_MS as iE,APPROVAL_TOKEN_PATTERN as sE,runApprovalGate as SE}from"./orchestration/index.js";export{X as ALL_PROGRESS_KINDS,Fe as APPLICATION_DEPLOY_ORDER,Be as APPLICATION_DESTROY_ORDER,Ve as APPLICATION_STACKS,K as APPROVAL_DECISIONS,G as APPROVAL_KINDS,sE as APPROVAL_TOKEN_PATTERN,_r as ApplicationError,zr as ApplicationStackService,ot as AuthError,Et as AwsError,h as BUILDERS,rt as BaseServiceError,v as CASCADE_ACCOUNT_PHASES,n as CASCADE_ACCOUNT_STATUSES,F as CASCADE_OUTCOME_RESULTS,S as CASCADE_PHASES,Ar as CDK_NO_STACKS_MATCH,fr as CdkArgumentBuilder,wr as CdkContextBuilder,$r as CdkError,xr as CdkEventMonitor,Ir as CdkProcessManager,gr as CdkService,O as ChangeCountsSchema,Br as CloudFormationError,Dr as CloudFormationEventMonitor,Fr as CloudFormationService,St as ConfigError,iE as DEFAULT_APPROVAL_TTL_MS,yr as DEFAULT_DEPLOY_TIMEOUT_MS,i as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,E as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,a as DEPLOYMENT_EVENT_STATUS_REASON_MAX,s as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,o as DEPLOYMENT_EVENT_TYPES,I as DEPLOY_EVENT_ARN_MAX,P as DEPLOY_EVENT_CONTRACT,R as DEPLOY_EVENT_CONTRACT_MAJOR,u as DEPLOY_EVENT_CONTRACT_MINOR,L as DEPLOY_EVENT_ERROR_MESSAGE_MAX,C as DEPLOY_EVENT_ID_MAX,d as DEPLOY_EVENT_MESSAGE_MAX,N as DEPLOY_EVENT_NAME_MAX,f as DEPLOY_EVENT_OUTPUT_MAX,D as DEPLOY_EVENT_STATUS_REASON_MAX,g as DEPLOY_EVENT_TRAIL_DETAIL_MAX,x as DEPLOY_EVENT_URL_MAX,k as DEPLOY_RESULTS,Y as DETECTION_PHASES,A as DeployEventSchema,_ as DeployResourceSchema,at as DeploymentError,t as DeploymentEventSchema,Gr as EcsError,br as EcsService,Kr as EcsServiceResolver,st as FileSystemError,pr as FjallStateFileSchema,Bo as FrameworkRegistry,Tr as INFRASTRUCTURE_FILENAME,Me as INFRASTRUCTURE_STEP_NAMES,ve as INFRA_STEP_NAME,y as LOG_LEVELS,_o as MAX_ROOT_SESSION_SECONDS,it as NetworkError,be as OPENNEXT_DEPLOY_ORDER,Ge as OPENNEXT_DESTROY_ORDER,He as OPENNEXT_PARALLEL_GROUPS,sr as OPENNEXT_PATTERNS,he as ORGANISATION_TYPES,Io as ORG_SETUP_PHASES,Qt as ORG_TRAIL_BUCKET_OUTPUT_KEY,No as OU_ONLY_ACCOUNT_BUCKETS,Ke as PARALLEL_DEPLOY_GROUPS,Xe as PARALLEL_DESTROY_GROUPS,we as PARALLEL_OPERATION_TYPES,V as PHASE_STATUSES,B as PLAN_ACTIONS,Qr as PROGRESS_MESSAGES,l as PlanChangeSchema,p as PlanPropertyChangeSchema,Ye as ProgressReporter,b as REPLACEMENT_MODES,fe as ROOT_ACCESS_FEATURES,To as ROOT_TASK_POLICY_ARNS,Ie as RootAccessEnablementError,Le as SECURITY_SERVICE_PRINCIPALS,ne as SERVICE_PRINCIPALS,M as STACK_CLEANUP_PHASES,cr as STACK_FAILED_STATE_PATTERN,nr as STACK_NOT_FOUND_PATTERN,U as STEP_COMPLETE_STATUSES,Ue as STEP_IDS,ye as STEP_NAMES,m as SUPPORTED_CONTRACT_MARKERS,q as SimpleAwsProvider,T as StepProgressSchema,Ho as StepRegistry,qt as TRAIL_BUCKET_OUTPUT_KEY,Jt as TRAIL_KEY_ARN_OUTPUT_KEY,Hr as TemplateHashError,Xr as TemplateHashService,tt as ValidationError,Ro as accountsConfigToOUTree,me as activateCostAllocationTags,Ae as activateTrustedAccess,co as assumeRootForTask,kt as buildAccountRegionPairs,ue as buildAccountToOUMap,Yo as buildBuildSecretSessionPolicy,Qo as buildDeployPlan,vt as buildRegionList,Jr as buildStepContextBuildConfig,$ as buildTargetSetUnreadyAdvisory,Z as buildTargetUnreadyAdvisory,Yt as cascadeHomeRegion,Vt as cascadeOperationKey,Ce as checkIdentityCentreStatus,te as checkRegionEnabled,W as checkTargetReadiness,zo as classifyImpact,Jo as computeAssemblyDigest,qo as computeDeployPlan,Wr as convertCloudFormationOutputsToRecord,Oe as createAccount,H as createDeployEmitter,Rr as createEmptyState,Rt as createSequencedCallbacks,Ht as decideNextTransition,jt as decommissionMemberTrailStorage,ur as deleteStateFile,ft as deploy,Zo as derivePropertyChanges,Sr as deriveResourcesFromManifestStacks,ie as describeOrganisation,z as describeTargetReadinessReason,xt as destroy,Wo as digestHead,Ko as dockerBuilder,jr as emitProgress,ge as enableCentralisedRootAccess,Te as enableIpamDelegatedAdmin,se as enablePolicyTypes,ce as enableRamSharing,Se as enableServiceAccess,ao as ensureEnforceSsl,ae as ensureOrganisationExists,Pe as ensureOrganisationalUnitsExist,Po as extractAllAccountNames,Ne as extractErrorName,dt as failure,mt as fileExists,At as filterDangerousEnvVars,pe as findAccount,Oo as flattenAccountsToEnvironments,vr as formatInfrastructureError,We as getApplicationDeployOrder,ze as getApplicationDestroyOrder,Ze as getApplicationStackName,Er as getApplicationStepId,or as getApplicationStepName,wo as getDestroyStepId,$e as getOrganisationStackName,qe as getParallelDeployGroups,Je as getParallelDestroyGroups,Yr as getSourceContext,Cr as getStateFilePath,kr as getStructuralHint,Vr as hasCdkDifferences,Ot as hasDockerfile,mo as isAccountsConfig,je as isApplicationOperation,er as isApplicationStack,Mr as isCdkError,$o as isDataLoss,ro as isEnforceSslStatement,Lt as isFailure,de as isOULeaf,ir as isOpenNextPattern,Qe as isOrganisationOperation,Co as isOuOnlyAccountBucket,rr as isQuarantineDetail,tr as isRetainedBucketsDetail,Ao as isRootTaskPolicyArn,eE as isStatefulResourceType,uo as isStringArray,Dt as isSuccess,le as listAccounts,Tt as maskSensitiveOutput,Kt as mergeReconciledProviderAccounts,Go as openNextBuilder,po as parseAccountsConfiguration,qr as parseBuildPhase,j as parseDeployContractVersion,w as parseDeployEvent,hr as parseDiffOutput,_t as parseShellArgs,yt as partitionAccounts,Vo as partitionForRegion,Re as placeAccountsInOUs,ee as probeAccountStackExists,Bt as projectAccountRows,Ft as projectScalarSummary,Or as readStateFile,Gt as reconcileProviderAccounts,wt as reconcileTrailMigration,oe as regionDisabledMessage,De as registerSecurityDelegates,tE as renderPlanLines,rE as renderPlanSummary,ko as resolveBuildArgs,Mo as resolveBuildSecretSessionProvider,Uo as resolveBuildSecrets,yo as resolveSecretRefValue,io as restoreAndReconcileQuarantinedBucket,oo as restoreBucketPolicy,SE as runApprovalGate,Lo as runOpenNextBuild,fo as runOrganisationSetup,EE as signApprovalToken,lt as sleep,vo as sourcedRefsFromBuildArgs,Ur as startStackMonitoring,Nr as stubCallerIdentity,Nt as success,Eo as synthesiseEnforceSslDocument,ar as toPascalCase,to as toResourcePolicyStatements,nt as toServiceError,oE as toWirePlanChanges,eo as triageBucketPolicy,zt as unlockBucket,Zt as unlockQueue,_e as updateBackupGlobalSettings,mr as updateTemplateHash,ho as validateBuildGroup,aE as verifyApprovalToken,So as verifyOrgTrailDelivery,lr as wrapApplicationError,Pr as writeStateFile};
1
+ import{DeploymentEventSchema as t,DEPLOYMENT_EVENT_TYPES as o,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as a,DEPLOYMENT_EVENT_STATUS_REASON_MAX as E,DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX as i,DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX as s,CASCADE_PHASES as S,CASCADE_ACCOUNT_STATUSES as n}from"./types/index.js";import{DeployEventSchema as A,StepProgressSchema as T,DeployResourceSchema as _,PlanChangeSchema as l,PlanPropertyChangeSchema as p,ChangeCountsSchema as O,DEPLOY_EVENT_CONTRACT as P,DEPLOY_EVENT_CONTRACT_MAJOR as R,DEPLOY_EVENT_CONTRACT_MINOR as u,SUPPORTED_CONTRACT_MARKERS as m,DEPLOY_EVENT_ID_MAX as d,DEPLOY_EVENT_NAME_MAX as C,DEPLOY_EVENT_MESSAGE_MAX as N,DEPLOY_EVENT_STATUS_REASON_MAX as D,DEPLOY_EVENT_ERROR_MESSAGE_MAX as L,DEPLOY_EVENT_TRAIL_DETAIL_MAX as f,DEPLOY_EVENT_OUTPUT_MAX as g,DEPLOY_EVENT_ARN_MAX as I,DEPLOY_EVENT_URL_MAX as x,STEP_COMPLETE_STATUSES as y,LOG_LEVELS as U,STACK_CLEANUP_PHASES as M,CASCADE_ACCOUNT_PHASES as v,DEPLOY_RESULTS as k,DETECTION_PHASES as Y,PHASE_STATUSES as h,BUILDERS as b,CASCADE_OUTCOME_RESULTS as V,PLAN_ACTIONS as F,REPLACEMENT_MODES as B,APPROVAL_KINDS as G,APPROVAL_DECISIONS as K,ALL_PROGRESS_KINDS as X,createDeployEmitter as H,parseDeployEvent as w,parseDeployContractVersion as j}from"./types/index.js";import{SimpleAwsProvider as q}from"./aws/index.js";import{checkTargetReadiness as W,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 Ee,describeOrganisation as ie,enablePolicyTypes as se,enableServiceAccess as Se,SERVICE_PRINCIPALS as ne,enableRamSharing as ce,activateTrustedAccess as Ae,enableIpamDelegatedAdmin as Te,updateBackupGlobalSettings as _e,listAccounts as le,findAccount as pe,createAccount as Oe,ensureOrganisationalUnitsExist as Pe,placeAccountsInOUs as Re,buildAccountToOUMap as ue,activateCostAllocationTags as me,checkIdentityCentreStatus as de,snapshotIdentityCentre as Ce,composeSdkAbortSignal as Ne,extractErrorName as De,isAborted as Le,DEFAULT_MAX_PAGES as fe,IDENTITY_STORE_PAGE_SIZE as ge,drainPages as Ie,isOULeaf as xe,registerSecurityDelegates as ye,SECURITY_SERVICE_PRINCIPALS as Ue,enableCentralisedRootAccess as Me,ROOT_ACCESS_FEATURES as ve,RootAccessEnablementError as ke}from"./aws/index.js";import{STEP_IDS as he,STEP_NAMES as be,INFRASTRUCTURE_STEP_NAMES as Ve,INFRA_STEP_NAME as Fe}from"./types/index.js";import{ProgressReporter as Ge,APPLICATION_STACKS as Ke,ORGANISATION_TYPES as Xe,APPLICATION_DEPLOY_ORDER as He,APPLICATION_DESTROY_ORDER as we,OPENNEXT_DEPLOY_ORDER as je,OPENNEXT_DESTROY_ORDER as Qe,PARALLEL_DEPLOY_GROUPS as qe,PARALLEL_DESTROY_GROUPS as Je,OPENNEXT_PARALLEL_GROUPS as We,PARALLEL_OPERATION_TYPES as Ze,isApplicationOperation as ze,isOrganisationOperation as $e,getParallelDeployGroups as er,getParallelDestroyGroups as rr,getApplicationDeployOrder as tr,getApplicationDestroyOrder as or,getApplicationStackName as ar,getOrganisationStackName as Er,isApplicationStack as ir,isQuarantineDetail as sr,isRetainedBucketsDetail as Sr,getApplicationStepName as nr,getApplicationStepId as cr,toPascalCase as Ar,isOpenNextPattern as Tr,OPENNEXT_PATTERNS as _r,deriveResourcesFromManifestStacks as lr,STACK_NOT_FOUND_PATTERN as pr,STACK_FAILED_STATE_PATTERN as Or,CDK_NO_STACKS_MATCH as Pr,INFRASTRUCTURE_FILENAME as Rr,ApplicationError as ur,wrapApplicationError as mr,FjallStateFileSchema as dr,readStateFile as Cr,writeStateFile as Nr,createEmptyState as Dr,deleteStateFile as Lr,updateTemplateHash as fr,getStateFilePath as gr,stubCallerIdentity as Ir}from"./types/index.js";import{CloudFormationEventMonitor as yr}from"./aws/index.js";import{CdkService as Mr,CdkArgumentBuilder as vr,CdkProcessManager as kr,CdkEventMonitor as Yr,startStackMonitoring as hr,DEFAULT_DEPLOY_TIMEOUT_MS as br,isCdkError as Vr,formatInfrastructureError as Fr,getStructuralHint as Br,getSourceContext as Gr,hasCdkDifferences as Kr,parseDiffOutput as Xr,CloudFormationService as Hr,CloudFormationError as wr,EcsService as jr,EcsError as Qr,EcsServiceResolver as qr,TemplateHashService as Jr,TemplateHashError as Wr,CdkContextBuilder as Zr,emitProgress as zr,PROGRESS_MESSAGES as $r,parseBuildPhase as et,buildStepContextBuildConfig as rt,convertCloudFormationOutputsToRecord as tt,ApplicationStackService as ot}from"./services/index.js";import{CdkError as Et}from"./types/errors/index.js";import{BaseServiceError as st,ValidationError as St,AuthError as nt,AwsError as ct,DeploymentError as At,NetworkError as Tt,FileSystemError as _t,ConfigError as lt,toServiceError as pt}from"./types/errors/index.js";import{filterDangerousEnvVars as Pt,maskSensitiveOutput as Rt,parseShellArgs as ut,sleep as mt}from"@fjall/util";import{artefactOutputKey as Ct,DeployModeSchema as Nt,ServiceArtefactSchema as Dt,ServiceArtefactsSchema as Lt}from"@fjall/util";import{hasDockerfile as gt}from"./util/dockerfileDetection.js";import{sleepAbortable as xt}from"./util/sleepAbortable.js";import{createSequencedCallbacks as Ut}from"./util/sequencedCallbacks.js";import{fileExists as vt}from"@fjall/util/fsHelpers";import{success as Yt,failure as ht,isSuccess as bt,isFailure as Vt}from"@fjall/generator";import{deploy as Bt}from"./orchestration/index.js";import{destroy as Kt}from"./orchestration/index.js";import{restart as Ht,probeSecretsDrift as wt,computeSecretsDrift as jt,deriveStaleParameters as Qt,extractConsumedSsmParameters as qt}from"./orchestration/index.js";import{partitionAccounts as Wt}from"./orchestration/index.js";import{buildRegionList as zt,buildAccountRegionPairs as $t,cascadeHomeRegion as eo,cascadeOperationKey as ro}from"./orchestration/index.js";import{projectScalarSummary as oo,projectAccountRows as ao}from"./orchestration/index.js";import{reconcileProviderAccounts as io,mergeReconciledProviderAccounts as so}from"./orchestration/index.js";import{decideNextTransition as no,reconcileTrailMigration as co,decommissionMemberTrailStorage as Ao,ORG_TRAIL_BUCKET_OUTPUT_KEY as To,TRAIL_BUCKET_OUTPUT_KEY as _o,TRAIL_KEY_ARN_OUTPUT_KEY as lo}from"./orchestration/index.js";import{unlockBucket as Oo,unlockQueue as Po}from"./orchestration/index.js";import{triageBucketPolicy as uo,isEnforceSslStatement as mo,toResourcePolicyStatements as Co,restoreBucketPolicy as No,synthesiseEnforceSslDocument as Do,ensureEnforceSsl as Lo,restoreAndReconcileQuarantinedBucket as fo}from"./orchestration/index.js";import{verifyOrgTrailDelivery as Io}from"./aws/cloudtrail/orgTrailDelivery.js";import{assumeRootForTask as yo,isRootTaskPolicyArn as Uo,ROOT_TASK_POLICY_ARNS as Mo,MAX_ROOT_SESSION_SECONDS as vo}from"./aws/sts/assumeRoot.js";import{parseAccountsConfiguration as Yo,flattenAccountsToEnvironments as ho,extractAllAccountNames as bo,accountsConfigToOUTree as Vo,isStringArray as Fo,isAccountsConfig as Bo,isOuOnlyAccountBucket as Go,OU_ONLY_ACCOUNT_BUCKETS as Ko}from"./orchestration/index.js";import{runOpenNextBuild as Ho}from"./orchestration/index.js";import{runOrganisationSetup as jo,ORG_SETUP_PHASES as Qo}from"./orchestration/index.js";import{resolveBuildSecrets as Jo,resolveSecretRefValue as Wo,resolveBuildSecretSessionProvider as Zo,sourcedRefsFromBuildArgs as zo,resolveBuildArgs as $o,buildBuildSecretSessionPolicy as ea,buildDeploySessionPolicy as ra,partitionForRegion as ta,validateBuildGroup as oa}from"./orchestration/index.js";import{FrameworkRegistry as Ea}from"./orchestration/index.js";import{openNextBuilder as sa,dockerBuilder as Sa}from"./orchestration/index.js";import{StepRegistry as ca,getDestroyStepId as Aa}from"./steps/index.js";import{buildDeployPlan as _a,computeDeployPlan as la,computeAssemblyDigest as pa,digestHead as Oa,classifyImpact as Pa,derivePropertyChanges as Ra,isDataLoss as ua,isStatefulResourceType as ma,renderPlanSummary as da,renderPlanLines as Ca,toWirePlanChanges as Na,signApprovalToken as Da,verifyApprovalToken as La,DEFAULT_APPROVAL_TTL_MS as fa,APPROVAL_TOKEN_PATTERN as ga,runApprovalGate as Ia}from"./orchestration/index.js";export{X as ALL_PROGRESS_KINDS,He as APPLICATION_DEPLOY_ORDER,we as APPLICATION_DESTROY_ORDER,Ke as APPLICATION_STACKS,K as APPROVAL_DECISIONS,G as APPROVAL_KINDS,ga as APPROVAL_TOKEN_PATTERN,ur as ApplicationError,ot as ApplicationStackService,nt as AuthError,ct as AwsError,b as BUILDERS,st as BaseServiceError,v as CASCADE_ACCOUNT_PHASES,n as CASCADE_ACCOUNT_STATUSES,V as CASCADE_OUTCOME_RESULTS,S as CASCADE_PHASES,Pr as CDK_NO_STACKS_MATCH,vr as CdkArgumentBuilder,Zr as CdkContextBuilder,Et as CdkError,Yr as CdkEventMonitor,kr as CdkProcessManager,Mr as CdkService,O as ChangeCountsSchema,wr as CloudFormationError,yr as CloudFormationEventMonitor,Hr as CloudFormationService,lt as ConfigError,fa as DEFAULT_APPROVAL_TTL_MS,br as DEFAULT_DEPLOY_TIMEOUT_MS,fe as DEFAULT_MAX_PAGES,i as DEPLOYMENT_EVENT_ERROR_MESSAGE_MAX,a as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,E as DEPLOYMENT_EVENT_STATUS_REASON_MAX,s as DEPLOYMENT_EVENT_TRAIL_DETAIL_MAX,o as DEPLOYMENT_EVENT_TYPES,I as DEPLOY_EVENT_ARN_MAX,P as DEPLOY_EVENT_CONTRACT,R as DEPLOY_EVENT_CONTRACT_MAJOR,u as DEPLOY_EVENT_CONTRACT_MINOR,L as DEPLOY_EVENT_ERROR_MESSAGE_MAX,d as DEPLOY_EVENT_ID_MAX,N as DEPLOY_EVENT_MESSAGE_MAX,C as DEPLOY_EVENT_NAME_MAX,g as DEPLOY_EVENT_OUTPUT_MAX,D as DEPLOY_EVENT_STATUS_REASON_MAX,f as DEPLOY_EVENT_TRAIL_DETAIL_MAX,x as DEPLOY_EVENT_URL_MAX,k as DEPLOY_RESULTS,Y as DETECTION_PHASES,A as DeployEventSchema,Nt as DeployModeSchema,_ as DeployResourceSchema,At as DeploymentError,t as DeploymentEventSchema,Qr as EcsError,jr as EcsService,qr as EcsServiceResolver,_t as FileSystemError,dr as FjallStateFileSchema,Ea as FrameworkRegistry,ge as IDENTITY_STORE_PAGE_SIZE,Rr as INFRASTRUCTURE_FILENAME,Ve as INFRASTRUCTURE_STEP_NAMES,Fe as INFRA_STEP_NAME,U as LOG_LEVELS,vo as MAX_ROOT_SESSION_SECONDS,Tt as NetworkError,je as OPENNEXT_DEPLOY_ORDER,Qe as OPENNEXT_DESTROY_ORDER,We as OPENNEXT_PARALLEL_GROUPS,_r as OPENNEXT_PATTERNS,Xe as ORGANISATION_TYPES,Qo as ORG_SETUP_PHASES,To as ORG_TRAIL_BUCKET_OUTPUT_KEY,Ko as OU_ONLY_ACCOUNT_BUCKETS,qe as PARALLEL_DEPLOY_GROUPS,Je as PARALLEL_DESTROY_GROUPS,Ze as PARALLEL_OPERATION_TYPES,h as PHASE_STATUSES,F as PLAN_ACTIONS,$r as PROGRESS_MESSAGES,l as PlanChangeSchema,p as PlanPropertyChangeSchema,Ge as ProgressReporter,B as REPLACEMENT_MODES,ve as ROOT_ACCESS_FEATURES,Mo as ROOT_TASK_POLICY_ARNS,ke as RootAccessEnablementError,Ue as SECURITY_SERVICE_PRINCIPALS,ne as SERVICE_PRINCIPALS,M as STACK_CLEANUP_PHASES,Or as STACK_FAILED_STATE_PATTERN,pr as STACK_NOT_FOUND_PATTERN,y as STEP_COMPLETE_STATUSES,he as STEP_IDS,be as STEP_NAMES,m as SUPPORTED_CONTRACT_MARKERS,Dt as ServiceArtefactSchema,Lt as ServiceArtefactsSchema,q as SimpleAwsProvider,T as StepProgressSchema,ca as StepRegistry,_o as TRAIL_BUCKET_OUTPUT_KEY,lo as TRAIL_KEY_ARN_OUTPUT_KEY,Wr as TemplateHashError,Jr as TemplateHashService,St as ValidationError,Vo as accountsConfigToOUTree,me as activateCostAllocationTags,Ae as activateTrustedAccess,Ct as artefactOutputKey,yo as assumeRootForTask,$t as buildAccountRegionPairs,ue as buildAccountToOUMap,ea as buildBuildSecretSessionPolicy,_a as buildDeployPlan,ra as buildDeploySessionPolicy,zt as buildRegionList,rt as buildStepContextBuildConfig,$ as buildTargetSetUnreadyAdvisory,z as buildTargetUnreadyAdvisory,eo as cascadeHomeRegion,ro as cascadeOperationKey,de as checkIdentityCentreStatus,te as checkRegionEnabled,W as checkTargetReadiness,Pa as classifyImpact,Ne as composeSdkAbortSignal,pa as computeAssemblyDigest,la as computeDeployPlan,jt as computeSecretsDrift,tt as convertCloudFormationOutputsToRecord,Oe as createAccount,H as createDeployEmitter,Dr as createEmptyState,Ut as createSequencedCallbacks,no as decideNextTransition,Ao as decommissionMemberTrailStorage,Lr as deleteStateFile,Bt as deploy,Ra as derivePropertyChanges,lr as deriveResourcesFromManifestStacks,Qt as deriveStaleParameters,ie as describeOrganisation,Z as describeTargetReadinessReason,Kt as destroy,Oa as digestHead,Sa as dockerBuilder,Ie as drainPages,zr as emitProgress,Me as enableCentralisedRootAccess,Te as enableIpamDelegatedAdmin,se as enablePolicyTypes,ce as enableRamSharing,Se as enableServiceAccess,Lo as ensureEnforceSsl,Ee as ensureOrganisationExists,Pe as ensureOrganisationalUnitsExist,bo as extractAllAccountNames,qt as extractConsumedSsmParameters,De as extractErrorName,ht as failure,vt as fileExists,Pt as filterDangerousEnvVars,pe as findAccount,ho as flattenAccountsToEnvironments,Fr as formatInfrastructureError,tr as getApplicationDeployOrder,or as getApplicationDestroyOrder,ar as getApplicationStackName,cr as getApplicationStepId,nr as getApplicationStepName,Aa as getDestroyStepId,Er as getOrganisationStackName,er as getParallelDeployGroups,rr as getParallelDestroyGroups,Gr as getSourceContext,gr as getStateFilePath,Br as getStructuralHint,Kr as hasCdkDifferences,gt as hasDockerfile,Le as isAborted,Bo as isAccountsConfig,ze as isApplicationOperation,ir as isApplicationStack,Vr as isCdkError,ua as isDataLoss,mo as isEnforceSslStatement,Vt as isFailure,xe as isOULeaf,Tr as isOpenNextPattern,$e as isOrganisationOperation,Go as isOuOnlyAccountBucket,sr as isQuarantineDetail,Sr as isRetainedBucketsDetail,Uo as isRootTaskPolicyArn,ma as isStatefulResourceType,Fo as isStringArray,bt as isSuccess,le as listAccounts,Rt as maskSensitiveOutput,so as mergeReconciledProviderAccounts,sa as openNextBuilder,Yo as parseAccountsConfiguration,et as parseBuildPhase,j as parseDeployContractVersion,w as parseDeployEvent,Xr as parseDiffOutput,ut as parseShellArgs,Wt as partitionAccounts,ta as partitionForRegion,Re as placeAccountsInOUs,ee as probeAccountStackExists,wt as probeSecretsDrift,ao as projectAccountRows,oo as projectScalarSummary,Cr as readStateFile,io as reconcileProviderAccounts,co as reconcileTrailMigration,oe as regionDisabledMessage,ye as registerSecurityDelegates,Ca as renderPlanLines,da as renderPlanSummary,$o as resolveBuildArgs,Zo as resolveBuildSecretSessionProvider,Jo as resolveBuildSecrets,Wo as resolveSecretRefValue,Ht as restart,fo as restoreAndReconcileQuarantinedBucket,No as restoreBucketPolicy,Ia as runApprovalGate,Ho as runOpenNextBuild,jo as runOrganisationSetup,Da as signApprovalToken,mt as sleep,xt as sleepAbortable,Ce as snapshotIdentityCentre,zo as sourcedRefsFromBuildArgs,hr as startStackMonitoring,Ir as stubCallerIdentity,Yt as success,Do as synthesiseEnforceSslDocument,Ar as toPascalCase,Co as toResourcePolicyStatements,pt as toServiceError,Na as toWirePlanChanges,uo as triageBucketPolicy,Oo as unlockBucket,Po as unlockQueue,_e as updateBackupGlobalSettings,fr as updateTemplateHash,oa as validateBuildGroup,La as verifyApprovalToken,Io as verifyOrgTrailDelivery,mr as wrapApplicationError,Nr as writeStateFile};
@@ -1 +1 @@
1
- import{join as F}from"path";import{CloudFormationClient as Y}from"@aws-sdk/client-cloudformation";import{EC2Client as J}from"@aws-sdk/client-ec2";import{success as E,failure as m}from"@fjall/generator";import{logger as O}from"@fjall/util/logger";import{imageTagParameterName as Q,maskSensitiveOutput as k}from"@fjall/util";import{parseDockerServicesFromManifest as V}from"@fjall/util/manifest";import{stubCallerIdentity as X}from"../../types/deployment/index.js";import{getApplicationDeployOrder as Z,getApplicationStackName as ee,getApplicationStepName as K,getApplicationStepId as W,APPLICATION_STACKS as T}from"../../types/operations.js";import{CdkContextBuilder as te}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as oe,bootstrapOrFail as ne}from"../contextHelpers.js";import{runDetectionPipeline as re}from"./detectionPipeline.js";import{STEP_IDS as N,STEP_NAMES as ae}from"../../types/stepDefinitions.js";import{StepRegistry as ie}from"../../steps/stepRegistry.js";import{checkTargetReadiness as se}from"../../aws/targetReadiness.js";import{cascadeHomeRegion as ce}from"../organisation/cascadeHelpers.js";import{withStepLifecycle as le}from"../stepLifecycle.js";import{DOCKER_BUILD_STEP_NAME as $,runDockerBuild as de}from"./dockerBuildHelper.js";import{getParallelPhase2Stacks as pe,deployParallelPhase as ue,deployStackSequential as fe,runDockerPreCompute as ge,createBuildCallbacks as me}from"./applicationDeployHelpers.js";import{deployCodeOnly as ke}from"./codeOnlyDeploy.js";import{runApprovalGate as ye}from"./approvalGate.js";const R="applicationDeploy";function he(a){const i=Object.entries(a);if(i.length===0)return;const r={};for(const[t,s]of i){const y=Q(t);r[y]=s}return r}async function je(a,i,r){const{callbacks:t,options:s}=a,y=Date.now(),C=te.buildDeploymentContext({deployType:"application",target:r.appName,path:r.path,region:i.awsProvider.getRegion(),callerIdentity:X(i.awsProvider.getAccountId()),...oe({orgConfig:a.orgConfig,identity:a.identity,skipOidc:a.options?.skipOidc})},{verbose:s?.verbose,infraOnly:s?.infraOnly},a.orgConfig),p=i.frameworkRegistry.resolve({appPath:r.path});let D;const h=!!s?.imageTag;if(p&&!h){D=p.builder.plan({appPath:r.path},p.detection);const e=me(t),o=await p.builder.build(r.path,D,e,{skipBuild:s?.skipBuild,infraOnly:s?.infraOnly});if(!o.success){const n=new Error(k(o.error.message));return t.onError?.(n),m(n)}}if(s?.deployOnly||h){t.onLog?.(h?`Rollback mode \u2014 rolling to image tag ${s?.imageTag}`:"Deploy-only mode \u2014 skipping infrastructure pipeline","info");const e=F(r.path,"cdk.out"),o=V(e),n=o.length>0,d=p?.detection.hasDockerfile===!0,l=n||d;O.debug(R,"Deploy-only branch entered",{isRollback:h,imageTag:s?.imageTag,appName:r.appName,appPath:r.path,cdkOutPath:e,dockerProviderAvailable:a.dockerProvider!==void 0,builderName:p?.builder.name,hasDockerfileFromManifest:n,hasDockerfileFromDisk:d,hasDockerfile:l,manifestDockerServiceCount:o.length,manifestDockerPaths:o.map(g=>g.docker.path)}),!n&&!d&&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");let u={};if(!h&&a.dockerProvider!==void 0&&l){O.debug(R,"Running Docker build before code-only deploy",{source:n?"manifest":"disk"});const g=await de(a,i,r,t);if(!g.success)return m(g.error);u=g.data}else O.debug(R,"Skipping Docker build",{reason:h?"rollback":a.dockerProvider===void 0?"no dockerProvider":"no Dockerfile detected"});return ke(a,i,r,u)}t.onLog?.("Analysing infrastructure\u2026","info");const A=await re(r,i,C,t);if(!A.success){const e=new Error(k(A.error.message));return t.onError?.(e),m(e)}const c=A.data;try{await t.onDetectionComplete?.({...c,builderName:p?.builder.name??"unknown"})}catch(e){const o=e instanceof Error?e.message:String(e),n=new Error(k(o));return t.onError?.(n),m(n)}const q={deploymentType:"application",operation:"deploy",deployOnly:!1,infraOnly:s?.infraOnly??!1,hasDockerfile:c.hasDockerfile,pattern:c.pattern,resources:c.resources,...p&&{builderName:p.builder.name}},I=ie.getSteps(q),M=I.findIndex(e=>e.id===N.TARGET_READINESS),L=await le(t,{stepId:N.TARGET_READINESS,stepName:ae.TARGET_READINESS,...M>=0&&{stepIndex:M,totalSteps:I.length}},async()=>{if(s?.skipReadinessCheck)return t.onLog?.("Skipping target readiness check (--skip-readiness-check)","warn"),{kind:"skipped",data:void 0};const e=i.awsProvider.getAccountId(),o=a.orgConfig?.providerAccounts.find(u=>u.id===e)?.name,n=i.awsProvider.getCredentials(),d=ce(a.orgConfig),l=await se({cloudFormation:i.awsProvider.getClient(Y),ec2:new J({region:d,...n!==void 0&&{credentials:n}})},{id:e,...o!==void 0&&{name:o}},i.awsProvider.getRegion(),a.orgConfig,a.abortSignal);return l.success?l.data.ready?{kind:"completed",data:void 0}:{kind:"error",error:new Error(k(l.data.advisory))}:{kind:"error",error:new Error(k(l.error.message))}},a.abortSignal);if(!L.success)return L;const f=D?D.deployOrder:Z({pattern:c.pattern,resources:c.resources}),S=f.length,_=c.hasDockerfile&&a.dockerProvider!==void 0&&f.includes(T.COMPUTE)&&s?.infraOnly!==!0;if(!c.hasDifferences&&!s?.force&&!_){t.onLog?.("No infrastructure changes detected","info"),t.onLog?.(s?.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 e=c.hasDockerfile&&a.dockerProvider!==void 0&&f.includes(T.COMPUTE);for(let n=0;n<f.length;n++){const d=f[n];e&&d===T.COMPUTE&&(t.onStepStart?.(N.DOCKER_OPERATIONS,$),t.onStepComplete?.(N.DOCKER_OPERATIONS,$,"skipped"));const l=W(d,"deploy"),u=K(d,"deploy");t.onStepStart?.(l,u,n,S),t.onStepComplete?.(l,u,"skipped",n,S)}const o=await i.stackService.resolveWebsiteUrl(r.appName);return E({target:r.appName,deploymentType:"application",outputs:o?{websiteUrl:o}:void 0,noChanges:!0,durationMs:Date.now()-y})}if(a.approvalGate!==void 0||s?.approvalToken!==void 0&&s.approvalToken!==""||s?.planOnly===!0){const e=F(r.path,"cdk.out"),o=await ye({approvalGate:a.approvalGate,options:s??{},target:r.appName,cdkOutPath:e,detection:{stackChanges:c.stackChanges,currentHashes:c.currentHashes},cfnService:i.cfnService,callbacks:t});if(!o.success)return o;const n=o.data;if(n.kind==="rejected")return t.onLog?.(`Deploy rejected: ${k(n.reason)}`,"warn"),E({target:r.appName,deploymentType:"application",rejected:!0,durationMs:Date.now()-y});if(n.kind==="awaiting")return E({target:r.appName,deploymentType:"application",awaitingApproval:!0,approvalToken:n.approvalToken,assemblyDigest:n.assemblyDigest,durationMs:Date.now()-y})}const x=await ne(i,C,t);if(!x.success)return x;const w={},P=new Map;for(let e=0;e<f.length;e++){const o=f[e],n=ee(r.appName,o),d=W(o,"deploy"),l=K(o,"deploy"),u=c.stackChanges.get(n)??!0,g=o===T.COMPUTE&&_;if(!u&&!s?.force&&!g){t.onStepStart?.(d,l,e,S),t.onLog?.(`Skipping ${o} \u2014 no changes detected`,"info"),t.onStepComplete?.(d,l,"skipped",e,S);continue}const v=pe(f,e,c.stackChanges,r.appName,s?.force);if(v.length>=2){const j=await ue(v,r,i,C,t,e,S,c,w,P);if(!j.success)return m(j.error);e+=v.length-1;continue}const b=await ge(o,a,i,r,t,c.hasDockerfile);if(b!==null&&!b.success)return m(b.error);const z=b!==null&&b.success?b.data.contentHashTagsByService:{},U=he(z),G=await fe(o,i,C,t,e,S,w,U!==void 0?{parameters:U}:void 0);if(!G.success)return m(G.error);const H=c.currentHashes.get(n);H&&P.set(n,H)}if(P.size>0){const e=await i.hashService.updateStateAfterDeploy(r.path,P);if(!e.success){const o=k(e.error.message);O.debug(R,"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 B=await i.stackService.resolveWebsiteUrl(r.appName);return B&&(w.websiteUrl=B),E({target:r.appName,deploymentType:"application",outputs:Object.keys(w).length>0?w:void 0,durationMs:Date.now()-y})}export{je as deployApplication};
1
+ import{join as q}from"path";import{CloudFormationClient as X}from"@aws-sdk/client-cloudformation";import{EC2Client as Z}from"@aws-sdk/client-ec2";import{success as S,failure as l}from"@fjall/generator";import{logger as I}from"@fjall/util/logger";import{ImageTagSchema as ee,imageTagParameterName as te,maskSensitiveOutput as k}from"@fjall/util";import{parseDockerServicesFromManifest as re}from"@fjall/util/manifest";import{stubCallerIdentity as ae}from"../../types/deployment/index.js";import{getApplicationDeployOrder as oe,getApplicationStackName as ne,getApplicationStepName as W,getApplicationStepId as z,APPLICATION_STACKS as O}from"../../types/operations.js";import{CdkContextBuilder as ie}from"../../services/supporting/CdkContextBuilder.js";import{buildParamsContext as se,bootstrapOrFail as ce}from"../contextHelpers.js";import{runDetectionPipeline as le}from"./detectionPipeline.js";import{STEP_IDS as P,STEP_NAMES as de}from"../../types/stepDefinitions.js";import{StepRegistry as pe}from"../../steps/stepRegistry.js";import{checkTargetReadiness as ue}from"../../aws/targetReadiness.js";import{cascadeHomeRegion as ge}from"../organisation/cascadeHelpers.js";import{withStepLifecycle as me}from"../stepLifecycle.js";import{DOCKER_BUILD_STEP_NAME as Y,runDockerBuild as fe}from"./dockerBuildHelper.js";import{getParallelPhase2Stacks as ke,deployParallelPhase as ye,deployStackSequential as he,runDockerPreCompute as be,createBuildCallbacks as Te}from"./applicationDeployHelpers.js";import{deployCodeOnly as we}from"./codeOnlyDeploy.js";import{collectFullDeployArtefacts as Se}from"./artefactCollection.js";import{runApprovalGate as ve}from"./approvalGate.js";const N="applicationDeploy";function De(t){const s=Object.entries(t);if(s.length===0)return;const n={};for(const[r,i]of s){const h=te(r);n[h]=i}return n}function Ee(t){if(t?.mode!==void 0&&t.mode!=="rollback"){if(t.imageTag)return l(new Error(`--image-tag requires rollback mode (explicit mode '${t.mode}' was supplied alongside an image tag)`));if(t.serviceImageTags)return l(new Error(`serviceImageTags requires rollback mode (explicit mode '${t.mode}' was supplied alongside serviceImageTags)`))}if(t?.mode==="rollback"){if(t.imageTag&&t.serviceImageTags)return l(new Error("rollback mode accepts exactly one of --image-tag or serviceImageTags \u2014 they are mutually exclusive"));if(!t.imageTag&&!t.serviceImageTags)return l(new Error("rollback mode requires --image-tag <tag> or serviceImageTags naming the image(s) to roll to"))}if(t?.serviceImageTags!==void 0){if(t.serviceName)return l(new Error("serviceImageTags already names its services \u2014 --service cannot be combined with it"));const s=Object.entries(t.serviceImageTags);if(s.length===0)return l(new Error("serviceImageTags must name at least one service"));for(const[n,r]of s){const i=ee.safeParse(r);if(!i.success)return l(new Error(`serviceImageTags.${n} is not a valid image tag: ${i.error.message}`))}}return S(void 0)}async function Je(t,s,n){const{callbacks:r,options:i}=t,h=Date.now(),v=i?.mode??(i?.imageTag||i?.serviceImageTags?"rollback":i?.deployOnly?"code-only":"full");if(v==="restart"){const e=new Error('mode "restart" is not a deploy \u2014 call the restart() entry point (fjall rollout) instead');return r.onError?.(e),l(e)}const M=Ee(i);if(!M.success){const e=k(M.error.message),a=new Error(e);return r.onError?.(a),l(a)}const D=ie.buildDeploymentContext({deployType:"application",target:n.appName,path:n.path,region:s.awsProvider.getRegion(),callerIdentity:ae(s.awsProvider.getAccountId()),...se({orgConfig:t.orgConfig,identity:t.identity,skipOidc:t.options?.skipOidc})},{verbose:i?.verbose,infraOnly:i?.infraOnly},t.orgConfig),u=s.frameworkRegistry.resolve({appPath:n.path});let E;const T=v==="rollback";if(u&&!T){E=u.builder.plan({appPath:n.path},u.detection);const e=Te(r),a=await u.builder.build(n.path,E,e,{skipBuild:i?.skipBuild,infraOnly:i?.infraOnly});if(!a.success){const o=new Error(k(a.error.message));return r.onError?.(o),l(o)}}if(v==="code-only"||T){r.onLog?.(T?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 e=q(n.path,"cdk.out"),a=re(e),o=a.length>0,p=u?.detection.hasDockerfile===!0,d=o||p;I.debug(N,"Deploy-only branch entered",{mode:v,imageTag:i?.imageTag,serviceImageTags:i?.serviceImageTags,appName:n.appName,appPath:n.path,cdkOutPath:e,dockerProviderAvailable:t.dockerProvider!==void 0,builderName:u?.builder.name,hasDockerfileFromManifest:o,hasDockerfileFromDisk:p,hasDockerfile:d,manifestDockerServiceCount:a.length,manifestDockerPaths:a.map(y=>y.docker.path)}),!o&&!p&&r.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");let g={};if(!T&&t.dockerProvider!==void 0&&d){I.debug(N,"Running Docker build before code-only deploy",{source:o?"manifest":"disk"});const y=await fe(t,s,n,r);if(!y.success)return l(y.error);g=y.data.contentHashTagsByService}else I.debug(N,"Skipping Docker build",{reason:T?"rollback":t.dockerProvider===void 0?"no dockerProvider":"no Dockerfile detected"});return we(t,s,n,g)}r.onLog?.("Analysing infrastructure\u2026","info");const R=await le(n,s,D,r);if(!R.success){const e=new Error(k(R.error.message));return r.onError?.(e),l(e)}const c=R.data;try{await r.onDetectionComplete?.({...c,builderName:u?.builder.name??"unknown"})}catch(e){const a=e instanceof Error?e.message:String(e),o=new Error(k(a));return r.onError?.(o),l(o)}const J={deploymentType:"application",operation:"deploy",deployOnly:!1,infraOnly:i?.infraOnly??!1,hasDockerfile:c.hasDockerfile,pattern:c.pattern,resources:c.resources,...u&&{builderName:u.builder.name}},x=pe.getSteps(J),L=x.findIndex(e=>e.id===P.TARGET_READINESS),_=await me(r,{stepId:P.TARGET_READINESS,stepName:de.TARGET_READINESS,...L>=0&&{stepIndex:L,totalSteps:x.length}},async()=>{if(i?.skipReadinessCheck)return r.onLog?.("Skipping target readiness check (--skip-readiness-check)","warn"),{kind:"skipped",data:void 0};const e=s.awsProvider.getAccountId(),a=t.orgConfig?.providerAccounts.find(g=>g.id===e)?.name,o=s.awsProvider.getCredentials(),p=ge(t.orgConfig),d=await ue({cloudFormation:s.awsProvider.getClient(X),ec2:new Z({region:p,...o!==void 0&&{credentials:o}})},{id:e,...a!==void 0&&{name:a}},s.awsProvider.getRegion(),t.orgConfig,t.abortSignal);return d.success?d.data.ready?{kind:"completed",data:void 0}:{kind:"error",error:new Error(k(d.data.advisory))}:{kind:"error",error:new Error(k(d.error.message))}},t.abortSignal);if(!_.success)return _;const f=E?E.deployOrder:oe({pattern:c.pattern,resources:c.resources}),b=f.length,j=c.hasDockerfile&&t.dockerProvider!==void 0&&f.includes(O.COMPUTE)&&i?.infraOnly!==!0;if(!c.hasDifferences&&!i?.force&&!j){r.onLog?.("No infrastructure changes detected","info"),r.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 e=c.hasDockerfile&&t.dockerProvider!==void 0&&f.includes(O.COMPUTE);for(let o=0;o<f.length;o++){const p=f[o];e&&p===O.COMPUTE&&(r.onStepStart?.(P.DOCKER_OPERATIONS,Y),r.onStepComplete?.(P.DOCKER_OPERATIONS,Y,"skipped"));const d=z(p,"deploy"),g=W(p,"deploy");r.onStepStart?.(d,g,o,b),r.onStepComplete?.(d,g,"skipped",o,b)}const a=await s.stackService.resolveWebsiteUrl(n.appName);return S({target:n.appName,deploymentType:"application",outputs:a?{websiteUrl:a}:void 0,noChanges:!0,artefacts:[],durationMs:Date.now()-h})}if(t.approvalGate!==void 0||i?.approvalToken!==void 0&&i.approvalToken!==""||i?.planOnly===!0){const e=q(n.path,"cdk.out"),a=await ve({approvalGate:t.approvalGate,options:i??{},target:n.appName,cdkOutPath:e,detection:{stackChanges:c.stackChanges,currentHashes:c.currentHashes},cfnService:s.cfnService,callbacks:r});if(!a.success)return a;const o=a.data;if(o.kind==="rejected")return r.onLog?.(`Deploy rejected: ${k(o.reason)}`,"warn"),S({target:n.appName,deploymentType:"application",rejected:!0,artefacts:[],...o.planDetail!==void 0?{planDetail:o.planDetail}:{},durationMs:Date.now()-h});if(o.kind==="awaiting")return S({target:n.appName,deploymentType:"application",awaitingApproval:!0,approvalToken:o.approvalToken,assemblyDigest:o.assemblyDigest,planDetail:o.planDetail,artefacts:[],durationMs:Date.now()-h})}const B=await ce(s,D,r);if(!B.success)return B;const w={},C=new Map;let H;for(let e=0;e<f.length;e++){const a=f[e],o=ne(n.appName,a),p=z(a,"deploy"),d=W(a,"deploy"),g=c.stackChanges.get(o)??!0,y=a===O.COMPUTE&&j;if(!g&&!i?.force&&!y){r.onStepStart?.(p,d,e,b),r.onLog?.(`Skipping ${a} \u2014 no changes detected`,"info"),r.onStepComplete?.(p,d,"skipped",e,b);continue}const A=ke(f,e,c.stackChanges,n.appName,i?.force);if(A.length>=2){const K=await ye(A,n,s,D,r,e,b,c,w,C);if(!K.success)return l(K.error);e+=A.length-1;continue}const m=await be(a,t,s,n,r,c.hasDockerfile);if(m!==null&&!m.success)return l(m.error);m!==null&&m.success&&(H=m.data);const V=m!==null&&m.success?m.data.contentHashTagsByService:{},G=De(V),$=await he(a,s,D,r,e,b,w,G!==void 0?{parameters:G}:void 0);if(!$.success)return l($.error);const F=c.currentHashes.get(o);F&&C.set(o,F)}if(C.size>0){const e=await s.hashService.updateStateAfterDeploy(n.path,C);if(!e.success){const a=k(e.error.message);I.debug(N,"Failed to update state file",{error:a}),r.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy unchanged stacks: ${a}`,"warn")}}const U=await s.stackService.resolveWebsiteUrl(n.appName);U&&(w.websiteUrl=U);const Q=await Se(s,n.appName,H,r);return S({target:n.appName,deploymentType:"application",outputs:Object.keys(w).length>0?w:void 0,artefacts:Q,durationMs:Date.now()-h})}export{Je as deployApplication};
@@ -5,6 +5,7 @@ import type { DeployCallbacks } from "../../types/callbacks.js";
5
5
  import type { ApplicationOperation, ApplicationStack } from "../../types/operations.js";
6
6
  import type { DeployServices } from "../serviceFactory.js";
7
7
  import type { DetectionResult } from "./detectionPipeline.js";
8
+ import { type DockerBuildProducts } from "./dockerBuildHelper.js";
8
9
  import type { BuildCallbacks } from "../../types/frameworkBuilder.js";
9
10
  /**
10
11
  * Identify Phase 2 stacks (Storage, Messaging, Database) that are consecutive
@@ -23,20 +24,18 @@ interface DeployStackSequentialOptions {
23
24
  * Deploy a single stack with step lifecycle events and output collection.
24
25
  */
25
26
  export declare function deployStackSequential(stack: ApplicationStack, services: DeployServices, context: DeploymentContext, callbacks: DeployCallbacks, stepIndex: number, totalSteps: number, allOutputs: Record<string, string>, deployOptions?: DeployStackSequentialOptions): Promise<Result<void>>;
26
- export interface DockerPreComputeOutcome {
27
- /**
28
- * Map from service name (with optional target suffix) to the resolved
29
- * content-hash tag pushed during this build phase. Empty for the legacy
30
- * single-image fallback path and for welcome-image setup; the orchestrator
31
- * skips `--parameters` plumbing in those cases.
32
- */
33
- contentHashTagsByService: Record<string, string>;
34
- }
27
+ /**
28
+ * What the pre-Compute docker phase produced: the per-service content-hash
29
+ * tag map (drives `--parameters` plumbing; empty for the legacy fallback and
30
+ * welcome-image paths) plus the digests/repo URI consumed by full-deploy
31
+ * artefact collection.
32
+ */
33
+ export type DockerPreComputeOutcome = DockerBuildProducts;
35
34
  /**
36
35
  * Run Docker build/push or welcome image setup before the Compute stack.
37
- * Returns a `Result<DockerPreComputeOutcome>` on success carrying the
38
- * per-service content-hash tag map, a failure on docker error, or `null`
39
- * when no docker work is required for this stack.
36
+ * Returns a `Result<DockerPreComputeOutcome>` on success carrying the build
37
+ * products, a failure on docker error, or `null` when no docker work is
38
+ * required for this stack.
40
39
  */
41
40
  export declare function runDockerPreCompute(stack: ApplicationStack, params: DeployParams, services: DeployServices, operation: ApplicationOperation, callbacks: DeployCallbacks, hasDockerfileOnDisk: boolean): Promise<Result<DockerPreComputeOutcome> | null>;
42
41
  /**
@@ -1,4 +1,4 @@
1
- import{success as h,failure as S}from"@fjall/generator";import{maskSensitiveOutput as C}from"@fjall/util";import{isAborted as R}from"../../aws/organisations/types.js";import{APPLICATION_STACKS as E,getApplicationStackName as O,getApplicationStepName as y,getApplicationStepId as N,PARALLEL_DEPLOY_GROUPS as L}from"../../types/operations.js";import{emitProgress as I}from"../../services/supporting/helpers.js";import{forwardOutput as B,forwardResourceProgress as _}from"../contextHelpers.js";import{runDockerBuild as k}from"./dockerBuildHelper.js";import{runWelcomeImageSetup as $}from"./welcomeImageHelper.js";import{withStepLifecycle as j}from"../stepLifecycle.js";function M(t,o,s,p,r){const c=new Set(L.PHASE_2.stacks),i=[];for(let n=o;n<t.length&&c.has(t[n]);n++)i.push(t[n]);if(i.length<2)return[];if(!r){const n=i.filter(f=>{const m=O(p,f);return s.get(m)!==!1});return n.length>=2?n:[]}return i}async function W(t,o,s,p,r,c,i,n,f,m){for(let e=0;e<t.length;e++){const a=t[e],l=N(a,"deploy"),d=y(a,"deploy");r.onStepStart?.(l,d,c+e,i)}I(r,"Deploying infrastructure in parallel\u2026"),r.onParallelPhaseStart?.(t,"Storage and database resources (parallel)");const u=await s.stackService.deployStacksInParallel(t,p,{onOutput:B(r),onResourceProgress:(e,a)=>{r.onResourceProgress?.(e),a&&r.onParallelStackResourceProgress?.(a,e)},onStackComplete:(e,a,l,d)=>{const P=N(e,"deploy"),x=y(e,"deploy"),A=c+t.indexOf(e),w=R(s.abortSignal);r.onStepComplete?.(P,x,a?"completed":w?"cancelled":"error",A,i),!a&&d&&!w&&r.onError?.(new Error(C(d.message)))}});if(!u.success)return r.onParallelPhaseComplete?.([]),S(u.error);const g=u.data.filter(e=>!e.success);if(r.onParallelPhaseComplete?.(u.data.map(e=>({stack:e.stack,success:e.success,error:e.error}))),g.length>0){const e=g.map(l=>l.stack).join(", "),a=g.map(l=>`${l.stack}: ${C(l.error?.message??"Unknown error")}`).join(`
1
+ import{success as h,failure as S}from"@fjall/generator";import{maskSensitiveOutput as C}from"@fjall/util";import{isAborted as R}from"../../aws/organisations/types.js";import{APPLICATION_STACKS as E,getApplicationStackName as O,getApplicationStepName as y,getApplicationStepId as N,PARALLEL_DEPLOY_GROUPS as L}from"../../types/operations.js";import{emitProgress as I}from"../../services/supporting/helpers.js";import{forwardOutput as x,forwardResourceProgress as _}from"../contextHelpers.js";import{emptyBuildProducts as k,runDockerBuild as $}from"./dockerBuildHelper.js";import{runWelcomeImageSetup as j}from"./welcomeImageHelper.js";import{withStepLifecycle as D}from"../stepLifecycle.js";function W(t,o,s,p,r){const d=new Set(L.PHASE_2.stacks),i=[];for(let n=o;n<t.length&&d.has(t[n]);n++)i.push(t[n]);if(i.length<2)return[];if(!r){const n=i.filter(f=>{const m=O(p,f);return s.get(m)!==!1});return n.length>=2?n:[]}return i}async function Y(t,o,s,p,r,d,i,n,f,m){for(let e=0;e<t.length;e++){const u=t[e],l=N(u,"deploy"),c=y(u,"deploy");r.onStepStart?.(l,c,d+e,i)}I(r,"Deploying infrastructure in parallel\u2026"),r.onParallelPhaseStart?.(t,"Storage and database resources (parallel)");const a=await s.stackService.deployStacksInParallel(t,p,{onOutput:x(r),onResourceProgress:(e,u)=>{r.onResourceProgress?.(e),u&&r.onParallelStackResourceProgress?.(u,e)},onStackComplete:(e,u,l,c)=>{const P=N(e,"deploy"),A=y(e,"deploy"),B=d+t.indexOf(e),w=R(s.abortSignal);r.onStepComplete?.(P,A,u?"completed":w?"cancelled":"error",B,i),!u&&c&&!w&&r.onError?.(new Error(C(c.message)))}});if(!a.success)return r.onParallelPhaseComplete?.([]),S(a.error);const g=a.data.filter(e=>!e.success);if(r.onParallelPhaseComplete?.(a.data.map(e=>({stack:e.stack,success:e.success,error:e.error}))),g.length>0){const e=g.map(l=>l.stack).join(", "),u=g.map(l=>`${l.stack}: ${C(l.error?.message??"Unknown error")}`).join(`
2
2
  `);return S(new Error(`Failed to deploy stacks: ${e}
3
3
 
4
- ${a}`))}for(const e of u.data){if(e.success&&e.outputs)for(const[d,P]of Object.entries(e.outputs))f[d]=String(P);const a=O(o.appName,e.stack),l=n.currentHashes.get(a);l&&m.set(a,l)}return h(void 0)}async function Y(t,o,s,p,r,c,i,n){const f=N(t,"deploy"),m=y(t,"deploy");return j(p,{stepId:f,stepName:m,stepIndex:r,totalSteps:c},async()=>{const u=await o.stackService.deployStack(t,s,{onOutput:B(p),onResourceProgress:_(p)},n?.parameters!==void 0?{parameters:n.parameters}:void 0);if(!u.success)return{kind:"error",error:u.error};if(u.data.outputs)for(const[g,e]of Object.entries(u.data.outputs))i[g]=String(e);return{kind:"completed",data:void 0}},o.abortSignal)}async function z(t,o,s,p,r,c){if(t!==E.COMPUTE||!o.dockerProvider)return null;if(c){const n=await k(o,s,p,r);return n.success?h({contentHashTagsByService:n.data}):S(n.error)}const i=await $(o,s,p,r);return i.success?h({contentHashTagsByService:{}}):S(i.error)}function J(t){return{onBuildStart:o=>{t.onOpenNextBuildStart?.(),t.onLog?.(`${o} build started`,"info")},onBuildProgress:(o,s)=>{t.onOpenNextProgress?.(s)},onBuildComplete:o=>{t.onOpenNextBuildComplete?.(),t.onLog?.(`${o} build complete`,"info")},onBuildError:(o,s)=>{t.onOpenNextBuildError?.(s)}}}export{J as createBuildCallbacks,W as deployParallelPhase,Y as deployStackSequential,M as getParallelPhase2Stacks,z as runDockerPreCompute};
4
+ ${u}`))}for(const e of a.data){if(e.success&&e.outputs)for(const[c,P]of Object.entries(e.outputs))f[c]=String(P);const u=O(o.appName,e.stack),l=n.currentHashes.get(u);l&&m.set(u,l)}return h(void 0)}async function z(t,o,s,p,r,d,i,n){const f=N(t,"deploy"),m=y(t,"deploy");return D(p,{stepId:f,stepName:m,stepIndex:r,totalSteps:d},async()=>{const a=await o.stackService.deployStack(t,s,{onOutput:x(p),onResourceProgress:_(p)},n?.parameters!==void 0?{parameters:n.parameters}:void 0);if(!a.success)return{kind:"error",error:a.error};if(a.data.outputs)for(const[g,e]of Object.entries(a.data.outputs))i[g]=String(e);return{kind:"completed",data:void 0}},o.abortSignal)}async function J(t,o,s,p,r,d){if(t!==E.COMPUTE||!o.dockerProvider)return null;if(d){const n=await $(o,s,p,r);return n.success?h(n.data):S(n.error)}const i=await j(o,s,p,r);return i.success?h(k()):S(i.error)}function Q(t){return{onBuildStart:o=>{t.onOpenNextBuildStart?.(),t.onLog?.(`${o} build started`,"info")},onBuildProgress:(o,s)=>{t.onOpenNextProgress?.(s)},onBuildComplete:o=>{t.onOpenNextBuildComplete?.(),t.onLog?.(`${o} build complete`,"info")},onBuildError:(o,s)=>{t.onOpenNextBuildError?.(s)}}}export{Q as createBuildCallbacks,Y as deployParallelPhase,z as deployStackSequential,W as getParallelPhase2Stacks,J as runDockerPreCompute};
@@ -15,7 +15,7 @@
15
15
  import { type Result } from "@fjall/generator";
16
16
  import type { DeployCallbacks } from "../../types/callbacks.js";
17
17
  import type { DeployOptions } from "../../types/params.js";
18
- import type { ApprovalGate } from "../../types/approval.js";
18
+ import type { ApprovalGate, ApprovalGatePlanDetail } from "../../types/approval.js";
19
19
  import { type CfnTemplateReader } from "./plan/computeDeployPlan.js";
20
20
  export interface RunApprovalGateParams {
21
21
  /** The surface resolver. Optional — a token-resume or plan-only run needs none. */
@@ -35,10 +35,12 @@ export type ApprovalGateOutcome = {
35
35
  } | {
36
36
  kind: "rejected";
37
37
  reason: string;
38
+ planDetail?: ApprovalGatePlanDetail;
38
39
  } | {
39
40
  kind: "awaiting";
40
41
  approvalToken: string;
41
42
  assemblyDigest: string;
42
43
  expiresAt: string;
44
+ planDetail: ApprovalGatePlanDetail;
43
45
  };
44
46
  export declare function runApprovalGate(params: RunApprovalGateParams): Promise<Result<ApprovalGateOutcome, Error>>;
@@ -1 +1 @@
1
- import{join as f}from"node:path";import{readFile as k}from"node:fs/promises";import{success as o,failure as d}from"@fjall/generator";import{maskSensitiveOutput as v}from"@fjall/util";import{computeAssemblyDigest as g}from"./plan/assemblyDigest.js";import{computeDeployPlan as m}from"./plan/computeDeployPlan.js";import{renderPlanLines as h}from"./plan/renderDeployPlan.js";import{signApprovalToken as y,verifyApprovalToken as w}from"./plan/approvalToken.js";function A(e){switch(e){case"superseded":return"the plan changed since it was approved (re-plan and approve again)";case"expired":return"the approval window expired";case"tampered":return"the approval signature did not verify";case"malformed":return"the approval token was malformed"}}async function x(e){const t=[];for(const n of e.changedStacks){const c=f(e.cdkOutPath,`${n}.template.json`);let i;try{i=JSON.parse(await k(c,"utf8"))}catch(r){return d(new Error(v(`Failed to read synthesised template for ${n}: ${r instanceof Error?r.message:String(r)}`)))}t.push({stackName:n,newTemplate:i})}return m({cfnService:e.cfnService,stacks:t,assemblyDigest:e.assemblyDigest})}function S(e,t){e.onLog?.(`Deploy plan: ${t.summary}`,"info");for(const n of h(t))e.onLog?.(n,"info")}async function C(e){const t=g(e.detection.currentHashes),n=e.options.approvalToken;if(n!==void 0&&n!==""){const s=w({token:n,assemblyDigest:t});if(s.ok)return e.callbacks.onLog?.("Approval token verified against the current plan \u2014 proceeding","info"),o({kind:"proceed"});const l=A(s.reason);return e.callbacks.onLog?.(`Approval refused: ${l}`,"warn"),o({kind:"rejected",reason:l})}const c=[...e.detection.stackChanges.entries()].filter(([,s])=>s).map(([s])=>s),i=await x({cfnService:e.cfnService,cdkOutPath:e.cdkOutPath,changedStacks:c,assemblyDigest:t});if(!i.success)return d(i.error);const r=i.data;S(e.callbacks,r);const a=y({assemblyDigest:t});if(e.options.autoApprove===!0)return e.callbacks.onLog?.("Plan auto-approved (--auto-approve)","info"),o({kind:"proceed"});if(e.options.planOnly===!0)return o({kind:"awaiting",approvalToken:a.token,assemblyDigest:t,expiresAt:a.expiresAt});if(e.approvalGate===void 0)return o({kind:"awaiting",approvalToken:a.token,assemblyDigest:t,expiresAt:a.expiresAt});const u={target:e.target,plan:r,approvalToken:a.token,expiresAt:a.expiresAt,hasDestructiveChanges:r.hasDestructiveChanges},p=await e.approvalGate.resolve(u);switch(p.kind){case"approved":return o({kind:"proceed"});case"rejected":return o({kind:"rejected",reason:p.reason});case"suspended":return o({kind:"awaiting",approvalToken:p.approvalToken,assemblyDigest:t,expiresAt:a.expiresAt})}}export{C as runApprovalGate};
1
+ import{join as k}from"node:path";import{readFile as g}from"node:fs/promises";import{success as s,failure as d}from"@fjall/generator";import{maskSensitiveOutput as h}from"@fjall/util";import{computeAssemblyDigest as v}from"./plan/assemblyDigest.js";import{computeDeployPlan as m}from"./plan/computeDeployPlan.js";import{renderPlanLines as y}from"./plan/renderDeployPlan.js";import{signApprovalToken as w,verifyApprovalToken as A}from"./plan/approvalToken.js";function x(e){switch(e){case"superseded":return"the plan changed since it was approved (re-plan and approve again)";case"expired":return"the approval window expired";case"tampered":return"the approval signature did not verify";case"malformed":return"the approval token was malformed"}}async function D(e){const t=[];for(const n of e.changedStacks){const i=k(e.cdkOutPath,`${n}.template.json`);let r;try{r=JSON.parse(await g(i,"utf8"))}catch(o){return d(new Error(h(`Failed to read synthesised template for ${n}: ${o instanceof Error?o.message:String(o)}`)))}t.push({stackName:n,newTemplate:r})}return m({cfnService:e.cfnService,stacks:t,assemblyDigest:e.assemblyDigest})}function S(e,t,n){const i=t.changeCount===0&&n.length>0?`no resource changes against the live stacks; template hashes differ from the last recorded deploy for ${n.length} stack(s) (${n.join(", ")}) \u2014 applying will redeploy them`:t.summary;e.onLog?.(`Deploy plan: ${i}`,"info");for(const r of y(t))e.onLog?.(r,"info")}async function G(e){const t=v(e.detection.currentHashes),n=e.options.approvalToken;if(n!==void 0&&n!==""){const a=A({token:n,assemblyDigest:t});if(a.ok)return e.callbacks.onLog?.("Approval token verified against the current plan \u2014 proceeding","info"),s({kind:"proceed"});const u=x(a.reason);return e.callbacks.onLog?.(`Approval refused: ${u}`,"warn"),s({kind:"rejected",reason:u})}const i=[...e.detection.stackChanges.entries()].filter(([,a])=>a).map(([a])=>a),r=await D({cfnService:e.cfnService,cdkOutPath:e.cdkOutPath,changedStacks:i,assemblyDigest:t});if(!r.success)return d(r.error);const o=r.data;S(e.callbacks,o,i);const p={hashDriftStacks:i,resourceChangeCount:o.changeCount,resourceChangedStacks:[...new Set(o.changes.map(a=>a.stack))]},c=w({assemblyDigest:t});if(e.options.autoApprove===!0)return e.callbacks.onLog?.("Plan auto-approved (--auto-approve)","info"),s({kind:"proceed"});if(e.options.planOnly===!0)return s({kind:"awaiting",approvalToken:c.token,assemblyDigest:t,expiresAt:c.expiresAt,planDetail:p});if(e.approvalGate===void 0)return s({kind:"awaiting",approvalToken:c.token,assemblyDigest:t,expiresAt:c.expiresAt,planDetail:p});const f={target:e.target,plan:o,approvalToken:c.token,expiresAt:c.expiresAt,hasDestructiveChanges:o.hasDestructiveChanges},l=await e.approvalGate.resolve(f);switch(l.kind){case"approved":return s({kind:"proceed"});case"rejected":return s({kind:"rejected",reason:l.reason,planDetail:p});case"suspended":return s({kind:"awaiting",approvalToken:l.approvalToken,assemblyDigest:t,expiresAt:c.expiresAt,planDetail:p})}}export{G as runApprovalGate};
@@ -0,0 +1,18 @@
1
+ import { type ServiceArtefact } from "@fjall/util";
2
+ import type { DeployCallbacks } from "../../types/callbacks.js";
3
+ import type { DeployServices } from "../serviceFactory.js";
4
+ import type { DockerBuildProducts } from "./dockerBuildHelper.js";
5
+ /**
6
+ * Collect `ServiceArtefact[]` for a successful FULL deploy from the build
7
+ * step's products plus a best-effort post-deploy ECS resolution (the same
8
+ * discovery `deployCodeOnly` uses). Full deploys roll images via CFN
9
+ * `<Service>ImageTag` parameters, so the live task definition is only
10
+ * knowable by describing the services AFTER the deploy.
11
+ *
12
+ * Best-effort by contract: a discovery or describe failure degrades the
13
+ * artefact (ECS-resolved `serviceName` falls back to the build's manifest
14
+ * service name; `taskDefinitionArn` stays absent) and warns — it NEVER fails
15
+ * a deploy that already succeeded. Returns `[]` when the deploy pushed no
16
+ * images (welcome-image seed, legacy fallback, infra-only).
17
+ */
18
+ export declare function collectFullDeployArtefacts(services: DeployServices, appName: string, build: DockerBuildProducts | undefined, callbacks: DeployCallbacks): Promise<ServiceArtefact[]>;
@@ -0,0 +1 @@
1
+ import{maskSensitiveOutput as S}from"@fjall/util";import{logger as g}from"@fjall/util/logger";import{extractEcsServiceName as l}from"../../aws/utils/arnParser.js";import{deriveEcrRepositoryArn as A}from"./codeOnlyDeploy.js";const m="artefactCollection";async function C(c,t,r,n){if(r===void 0||r.repoUri===void 0)return[];const s=Object.entries(r.contentHashTagsByService);if(s.length===0)return[];const o=r.repoUri,i=A(o),d=await y(c,t,n);return s.map(([e,a])=>{const v=r.imageDigestsByService[e],f=p(e,d);return{serviceName:f?.ecsServiceName??e,imageTag:a,imageUri:`${o}:${a}`,...v!==void 0?{imageDigest:v}:{},...i!==""?{ecrRepositoryArn:i}:{},...f?.taskDefinitionArn!==void 0?{taskDefinitionArn:f.taskDefinitionArn}:{}}})}async function y(c,t,r){try{const n=await c.ecsResolver.getDeployableClusterAndServices(t);if(!n.success)return u(r,t,n.error.message),[];const{clusterArn:s,serviceArns:o}=n.data;if(!s||o.length===0)return g.debug(m,"No deployable ECS services discovered",{appName:t}),[];const i=await c.ecsService.describeServices(s,o);if(!i.success)return u(r,t,i.error.message),o.map(e=>l(e)).filter(e=>e!==void 0&&e!=="").map(e=>({ecsServiceName:e}));const d=[];for(const e of i.data){const a=e.serviceName??(e.serviceArn!==void 0?l(e.serviceArn):void 0);a===void 0||a===""||d.push({ecsServiceName:a,...e.taskDefinition!==void 0?{taskDefinitionArn:e.taskDefinition}:{}})}return d}catch(n){return u(r,t,n instanceof Error?n.message:String(n)),[]}}function p(c,t){const r=c.toLowerCase(),n=t.find(i=>i.ecsServiceName.toLowerCase()===r);if(n)return n;const s=t.filter(i=>i.ecsServiceName.toLowerCase().includes(r));if(s.length===1)return s[0];const o=s.filter(i=>i.ecsServiceName.toLowerCase().endsWith(`-${r}`));if(o.length===1)return o[0]}function u(c,t,r){const n=S(r);g.debug(m,"Post-deploy artefact resolution degraded",{appName:t,error:n}),c.onLog?.(`Deploy succeeded, but resolving live task definitions for release artefacts failed: ${n}. Artefacts are recorded without task definition ARNs.`,"warn")}export{C as collectFullDeployArtefacts};
@@ -16,6 +16,14 @@ export interface BuildSecretSessionContext {
16
16
  accountId: string;
17
17
  partition: string;
18
18
  }
19
+ /**
20
+ * The inline session policy must stay well under the AWS hard limit (2048 chars
21
+ * for an AssumeRoleWithWebIdentity inline `Policy`). We fail closed before
22
+ * minting a session whose policy would be rejected AWS-side, rather than ship a
23
+ * silently-broadened or truncated policy. Shared with `deploySessionPolicy.ts`
24
+ * — both builders guard the same AWS limit.
25
+ */
26
+ export declare const MAX_INLINE_POLICY_CHARS = 2048;
19
27
  /**
20
28
  * Derive the `aws` / `aws-cn` partition from a region. China regions use the
21
29
  * `aws-cn` partition; everything else (incl. GovCloud `us-gov-*`, which is
@@ -1 +1 @@
1
- import{success as $,failure as g}from"@fjall/generator";import{toKebab as p}from"@fjall/util";const l=2048;function w(s){return s.startsWith("cn-")?"aws-cn":"aws"}function R(s,f){const{region:r,accountId:n,partition:a}=s,i=p(s.appName),u=`arn:${a}:ssm:${r}:${n}:parameter/${i}/*`,m=`arn:${a}:secretsmanager:${r}:${n}:secret:fjall-${i}-*`,t=new Set;for(const e of f){if(e.ssm!==void 0&&e.ssm!==""){const c=e.ssm.startsWith("/")?e.ssm.slice(1):e.ssm;c.startsWith(`${i}/`)||t.add(`arn:${a}:ssm:${r}:${n}:parameter/${c}`)}if(e.secretsManagerArn!==void 0&&e.secretsManagerArn!==""){const c=m.replace(/\*$/,"");e.secretsManagerArn.startsWith(c)||t.add(e.secretsManagerArn)}e.secretsManagerName!==void 0&&e.secretsManagerName!==""&&!e.secretsManagerName.startsWith(`fjall-${i}-`)&&t.add(`arn:${a}:secretsmanager:${r}:${n}:secret:${e.secretsManagerName}-*`)}const d=[{Sid:"FjallBuildSsmRead",Effect:"Allow",Action:["ssm:GetParameter","ssm:GetParameters"],Resource:[u,...[...t].filter(S)]},{Sid:"FjallBuildSecretsManagerRead",Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:[m,...[...t].filter(A)]},{Sid:"FjallBuildKmsDecrypt",Effect:"Allow",Action:["kms:Decrypt"],Resource:"*",Condition:{StringEquals:{"kms:ViaService":[`ssm.${r}.amazonaws.com`,`secretsmanager.${r}.amazonaws.com`]}}}],o=JSON.stringify({Version:"2012-10-17",Statement:d});return o.length>l?g(new Error(`Build-secret session policy is ${o.length} chars, exceeding the ${l}-char AWS inline-policy limit. Reduce the number of out-of-prefix secret/parameter references for this build.`)):$(o)}function S(s){return s.includes(":ssm:")}function A(s){return s.includes(":secretsmanager:")}export{R as buildBuildSecretSessionPolicy,w as partitionForRegion};
1
+ import{success as $,failure as g}from"@fjall/generator";import{toKebab as p}from"@fjall/util";const l=2048;function w(s){return s.startsWith("cn-")?"aws-cn":"aws"}function R(s,f){const{region:r,accountId:n,partition:a}=s,i=p(s.appName),u=`arn:${a}:ssm:${r}:${n}:parameter/${i}/*`,m=`arn:${a}:secretsmanager:${r}:${n}:secret:fjall-${i}-*`,t=new Set;for(const e of f){if(e.ssm!==void 0&&e.ssm!==""){const c=e.ssm.startsWith("/")?e.ssm.slice(1):e.ssm;c.startsWith(`${i}/`)||t.add(`arn:${a}:ssm:${r}:${n}:parameter/${c}`)}if(e.secretsManagerArn!==void 0&&e.secretsManagerArn!==""){const c=m.replace(/\*$/,"");e.secretsManagerArn.startsWith(c)||t.add(e.secretsManagerArn)}e.secretsManagerName!==void 0&&e.secretsManagerName!==""&&!e.secretsManagerName.startsWith(`fjall-${i}-`)&&t.add(`arn:${a}:secretsmanager:${r}:${n}:secret:${e.secretsManagerName}-*`)}const d=[{Sid:"FjallBuildSsmRead",Effect:"Allow",Action:["ssm:GetParameter","ssm:GetParameters"],Resource:[u,...[...t].filter(S)]},{Sid:"FjallBuildSecretsManagerRead",Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:[m,...[...t].filter(A)]},{Sid:"FjallBuildKmsDecrypt",Effect:"Allow",Action:["kms:Decrypt"],Resource:"*",Condition:{StringEquals:{"kms:ViaService":[`ssm.${r}.amazonaws.com`,`secretsmanager.${r}.amazonaws.com`]}}}],o=JSON.stringify({Version:"2012-10-17",Statement:d});return o.length>l?g(new Error(`Build-secret session policy is ${o.length} chars, exceeding the ${l}-char AWS inline-policy limit. Reduce the number of out-of-prefix secret/parameter references for this build.`)):$(o)}function S(s){return s.includes(":ssm:")}function A(s){return s.includes(":secretsmanager:")}export{l as MAX_INLINE_POLICY_CHARS,R as buildBuildSecretSessionPolicy,w as partitionForRegion};
@@ -54,5 +54,18 @@ export declare function rebaseRollbackTagForService(suppliedTag: string, service
54
54
  * per service via `rebaseRollbackTagForService` so each service rolls its OWN
55
55
  * `<service>-…` image family (a multi-image stack shares one ECR repo, so an
56
56
  * un-rebased tag would silently roll the wrong service's image).
57
+ *
58
+ * `options.serviceImageTags` (F12) is a THIRD, mutually-exclusive tag source:
59
+ * an exact per-service map (bare service name → tag) recorded by a prior
60
+ * Release. Unlike `imageTag`, map-supplied tags are never re-based — they
61
+ * already name the exact service — and never fall back to tag pinning; see
62
+ * `serviceImageTagsRollback.ts`.
57
63
  */
58
64
  export declare function deployCodeOnly(params: DeployParams, services: DeployServices, operation: ApplicationOperation, contentHashTagsByService: Record<string, string>): Promise<Result<DeployResult>>;
65
+ /**
66
+ * Derive an ECR repository ARN from an image URI of shape
67
+ * `<account>.dkr.ecr.<region>.amazonaws.com/<repo>`. Returns "" when the URI
68
+ * does not match the ECR pattern (e.g. third-party registries) so the caller
69
+ * can persist the imageUri without a misleading ARN.
70
+ */
71
+ export declare function deriveEcrRepositoryArn(repoUri: string): string;
@@ -1 +1 @@
1
- import{join as _}from"path";import{success as j,failure as S}from"@fjall/generator";import{logger as L}from"@fjall/util/logger";import{maskSensitiveOutput as v}from"@fjall/util";import{parseDockerServicesFromManifest as N}from"@fjall/util/manifest";import{APPLICATION_STACKS as F,getApplicationStepId as W,getApplicationStepName as q}from"../../types/operations.js";import{extractEcsServiceName as O}from"../../aws/utils/arnParser.js";import{stripTagOrDigest as U}from"../../services/infrastructure/EcrImageInspectorService.js";import{withStepLifecycle as z}from"../stepLifecycle.js";const I="codeOnlyDeploy";function G(n,a){if(n)return a[n.name]}function H(n,a){const o=a.toLowerCase();return n.find(t=>t.name.toLowerCase()===o)??n.find(t=>o.includes(t.name.toLowerCase()))}function K(n,a,o){const t=a.toLowerCase(),c=n.toLowerCase(),g=o.map(p=>p.toLowerCase()).filter(p=>p!==""&&c.startsWith(`${p}-`)).sort((p,T)=>T.length-p.length)[0];if(g===void 0||g===t)return n;const E=n.slice(g.length);return`${t}${E}`}const X=0,Y=1;async function ae(n,a,o,t){const{callbacks:c,options:g}=n,E=Date.now(),p=W(F.COMPUTE,"deploy"),T=q(F.COMPUTE,"deploy");return z(c,{stepId:p,stepName:T,stepIndex:X,totalSteps:Y},async()=>{const d=g?.imageTag;d&&c.onLog?.(`Rolling to supplied image tag ${d}`,"info");const D=N(_(o.path,"cdk.out"));L.debug(I,"Code-only rollout starting",{explicitRollbackTag:d,workingDirectory:n.workingDirectory,contentHashTagsByService:t,manifestServiceCount:D.length,manifestServices:D.map(e=>({name:e.name,target:e.docker.target}))}),c.onLog?.("Discovering ECS cluster and services\u2026","info");const h=await a.ecsResolver.getDeployableClusterAndServices(o.appName);if(!h.success)return L.debug(I,"ECS discovery failed",{appName:o.appName,error:v(h.error.message)}),{kind:"error",error:h.error};const{clusterArn:r,serviceArns:m}=h.data;if(L.debug(I,"ECS discovery complete",{appName:o.appName,clusterArn:r,serviceCount:m.length,serviceArns:m}),!r||m.length===0){const e=`No deployable ECS services found for ${o.appName}`;return c.onLog?.(e,"warn"),{kind:"skipped",data:{target:o.appName,deploymentType:"application",durationMs:Date.now()-E,noChanges:!0}}}const b=g?.serviceName?.toLowerCase(),$=b===""?void 0:b,f=$?m.filter(e=>{const l=(O(e)??"").toLowerCase();return l===$||l.endsWith($)}):m;if($&&f.length===0){const e=m.map(l=>O(l)??"unknown").join(", ");return{kind:"error",error:new Error(`Service '${$}' not found. Available: ${e||"none"}`)}}const w={},k=[],R=m.map(e=>O(e)).filter(e=>e!==void 0&&e!=="");for(let e=0;e<f.length;e++){const l=f[e];if(!l)continue;const i=O(l)??`service-${e+1}`,A=`[${e+1}/${f.length}] ${i}`,y=H(D,i),x=G(y,t);let C,s;if(d!==void 0)C=K(d,i,R),C!==d?(s=d,c.onLog?.(`Re-based image tag ${d} \u2192 ${C} for ${i}`,"info")):R.length>1&&!d.toLowerCase().startsWith(`${i.toLowerCase()}-`)&&c.onLog?.(`Image tag ${d} has no recognised service prefix; applying verbatim to ${i} \u2014 confirm it points at this service's image`,"warn");else if(x!==void 0)C=x;else{const P=`No image available to deploy for ${i}: 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.`;c.onLog?.(P,"warn"),k.push(`${i}: ${P}`);continue}L.debug(I,"Starting service rollout",{serviceName:i,serviceArn:l,imageTag:C,explicitRollbackTag:d,contentHashTag:x,manifestServiceMatched:y?.name,dockerTarget:y?.docker.target,index:e,total:f.length}),c.onECSUpdate?.(`${A}: rolling out image tag ${C}`,i);const u=await J(a,r,l,i,C,c,s);if(L.debug(I,"Service rollout completed",{serviceName:i,success:u.success,...u.success?{taskDefinitionArn:u.data.taskDefinitionArn,imageDigest:u.data.imageDigest,durationMs:u.data.durationMs}:{error:v(u.error.message)}}),!u.success){k.push(`${i}: ${v(u.error.message)}`);continue}w[`${i}TaskDefinition`]=u.data.taskDefinitionArn,w[`${i}PreviousTaskDefinition`]=u.data.previousTaskDefinitionArn,w[`${i}ImageTag`]=C,w[`${i}ImageUri`]=u.data.imageUri,w[`${i}EcrRepositoryArn`]=u.data.ecrRepositoryArn,u.data.imageDigest!==void 0&&(w[`${i}ImageDigest`]=u.data.imageDigest)}const M=Date.now()-E;if(k.length>0){const e=f.length-k.length,l=f.length,i=k.length===l?`All ${l} ECS service rollouts failed: ${k.join("; ")}`:`Partial rollout: ${e}/${l} services succeeded. Failures: ${k.join("; ")}`;return{kind:"error",error:new Error(i)}}return{kind:"completed",data:{target:o.appName,deploymentType:"application",outputs:Object.keys(w).length>0?w:void 0,durationMs:M}}},n.abortSignal)}async function J(n,a,o,t,c,g,E){const p=Date.now(),T=await n.ecsService.describeServices(a,[o]);if(!T.success)return S(new Error(`Failed to describe service ${t}: ${T.error.message}`));const d=T.data[0];if(!d?.taskDefinition)return S(new Error(`Service ${t} has no task definition`));const D=d.taskDefinition,h=await n.ecsService.getLatestTaskDefinition(D);if(!h.success)return S(new Error(`Failed to fetch task definition for ${t}: ${h.error.message}`));const r=h.data;if(!r||!r.containerDefinitions||r.containerDefinitions.length===0)return S(new Error(`Task definition for ${t} has no container definitions`));const m=r.containerDefinitions.find(s=>s.image)?.image;if(!m)return S(new Error(`Task definition for ${t} has no container image \u2014 cannot derive repository URI`));const b=U(m),$=await n.ecrImageInspector.getImageDigest(b,c);let f;if($.success)f=$.data;else{if(E!==void 0)return S(new Error(`Re-based image tag '${c}' (from supplied '${E}') was not found in ECR for ${t}: ${v($.error.message)}. The supplied tag's build has no image for ${t} \u2014 supply that service's own tag, or pass --service to roll a single service.`));g.onLog?.(`Could not resolve image digest for ${t} (${v($.error.message)}); falling back to tag pinning`,"warn")}const w=s=>f!==void 0?`${s}@${f}`:`${s}:${c}`,k=r.containerDefinitions.map(s=>s.image?{...s,image:w(U(s.image))}:s),R=r.family;if(!R)return S(new Error(`Task definition for ${t} has no family`));const M=await n.ecsService.registerTaskDefinition({family:R,taskRoleArn:r.taskRoleArn,executionRoleArn:r.executionRoleArn,networkMode:r.networkMode,containerDefinitions:k,volumes:r.volumes,placementConstraints:r.placementConstraints,requiresCompatibilities:r.requiresCompatibilities,cpu:r.cpu,memory:r.memory,runtimePlatform:r.runtimePlatform,proxyConfiguration:r.proxyConfiguration,inferenceAccelerators:r.inferenceAccelerators,pidMode:r.pidMode,ipcMode:r.ipcMode,ephemeralStorage:r.ephemeralStorage});if(!M.success)return S(new Error(`Failed to register task definition for ${t}: ${M.error.message}`));const e=M.data;g.onTaskDefRegistered?.({serviceName:t,taskDefinitionArn:e,previousTaskDefinitionArn:D,revision:V(e),family:R,...f!==void 0?{imageDigest:f}:{}});const l=await n.ecsService.updateService(a,o,{taskDefinition:e,forceNewDeployment:!0});if(!l.success)return S(new Error(`Failed to update service ${t}: ${l.error.message}`));const i=await n.ecsService.pollDeployment({clusterArn:a,serviceArn:o,waitForCompletion:!0,progressCallback:s=>{const u=s.latestEvent?` \u2014 ${v(s.latestEvent)}`:"";g.onECSProgress?.(`${t}: ${v(s.message)}${u}`,s.percentComplete)}}),A=Date.now()-p;if(!i.success){const s=v(i.error.message);return g.onECSComplete?.({serviceName:t,serviceArn:o,success:!1,taskDefinitionArn:e,durationMs:A,reason:s}),S(new Error(`ECS rollout failed for ${t}: ${s}`))}const y=await n.ecsService.getDeploymentStatus(a,o);g.onECSComplete?.({serviceName:t,serviceArn:o,success:!0,taskDefinitionArn:e,durationMs:A,finalRunningCount:y.success?y.data.runningCount:void 0,finalDesiredCount:y.success?y.data.desiredCount:void 0}),L.debug(I,`Rolled out ${t} successfully`,{serviceArn:o,newTaskDefArn:e,previousTaskDefArn:D,durationMs:A});const x=`${b}:${c}`,C=Q(b);return j({taskDefinitionArn:e,previousTaskDefinitionArn:D,imageUri:x,ecrRepositoryArn:C,imageDigest:f,durationMs:A})}function Q(n){const a=n.match(/^(\d{12})\.dkr\.ecr\.([a-z0-9-]+)\.amazonaws\.com\/(.+)$/);if(!a)return"";const[,o,t,c]=a;return`arn:aws:ecr:${t}:${o}:repository/${c}`}function V(n){const a=n.lastIndexOf(":");if(a<0)return 0;const o=n.slice(a+1);return/^\d+$/.test(o)?parseInt(o,10):0}export{ae as deployCodeOnly,G as lookupContentHashTag,K as rebaseRollbackTagForService};
1
+ import{join as W}from"path";import{success as H,failure as O}from"@fjall/generator";import{logger as A}from"@fjall/util/logger";import{artefactOutputKey as I,imageTagParameterName as X,maskSensitiveOutput as C}from"@fjall/util";import{parseDockerServicesFromManifest as Y}from"@fjall/util/manifest";import{APPLICATION_STACKS as x,getApplicationStackName as q,getApplicationStepId as J,getApplicationStepName as Q}from"../../types/operations.js";import{extractEcsServiceName as L}from"../../aws/utils/arnParser.js";import{isAborted as K}from"../../aws/organisations/types.js";import{stripTagOrDigest as V}from"../../services/infrastructure/EcrImageInspectorService.js";import{withStepLifecycle as Z}from"../stepLifecycle.js";import{registerAndRollTaskDefinition as B}from"./taskDefinitionRoll.js";import{matchesServiceName as ee,matchServiceImageTagsToLiveServices as te,preflightResolveServiceImageTagDigests as re,resolveServiceTaskDefinition as ie}from"./serviceImageTagsRollback.js";const N="codeOnlyDeploy";function ne(t,s){if(t)return s[t.name]}function ae(t,s){const e=s.toLowerCase();return t.find(i=>i.name.toLowerCase()===e)??t.find(i=>e.includes(i.name.toLowerCase()))}function oe(t,s,e){const i=s.toLowerCase(),n=t.toLowerCase(),d=e.map(c=>c.toLowerCase()).filter(c=>c!==""&&n.startsWith(`${c}-`)).sort((c,m)=>m.length-c.length)[0];if(d===void 0||d===i)return t;const f=t.slice(d.length);return`${i}${f}`}const se=0,ce=1;function j(t,s,e,i,n){i[I(t,"TaskDefinition")]=e.taskDefinitionArn,i[I(t,"PreviousTaskDefinition")]=e.previousTaskDefinitionArn,i[I(t,"ImageTag")]=s,i[I(t,"ImageUri")]=e.imageUri,i[I(t,"EcrRepositoryArn")]=e.ecrRepositoryArn,e.imageDigest!==void 0&&(i[I(t,"ImageDigest")]=e.imageDigest),n.push({serviceName:t,imageTag:s,imageUri:e.imageUri,taskDefinitionArn:e.taskDefinitionArn,previousTaskDefinitionArn:e.previousTaskDefinitionArn,...e.imageDigest!==void 0?{imageDigest:e.imageDigest}:{},...e.ecrRepositoryArn!==""?{ecrRepositoryArn:e.ecrRepositoryArn}:{}})}async function F(t,s,e,i,n){if(e.length===0)return;const d=q(s,x.COMPUTE),f={};for(const{serviceName:m,imageTag:l}of e)f[X(m)]=l;const c=await t.cfnService.updateStackParameters(d,f,n);if(!c.success){i.onLog?.(`Rollback succeeded but the CloudFormation ImageTag parameter reconcile failed \u2014 the next full deploy may revert this rollback. Reason: ${C(c.error.message)}`,"warn");return}c.data.skippedKeys.length>0&&(i.onLog?.(`Rollback succeeded but ${c.data.skippedKeys.length} ImageTag parameter(s) were not found on stack ${d} (${c.data.skippedKeys.join(", ")}) \u2014 the next full deploy may revert those services`,"warn"),A.debug(N,"ImageTag reconcile skipped stale parameters",{stackName:d,skippedKeys:c.data.skippedKeys}))}async function Se(t,s,e,i){const{callbacks:n,options:d}=t,f=Date.now(),c=J(x.COMPUTE,"deploy"),m=Q(x.COMPUTE,"deploy");return Z(n,{stepId:c,stepName:m,stepIndex:se,totalSteps:ce},async()=>{const l=d?.imageTag,$=d?.serviceImageTags;l?n.onLog?.(`Rolling to supplied image tag ${l}`,"info"):$&&n.onLog?.(`Rolling ${Object.keys($).length} service(s) to their release-recorded image tags`,"info");const k=Y(W(e.path,"cdk.out"));A.debug(N,"Code-only rollout starting",{explicitRollbackTag:l,serviceImageTags:$,workingDirectory:t.workingDirectory,contentHashTagsByService:i,manifestServiceCount:k.length,manifestServices:k.map(o=>({name:o.name,target:o.docker.target}))}),n.onLog?.("Discovering ECS cluster and services\u2026","info");const u=await s.ecsResolver.getDeployableClusterAndServices(e.appName);if(!u.success)return A.debug(N,"ECS discovery failed",{appName:e.appName,error:C(u.error.message)}),{kind:"error",error:u.error};const{clusterArn:D,serviceArns:r}=u.data;if(A.debug(N,"ECS discovery complete",{appName:e.appName,clusterArn:D,serviceCount:r.length,serviceArns:r}),!D||r.length===0){const o=`No deployable ECS services found for ${e.appName}`;return n.onLog?.(o,"warn"),{kind:"skipped",data:{target:e.appName,deploymentType:"application",durationMs:Date.now()-f,noChanges:!0,artefacts:[]}}}if($!==void 0)return ge(s,e,D,r,$,n,t.abortSignal,f);const a=d?.serviceName?.toLowerCase(),y=a===""?void 0:a,p=y?r.filter(o=>ee(L(o)??"",y)):r;if(y&&p.length===0){const o=r.map(w=>L(w)??"unknown").join(", ");return{kind:"error",error:new Error(`Service '${y}' not found. Available: ${o||"none"}`)}}const v={},E=[],g=[],b=r.map(o=>L(o)).filter(o=>o!==void 0&&o!=="");for(let o=0;o<p.length;o++){if(K(t.abortSignal))return{kind:"error",error:new Error(`Rollout cancelled after ${E.length}/${p.length} services`)};const w=p[o];if(!w)continue;const h=L(w)??`service-${o+1}`,G=`[${o+1}/${p.length}] ${h}`,R=ae(k,h),M=ne(R,i);let T,P;if(l!==void 0)T=oe(l,h,b),T!==l?(P=l,n.onLog?.(`Re-based image tag ${l} \u2192 ${T} for ${h}`,"info")):b.length>1&&!l.toLowerCase().startsWith(`${h.toLowerCase()}-`)&&n.onLog?.(`Image tag ${l} has no recognised service prefix; applying verbatim to ${h} \u2014 confirm it points at this service's image`,"warn");else if(M!==void 0)T=M;else{const U=`No image available to deploy for ${h}: 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?.(U,"warn"),g.push(`${h}: ${U}`);continue}A.debug(N,"Starting service rollout",{serviceName:h,serviceArn:w,imageTag:T,explicitRollbackTag:l,contentHashTag:M,manifestServiceMatched:R?.name,dockerTarget:R?.docker.target,index:o,total:p.length}),n.onECSUpdate?.(`${G}: rolling out image tag ${T}`,h);const S=await _(s,D,w,h,T,n,P,void 0,t.abortSignal);if(A.debug(N,"Service rollout completed",{serviceName:h,success:S.success,...S.success?{taskDefinitionArn:S.data.taskDefinitionArn,imageDigest:S.data.imageDigest,durationMs:S.data.durationMs}:{error:C(S.error.message)}}),!S.success){g.push(`${h}: ${C(S.error.message)}`);continue}j(h,T,S.data,v,E)}const z=Date.now()-f;if(g.length>0){const o=p.length-g.length,w=p.length,h=g.length===w?`All ${w} ECS service rollouts failed: ${g.join("; ")}`:`Partial rollout: ${o}/${w} services succeeded. Failures: ${g.join("; ")}`;return{kind:"error",error:new Error(h)}}return l!==void 0&&await F(s,e.appName,E.map(o=>({serviceName:o.serviceName,imageTag:o.imageTag})),n,t.abortSignal),{kind:"completed",data:{target:e.appName,deploymentType:"application",outputs:Object.keys(v).length>0?v:void 0,artefacts:E,durationMs:z}}},t.abortSignal)}async function ge(t,s,e,i,n,d,f,c){const m=te(i,n);for(const r of m.unmatchedLiveServiceNames)d.onLog?.(`Service ${r} is not part of this release \u2014 leaving it untouched`,"warn");for(const r of m.staleMapKeys)d.onLog?.(`Service ${r} from the release no longer exists in the stack`,"warn");if(m.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 l=await re(t,e,m.matched,f);if(!l.success)return{kind:"error",error:l.error};const $={},k=[],u=[];for(let r=0;r<m.matched.length;r++){if(K(f))return{kind:"error",error:new Error(`Rollout cancelled after ${k.length}/${m.matched.length} services`)};const a=m.matched[r];if(!a)continue;const y=`[${r+1}/${m.matched.length}] ${a.serviceName}`,p=l.data.get(a.serviceArn);if(p===void 0){u.push(`${a.serviceName}: pre-flight digest missing after a successful pre-flight`);continue}A.debug(N,"Starting service rollout (serviceImageTags)",{serviceName:a.serviceName,serviceArn:a.serviceArn,imageTag:a.tag,mapKey:a.mapKey,index:r,total:m.matched.length}),d.onECSUpdate?.(`${y}: rolling out image tag ${a.tag}`,a.serviceName);const v=await _(t,e,a.serviceArn,a.serviceName,a.tag,d,void 0,p,f);if(A.debug(N,"Service rollout completed (serviceImageTags)",{serviceName:a.serviceName,success:v.success,...v.success?{taskDefinitionArn:v.data.taskDefinitionArn,imageDigest:v.data.imageDigest,durationMs:v.data.durationMs}:{error:C(v.error.message)}}),!v.success){u.push(`${a.serviceName}: ${C(v.error.message)}`);continue}j(a.serviceName,a.tag,v.data,$,k)}const D=Date.now()-c;if(u.length>0){const r=m.matched.length-u.length,a=m.matched.length,y=u.length===a?`All ${a} ECS service rollouts failed: ${u.join("; ")}`:`Partial rollout: ${r}/${a} services succeeded. Failures: ${u.join("; ")}`;return{kind:"error",error:new Error(y)}}return await F(t,s.appName,k.map(r=>({serviceName:r.serviceName,imageTag:r.imageTag})),d,f),{kind:"completed",data:{target:s.appName,deploymentType:"application",outputs:Object.keys($).length>0?$:void 0,artefacts:k,durationMs:D}}}async function _(t,s,e,i,n,d,f,c,m){const l=Date.now();let $,k,u,D,r;if(c!==void 0)$=c.taskDefinition.previousTaskDefArn,k=c.taskDefinition.taskDefinition,u=c.taskDefinition.containerDefinitions,D=c.taskDefinition.repoUri,r=c.imageDigest;else{const g=await ie(t,s,e,i);if(!g.success)return O(g.error);$=g.data.previousTaskDefArn,k=g.data.taskDefinition,u=g.data.containerDefinitions,D=g.data.repoUri;const b=await t.ecrImageInspector.getImageDigest(D,n,m);if(b.success)r=b.data;else{if(f!==void 0)return O(new Error(`Re-based image tag '${n}' (from supplied '${f}') was not found in ECR for ${i}: ${C(b.error.message)}. The supplied tag's build has no image for ${i} \u2014 supply that service's own tag, or pass --service to roll a single service.`));d.onLog?.(`Could not resolve image digest for ${i} (${C(b.error.message)}); falling back to tag pinning`,"warn")}}const a=g=>r!==void 0?`${g}@${r}`:`${g}:${n}`,y=u.map(g=>g.image?{...g,image:a(V(g.image))}:g),p=await B(t,{clusterArn:s,serviceArn:e,serviceName:i,taskDefinition:k,containerDefinitions:y,previousTaskDefArn:$,...r!==void 0?{imageDigest:r}:{},startedAtMs:l},d);if(!p.success)return O(p.error);const v=`${D}:${n}`,E=de(D);return H({taskDefinitionArn:p.data.newTaskDefArn,previousTaskDefinitionArn:$,imageUri:v,ecrRepositoryArn:E,imageDigest:r,durationMs:p.data.durationMs})}function de(t){const s=t.match(/^(\d{12})\.dkr\.ecr\.([a-z0-9-]+)\.amazonaws\.com\/(.+)$/);if(!s)return"";const[,e,i,n]=s;return`arn:aws:ecr:${i}:${e}:repository/${n}`}export{Se as deployCodeOnly,de as deriveEcrRepositoryArn,ne as lookupContentHashTag,oe as rebaseRollbackTagForService};