@fjall/util 39.0.0 → 39.0.2

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.
package/dist/.minified CHANGED
@@ -1 +1 @@
1
- 139 files minified at 2026-09-19T23:56:50.203Z
1
+ 140 files minified at 2026-09-26T12:07:43.740Z
@@ -9,6 +9,10 @@ export interface RootCause {
9
9
  }
10
10
  export interface FailureAnalysis {
11
11
  rootCause: RootCause;
12
+ /**
13
+ * Every failed event of the operation, oldest first. A resource that failed
14
+ * and then failed again in the rollback appears once per failure.
15
+ */
12
16
  affectedResources: ResourceEvent[];
13
17
  dependencyChain: string[];
14
18
  summary: string;
@@ -29,31 +33,20 @@ export interface FailureAnalysis {
29
33
  export declare class CloudFormationFailureAnalyser {
30
34
  private knownErrorPatterns;
31
35
  /**
32
- * `stackName` opts the drift scan into current-operation bounding: the
33
- * monitor's event history is seeded with the stack's FULL retained event
34
- * history (~90 days), so an unbounded scan would resurrect suspects from
35
- * long-past operations that were since cured. Callers whose history is
36
- * already operation-scoped (callback-fed collections) omit it.
36
+ * `stackName` bounds the analysis to the current operation: the events at
37
+ * or after the stack's latest operation-opening event. Callers whose history
38
+ * is already operation-scoped (callback-fed collections) omit it. When no
39
+ * opening event is visible, the drift scan yields nothing (fail-safe: a
40
+ * missed hint is recoverable via `fjall drift detect`, a stale suspect
41
+ * self-reinforces through the journal), but the root cause is still read
42
+ * from every failed event, because a failed deploy always needs a headline.
37
43
  */
38
44
  analyseFailure(eventHistory: Map<string, ResourceEvent[]>, stackName?: string): FailureAnalysis | null;
39
- /**
40
- * Scans EVERY failed event, not failedResources: a wedged resource's
41
- * UPDATE_FAILED is superseded by its rollback event, so latest-per-resource
42
- * semantics would drop exactly the wedge. When `stackName` is given, the
43
- * scan is bounded to events at/after the current operation's opening event;
44
- * if no opening event is visible the scan yields nothing rather than risk
45
- * classifying a stale prior-operation failure (fail-safe: a missed hint is
46
- * recoverable via `fjall drift detect`, a stale suspect self-reinforces
47
- * through the journal).
48
- */
49
- private classifyDriftSuspects;
50
- private findFailedResources;
51
- private findRootCause;
52
45
  private categoriseError;
53
46
  private isDirectCause;
54
47
  private buildDependencyChain;
55
48
  private generateRemediation;
56
49
  private generateSummary;
50
+ private failureVerb;
57
51
  private simplifyResourceType;
58
- private isFailedStatus;
59
52
  }
@@ -1 +1 @@
1
- var u=Object.defineProperty;var c=(o,e)=>u(o,"name",{value:e,configurable:!0});import{classifyDriftSuspectEvents as l,findCurrentOperationStart as f}from"./driftSuspects.js";class m{static{c(this,"CloudFormationFailureAnalyser")}knownErrorPatterns=[{pattern:/AccessDenied|UnauthorizedOperation|Forbidden/i,category:"permissions",remediation:["Check IAM permissions for the deployment role","Ensure the role has necessary CloudFormation permissions","Verify service-linked roles are created if needed"]},{pattern:/Invalid.*Parameter|ValidationError|Invalid.*Value/i,category:"validation",remediation:["Review parameter values in your CDK code","Check for typos in resource names or ARNs","Ensure all required parameters are provided"]},{pattern:/Limit.*Exceeded|Quota.*Exceeded|Maximum.*reached/i,category:"limit",remediation:["Check AWS service quotas in the Service Quotas console","Request a quota increase if needed","Consider using a different region with available capacity"]},{pattern:/Timeout|Connection.*refused|Network.*unreachable/i,category:"network",remediation:["Check network connectivity and VPC settings","Verify security groups and NACLs","Ensure endpoints are accessible"]},{pattern:/already exists|Duplicate|ConflictException/i,category:"validation",remediation:["Resource with this name already exists","Consider using a different name or deleting the existing resource","Check if you are deploying to the correct account/region"]},{pattern:/Role.*not.*found|Role.*does.*not.*exist/i,category:"dependency",remediation:["Ensure IAM roles are created before dependent resources","Check role names and ARNs are correct","Verify cross-stack references are properly configured"]}];analyseFailure(e,t){const r=this.findFailedResources(e);if(r.length===0)return null;const s=this.findRootCause(r,e),n=this.buildDependencyChain(s.resource,r),i=this.classifyDriftSuspects(e,t),a=this.generateRemediation(s);i.length>0&&a.unshift("One or more resources CloudFormation still tracks appear to have been deleted outside CloudFormation","Run 'fjall drift detect' to confirm the deletion; confirmed deletions are remediated with 'fjall drift repair'");const d=this.generateSummary(s,r);return{rootCause:s,affectedResources:r,dependencyChain:n,summary:d,remediation:a,errorPattern:s.category,...i.length>0?{driftSuspects:i}:{}}}classifyDriftSuspects(e,t){const r=t!==void 0?f(e.get(t)??[],t):null;if(t!==void 0&&r===null)return[];const s=[];for(const n of e.values())for(const i of n)this.isFailedStatus(i.status)&&(r!==null&&i.timestamp.getTime()<r.getTime()||s.push(i));return l(s)}findFailedResources(e){const t=[];for(const[r,s]of e){const n=s[s.length-1];n&&this.isFailedStatus(n.status)&&t.push(n)}return t.sort((r,s)=>r.timestamp.getTime()-s.timestamp.getTime())}findRootCause(e,t){if(e.length===0)return{resource:{logicalId:"Unknown",resourceType:"Unknown",status:"FAILED",timestamp:new Date},reason:"No failed resources found",category:"unknown",isDirectCause:!1};const r=e[0],s=this.categoriseError(r.statusReason||""),n=this.isDirectCause(r,t);return{resource:r,reason:r.statusReason||"Unknown error",category:s,isDirectCause:n}}categoriseError(e){for(const t of this.knownErrorPatterns)if(t.pattern.test(e))return t.category;return"unknown"}isDirectCause(e,t){const r=e.statusReason||"";return r.includes("depends on")||r.includes("referenced by")||r.includes("required by")?!1:!(t.get(e.logicalId)||[]).some(i=>i.status.includes("COMPLETE")&&!i.status.includes("ROLLBACK"))}buildDependencyChain(e,t){const r=[];r.push(`${e.logicalId} (${e.resourceType}) - ROOT CAUSE`);for(const s of t)s.logicalId!==e.logicalId&&((s.statusReason||"").toLowerCase().includes(e.logicalId.toLowerCase())?r.push(` \u2192 ${s.logicalId} (${s.resourceType}) - Failed due to ${e.logicalId}`):r.push(` \u2192 ${s.logicalId} (${s.resourceType})`));return r}generateRemediation(e){const t=[];for(const r of this.knownErrorPatterns)if(r.category===e.category){t.push(...r.remediation);break}return e.resource.resourceType.includes("IAM")?t.push("Review IAM policies and trust relationships"):e.resource.resourceType.includes("Lambda")?t.push("Check Lambda function configuration and runtime"):e.resource.resourceType.includes("ECS")&&t.push("Verify ECS task definition and container configuration"),t.length===0&&t.push("Review the CloudFormation console for detailed error messages","Check the resource configuration in your CDK code","Ensure all dependencies are properly defined"),t}generateSummary(e,t){const r=this.simplifyResourceType(e.resource.resourceType),s=t.length;let n=`Deployment failed: ${r} "${e.resource.logicalId}" `;switch(e.category){case"permissions":n+="failed due to insufficient permissions";break;case"validation":n+="failed validation";break;case"dependency":n+="has missing or invalid dependencies";break;case"limit":n+="exceeded AWS service limits";break;case"network":n+="encountered network issues";break;default:n+="failed to create"}return s>1&&(n+=` (${s-1} dependent resources also failed)`),n}simplifyResourceType(e){return e.replace("AWS::","").replace("::"," ")}isFailedStatus(e){return e.includes("FAILED")}}export{m as CloudFormationFailureAnalyser};
1
+ var f=Object.defineProperty;var d=(a,e)=>f(a,"name",{value:e,configurable:!0});import{classifyDriftSuspectEvents as p}from"./driftSuspects.js";import{findRootFailure as m,readOperationFailures as h}from"./operationFailures.js";class k{static{d(this,"CloudFormationFailureAnalyser")}knownErrorPatterns=[{pattern:/AccessDenied|UnauthorizedOperation|Forbidden/i,category:"permissions",remediation:["Check IAM permissions for the deployment role","Ensure the role has necessary CloudFormation permissions","Verify service-linked roles are created if needed"]},{pattern:/Invalid.*Parameter|ValidationError|Invalid.*Value/i,category:"validation",remediation:["Review parameter values in your CDK code","Check for typos in resource names or ARNs","Ensure all required parameters are provided"]},{pattern:/Limit.*Exceeded|Quota.*Exceeded|Maximum.*reached/i,category:"limit",remediation:["Check AWS service quotas in the Service Quotas console","Request a quota increase if needed","Consider using a different region with available capacity"]},{pattern:/Timeout|Connection.*refused|Network.*unreachable/i,category:"network",remediation:["Check network connectivity and VPC settings","Verify security groups and NACLs","Ensure endpoints are accessible"]},{pattern:/already exists|Duplicate|ConflictException/i,category:"validation",remediation:["Resource with this name already exists","Consider using a different name or deleting the existing resource","Check if you are deploying to the correct account/region"]},{pattern:/Role.*not.*found|Role.*does.*not.*exist/i,category:"dependency",remediation:["Ensure IAM roles are created before dependent resources","Check role names and ARNs are correct","Verify cross-stack references are properly configured"]}];analyseFailure(e,i){const{opening:t,failed:s}=h(e,i),r=m(s);if(r===void 0)return null;const n={resource:r,reason:r.statusReason||"Unknown error",category:this.categoriseError(r.statusReason||""),isDirectCause:this.isDirectCause(r,e)},l=this.buildDependencyChain(r,s),o=i!==void 0&&t===null?[]:p(s),c=this.generateRemediation(n);o.length>0&&c.unshift("One or more resources CloudFormation still tracks appear to have been deleted outside CloudFormation","Run 'fjall drift detect' to confirm the deletion; confirmed deletions are remediated with 'fjall drift repair'");const u=this.generateSummary(n,s);return{rootCause:n,affectedResources:s,dependencyChain:l,summary:u,remediation:c,errorPattern:n.category,...o.length>0?{driftSuspects:o}:{}}}categoriseError(e){for(const i of this.knownErrorPatterns)if(i.pattern.test(e))return i.category;return"unknown"}isDirectCause(e,i){const t=e.statusReason||"";return t.includes("depends on")||t.includes("referenced by")||t.includes("required by")?!1:!(i.get(e.logicalId)||[]).some(n=>n.timestamp.getTime()<e.timestamp.getTime()&&n.status.includes("COMPLETE")&&!n.status.includes("ROLLBACK"))}buildDependencyChain(e,i){const t=[];t.push(`${e.logicalId} (${e.resourceType}) - ROOT CAUSE`);const s=new Set([e.logicalId]);for(const r of i){if(s.has(r.logicalId))continue;s.add(r.logicalId),(r.statusReason||"").toLowerCase().includes(e.logicalId.toLowerCase())?t.push(` \u2192 ${r.logicalId} (${r.resourceType}) - Failed due to ${e.logicalId}`):t.push(` \u2192 ${r.logicalId} (${r.resourceType})`)}return t}generateRemediation(e){const i=[];for(const t of this.knownErrorPatterns)if(t.category===e.category){i.push(...t.remediation);break}return e.resource.resourceType.includes("IAM")?i.push("Review IAM policies and trust relationships"):e.resource.resourceType.includes("Lambda")?i.push("Check Lambda function configuration and runtime"):e.resource.resourceType.includes("ECS")&&i.push("Verify ECS task definition and container configuration"),i.length===0&&i.push("Review the CloudFormation console for detailed error messages","Check the resource configuration in your CDK code","Ensure all dependencies are properly defined"),i}generateSummary(e,i){const t=this.simplifyResourceType(e.resource.resourceType),s=new Set(i.map(n=>n.logicalId).filter(n=>n!==e.resource.logicalId)).size;let r=`Deployment failed: ${t} "${e.resource.logicalId}" `;switch(e.category){case"permissions":r+="failed due to insufficient permissions";break;case"validation":r+="failed validation";break;case"dependency":r+="has missing or invalid dependencies";break;case"limit":r+="exceeded AWS service limits";break;case"network":r+="encountered network issues";break;default:r+=this.failureVerb(e.resource.status)}return s>0&&(r+=` (${s} dependent resources also failed)`),r}failureVerb(e){switch(e){case"CREATE_FAILED":return"failed to create";case"UPDATE_FAILED":return"failed to update";case"DELETE_FAILED":return"failed to delete";default:return"failed"}}simplifyResourceType(e){return e.replace("AWS::","").replace("::"," ")}}export{k as CloudFormationFailureAnalyser};
@@ -29,6 +29,8 @@ export interface DriftSuspectEvent {
29
29
  failedStatus: string;
30
30
  statusReason: string;
31
31
  }
32
+ /** True when CloudFormation cancelled the resource because a sibling failed. */
33
+ export declare function isCancelledCollateral(statusReason: string): boolean;
32
34
  /** True when a failure reason carries the out-of-band-deletion shape. */
33
35
  export declare function isDriftSuspectReason(statusReason: string): boolean;
34
36
  /**
@@ -1 +1 @@
1
- var i=Object.defineProperty;var o=(e,s)=>i(e,"name",{value:s,configurable:!0});const c=new Set(["UPDATE_FAILED","DELETE_FAILED"]),u=[/HandlerErrorCode:\s*NotFound\b/,/does not exist \(Service:/i,/\b(?:ResourceNotFoundException|NotFoundException|NoSuchBucket|NoSuchEntity)\b/],a=/Resource (?:creation|update) cancelled/i;function r(e){return a.test(e)?!1:u.some(s=>s.test(e))}o(r,"isDriftSuspectReason");const E="AWS::CloudFormation::Stack",S=new Set(["CREATE_IN_PROGRESS","UPDATE_IN_PROGRESS","DELETE_IN_PROGRESS","IMPORT_IN_PROGRESS"]),d="User Initiated";function R(e,s){return e.resourceType===E&&e.logicalId===s&&S.has(e.status)&&e.statusReason!==void 0&&e.statusReason.includes(d)}o(R,"isOperationOpeningEvent");function l(e,s){let n=null;for(const t of e)R(t,s)&&(n===null||t.timestamp.getTime()>n.getTime())&&(n=t.timestamp);return n}o(l,"findCurrentOperationStart");function f(e){const s=[],n=new Set;for(const t of e)n.has(t.logicalId)||c.has(t.status)&&(t.statusReason===void 0||t.statusReason===""||r(t.statusReason)&&(n.add(t.logicalId),s.push({logicalId:t.logicalId,resourceType:t.resourceType,...t.physicalId!==void 0&&t.physicalId!==""?{physicalId:t.physicalId}:{},failedStatus:t.status,statusReason:t.statusReason})));return s}o(f,"classifyDriftSuspectEvents");export{f as classifyDriftSuspectEvents,l as findCurrentOperationStart,r as isDriftSuspectReason,R as isOperationOpeningEvent};
1
+ var i=Object.defineProperty;var o=(e,n)=>i(e,"name",{value:n,configurable:!0});const c=new Set(["UPDATE_FAILED","DELETE_FAILED"]),a=[/HandlerErrorCode:\s*NotFound\b/,/does not exist \(Service:/i,/\b(?:ResourceNotFoundException|NotFoundException|NoSuchBucket|NoSuchEntity)\b/],u=/Resource (?:creation|update) cancelled/i;function r(e){return u.test(e)}o(r,"isCancelledCollateral");function E(e){return r(e)?!1:a.some(n=>n.test(e))}o(E,"isDriftSuspectReason");const l="AWS::CloudFormation::Stack",S=new Set(["CREATE_IN_PROGRESS","UPDATE_IN_PROGRESS","DELETE_IN_PROGRESS","IMPORT_IN_PROGRESS"]),d="User Initiated";function R(e,n){return e.resourceType===l&&e.logicalId===n&&S.has(e.status)&&e.statusReason!==void 0&&e.statusReason.includes(d)}o(R,"isOperationOpeningEvent");function f(e,n){let s=null;for(const t of e)R(t,n)&&(s===null||t.timestamp.getTime()>s.getTime())&&(s=t.timestamp);return s}o(f,"findCurrentOperationStart");function p(e){const n=[],s=new Set;for(const t of e)s.has(t.logicalId)||c.has(t.status)&&(t.statusReason===void 0||t.statusReason===""||E(t.statusReason)&&(s.add(t.logicalId),n.push({logicalId:t.logicalId,resourceType:t.resourceType,...t.physicalId!==void 0&&t.physicalId!==""?{physicalId:t.physicalId}:{},failedStatus:t.status,statusReason:t.statusReason})));return n}o(p,"classifyDriftSuspectEvents");export{p as classifyDriftSuspectEvents,f as findCurrentOperationStart,r as isCancelledCollateral,E as isDriftSuspectReason,R as isOperationOpeningEvent};
@@ -5,6 +5,7 @@ export { type ResourceProgressCounts, countResourceProgress, formatElapsed } fro
5
5
  export { CloudFormationFailureAnalyser, type RootCause, type FailureAnalysis } from "./CloudFormationFailureAnalyser.js";
6
6
  export { FAILURE_ANALYSIS_CATEGORIES, type FailureAnalysisCategory } from "./failureAnalysisCategories.js";
7
7
  export { maskFailureAnalysis } from "./maskFailureAnalysis.js";
8
+ export { findRootFailure, isFailedResourceStatus, readOperationFailures, type OperationFailures } from "./operationFailures.js";
8
9
  export { classifyDriftSuspectEvents, findCurrentOperationStart, isDriftSuspectReason, isOperationOpeningEvent, type DriftSuspectEvent } from "./driftSuspects.js";
9
10
  export { IPAM_OPERATIONS_POOL_TAG_KEY, formatIpamPairTagValue } from "./ipamTags.js";
10
11
  export { FJALL_RESOURCE_TYPE_TAG_KEY, FJALL_RESOURCE_TYPES, type FjallResourceType, KMS_ALIAS_TAG_KEY, KMS_RETENTION_TAG_KEY, S3_BACKUP_EXEMPT_TAG_KEY, S3_BACKUP_EXEMPTIONS, S3_VERSIONING_EXEMPT_TAG_KEY, S3_VERSIONING_EXEMPTIONS, SDK_PRE_EMPTY_TAG_KEY, type S3BackupExemption, type S3VersioningExemption } from "./infraTags.js";
package/dist/aws/index.js CHANGED
@@ -1 +1 @@
1
- import{AWSError as E,NoRolesFoundError as _,InvalidCredentialsError as e,SSOTokenExpiredError as T,MissingRegionError as A,ProfileNotFoundError as S,CommandError as O,isAWSError as t,isNoRolesFoundError as s,isSSOUnauthorizedError as i}from"./errors.js";import{STACK_NOT_FOUND_PATTERN as a,CDK_NO_STACKS_MATCH as n,isResourceEvent as R}from"./cloudformationTypes.js";import{AWS_RESOURCE_TYPES as C,isAwsResourceType as I}from"./resourceTypes.js";import{countResourceProgress as m,formatElapsed as P}from"./deployProgress.js";import{CloudFormationFailureAnalyser as u}from"./CloudFormationFailureAnalyser.js";import{FAILURE_ANALYSIS_CATEGORIES as M}from"./failureAnalysisCategories.js";import{maskFailureAnalysis as x}from"./maskFailureAnalysis.js";import{classifyDriftSuspectEvents as F,findCurrentOperationStart as G,isDriftSuspectReason as Y,isOperationOpeningEvent as U}from"./driftSuspects.js";import{IPAM_OPERATIONS_POOL_TAG_KEY as g,formatIpamPairTagValue as D}from"./ipamTags.js";import{FJALL_RESOURCE_TYPE_TAG_KEY as v,FJALL_RESOURCE_TYPES as V,KMS_ALIAS_TAG_KEY as W,KMS_RETENTION_TAG_KEY as X,S3_BACKUP_EXEMPT_TAG_KEY as h,S3_BACKUP_EXEMPTIONS as k,S3_VERSIONING_EXEMPT_TAG_KEY as B,S3_VERSIONING_EXEMPTIONS as J,SDK_PRE_EMPTY_TAG_KEY as w}from"./infraTags.js";import{COST_ALLOCATION_TAGS as H,DEFAULT_COST_ALLOCATION_ENVIRONMENT as b,DEFAULT_COST_ALLOCATION_OWNER as j,ecrCreateRepositoryTags as q,rdsPreMigrationSnapshotTags as Q}from"./costAllocationTags.js";import{ACCOUNT_MONITORING_ROLE_NAME as $}from"./monitoringRole.js";export{$ as ACCOUNT_MONITORING_ROLE_NAME,E as AWSError,C as AWS_RESOURCE_TYPES,n as CDK_NO_STACKS_MATCH,H as COST_ALLOCATION_TAGS,u as CloudFormationFailureAnalyser,O as CommandError,b as DEFAULT_COST_ALLOCATION_ENVIRONMENT,j as DEFAULT_COST_ALLOCATION_OWNER,M as FAILURE_ANALYSIS_CATEGORIES,V as FJALL_RESOURCE_TYPES,v as FJALL_RESOURCE_TYPE_TAG_KEY,g as IPAM_OPERATIONS_POOL_TAG_KEY,e as InvalidCredentialsError,W as KMS_ALIAS_TAG_KEY,X as KMS_RETENTION_TAG_KEY,A as MissingRegionError,_ as NoRolesFoundError,S as ProfileNotFoundError,k as S3_BACKUP_EXEMPTIONS,h as S3_BACKUP_EXEMPT_TAG_KEY,J as S3_VERSIONING_EXEMPTIONS,B as S3_VERSIONING_EXEMPT_TAG_KEY,w as SDK_PRE_EMPTY_TAG_KEY,T as SSOTokenExpiredError,a as STACK_NOT_FOUND_PATTERN,F as classifyDriftSuspectEvents,m as countResourceProgress,q as ecrCreateRepositoryTags,G as findCurrentOperationStart,P as formatElapsed,D as formatIpamPairTagValue,t as isAWSError,I as isAwsResourceType,Y as isDriftSuspectReason,s as isNoRolesFoundError,U as isOperationOpeningEvent,R as isResourceEvent,i as isSSOUnauthorizedError,x as maskFailureAnalysis,Q as rdsPreMigrationSnapshotTags};
1
+ import{AWSError as e,NoRolesFoundError as E,InvalidCredentialsError as _,SSOTokenExpiredError as T,MissingRegionError as t,ProfileNotFoundError as A,CommandError as S,isAWSError as s,isNoRolesFoundError as O,isSSOUnauthorizedError as i}from"./errors.js";import{STACK_NOT_FOUND_PATTERN as n,CDK_NO_STACKS_MATCH as N,isResourceEvent as R}from"./cloudformationTypes.js";import{AWS_RESOURCE_TYPES as C,isAwsResourceType as f}from"./resourceTypes.js";import{countResourceProgress as m,formatElapsed as u}from"./deployProgress.js";import{CloudFormationFailureAnalyser as L}from"./CloudFormationFailureAnalyser.js";import{FAILURE_ANALYSIS_CATEGORIES as d}from"./failureAnalysisCategories.js";import{maskFailureAnalysis as K}from"./maskFailureAnalysis.js";import{findRootFailure as M,isFailedResourceStatus as G,readOperationFailures as Y}from"./operationFailures.js";import{classifyDriftSuspectEvents as c,findCurrentOperationStart as g,isDriftSuspectReason as D,isOperationOpeningEvent as y}from"./driftSuspects.js";import{IPAM_OPERATIONS_POOL_TAG_KEY as V,formatIpamPairTagValue as W}from"./ipamTags.js";import{FJALL_RESOURCE_TYPE_TAG_KEY as h,FJALL_RESOURCE_TYPES as k,KMS_ALIAS_TAG_KEY as B,KMS_RETENTION_TAG_KEY as J,S3_BACKUP_EXEMPT_TAG_KEY as w,S3_BACKUP_EXEMPTIONS as z,S3_VERSIONING_EXEMPT_TAG_KEY as H,S3_VERSIONING_EXEMPTIONS as b,SDK_PRE_EMPTY_TAG_KEY as j}from"./infraTags.js";import{COST_ALLOCATION_TAGS as Q,DEFAULT_COST_ALLOCATION_ENVIRONMENT as Z,DEFAULT_COST_ALLOCATION_OWNER as $,ecrCreateRepositoryTags as rr,rdsPreMigrationSnapshotTags as or}from"./costAllocationTags.js";import{ACCOUNT_MONITORING_ROLE_NAME as Er}from"./monitoringRole.js";export{Er as ACCOUNT_MONITORING_ROLE_NAME,e as AWSError,C as AWS_RESOURCE_TYPES,N as CDK_NO_STACKS_MATCH,Q as COST_ALLOCATION_TAGS,L as CloudFormationFailureAnalyser,S as CommandError,Z as DEFAULT_COST_ALLOCATION_ENVIRONMENT,$ as DEFAULT_COST_ALLOCATION_OWNER,d as FAILURE_ANALYSIS_CATEGORIES,k as FJALL_RESOURCE_TYPES,h as FJALL_RESOURCE_TYPE_TAG_KEY,V as IPAM_OPERATIONS_POOL_TAG_KEY,_ as InvalidCredentialsError,B as KMS_ALIAS_TAG_KEY,J as KMS_RETENTION_TAG_KEY,t as MissingRegionError,E as NoRolesFoundError,A as ProfileNotFoundError,z as S3_BACKUP_EXEMPTIONS,w as S3_BACKUP_EXEMPT_TAG_KEY,b as S3_VERSIONING_EXEMPTIONS,H as S3_VERSIONING_EXEMPT_TAG_KEY,j as SDK_PRE_EMPTY_TAG_KEY,T as SSOTokenExpiredError,n as STACK_NOT_FOUND_PATTERN,c as classifyDriftSuspectEvents,m as countResourceProgress,rr as ecrCreateRepositoryTags,g as findCurrentOperationStart,M as findRootFailure,u as formatElapsed,W as formatIpamPairTagValue,s as isAWSError,f as isAwsResourceType,D as isDriftSuspectReason,G as isFailedResourceStatus,O as isNoRolesFoundError,y as isOperationOpeningEvent,R as isResourceEvent,i as isSSOUnauthorizedError,K as maskFailureAnalysis,or as rdsPreMigrationSnapshotTags,Y as readOperationFailures};
@@ -0,0 +1,34 @@
1
+ import type { ResourceEvent } from "./cloudformationTypes.js";
2
+ /** True for every CloudFormation status that reports a failure. */
3
+ export declare function isFailedResourceStatus(status: string): boolean;
4
+ export interface OperationFailures {
5
+ /**
6
+ * When the current operation opened, or null when its opening event is not
7
+ * in the history (or no stack name was given).
8
+ */
9
+ opening: Date | null;
10
+ /** Every failed event at or after `opening`, oldest first. */
11
+ failed: ResourceEvent[];
12
+ }
13
+ /**
14
+ * The failed events of the stack's current operation. Every event is read,
15
+ * not each resource's latest: a resource that failed and was then rolled back
16
+ * ends on a COMPLETE event, so latest-event reading drops exactly the failure
17
+ * that started the rollback and keeps the rollback's own failures
18
+ * (fjall-deploy-tests #94). The sort is stable and orders by event time, so
19
+ * the result does not depend on the order the events were recorded in.
20
+ *
21
+ * `stackName` bounds the read to the events at or after the stack's latest
22
+ * operation-opening event. Without it, or when no opening event is visible,
23
+ * every failed event in the history is returned.
24
+ */
25
+ export declare function readOperationFailures(eventHistory: ReadonlyMap<string, readonly ResourceEvent[]>, stackName?: string): OperationFailures;
26
+ /**
27
+ * The failure that failed the operation, from its failed events oldest first.
28
+ * A rollback only starts after a failure, so its own failures (a
29
+ * DELETE_FAILED on the way back) come later, and a resource CloudFormation
30
+ * cancelled because a sibling failed says nothing about itself. So it is the
31
+ * earliest failure that is not cancellation collateral, or the earliest
32
+ * failure when every one of them is.
33
+ */
34
+ export declare function findRootFailure(failed: readonly ResourceEvent[]): ResourceEvent | undefined;
@@ -0,0 +1 @@
1
+ var s=Object.defineProperty;var i=(t,e)=>s(t,"name",{value:e,configurable:!0});import{findCurrentOperationStart as a,isCancelledCollateral as f}from"./driftSuspects.js";function l(t){return t.includes("FAILED")}i(l,"isFailedResourceStatus");function m(t,e){const o=e!==void 0?a(t.get(e)??[],e):null,r=[];for(const u of t.values())for(const n of u)l(n.status)&&(o!==null&&n.timestamp.getTime()<o.getTime()||r.push(n));return r.sort((u,n)=>u.timestamp.getTime()-n.timestamp.getTime()),{opening:o,failed:r}}i(m,"readOperationFailures");function d(t){return t.find(e=>!f(e.statusReason??""))??t[0]}i(d,"findRootFailure");export{d as findRootFailure,l as isFailedResourceStatus,m as readOperationFailures};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fjall/util",
3
- "version": "39.0.0",
3
+ "version": "39.0.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/fjall-tech/fjall.git",