| | | 1 | | /** |
| | | 2 | | * Base class for all domain-specific errors in the application. |
| | | 3 | | */ |
| | | 4 | | export class DomainError extends Error { |
| | | 5 | | constructor(message: string) { |
| | 201 | 6 | | super(message); |
| | 201 | 7 | | this.name = this.constructor.name; |
| | 201 | 8 | | Error.captureStackTrace(this, this.constructor); |
| | | 9 | | } |
| | | 10 | | } |
| | | 11 | | |
| | | 12 | | /** |
| | | 13 | | * Error thrown when required arguments are missing or invalid. |
| | | 14 | | */ |
| | | 15 | | export class InvalidArgumentError extends DomainError {} |
| | | 16 | | |
| | | 17 | | /** |
| | | 18 | | * Error thrown when a required dependency is missing. |
| | | 19 | | */ |
| | | 20 | | export class DependencyMissingError extends DomainError {} |
| | | 21 | | |
| | | 22 | | /** |
| | | 23 | | * Error thrown when a secret operation fails. |
| | | 24 | | */ |
| | | 25 | | export class SecretOperationError extends DomainError {} |
| | | 26 | | |
| | | 27 | | /** |
| | | 28 | | * Error thrown when an environment file operation fails. |
| | | 29 | | */ |
| | | 30 | | export class EnvironmentFileError extends DomainError {} |
| | | 31 | | |
| | | 32 | | /** |
| | | 33 | | * Error thrown when a parameter cannot be found. |
| | | 34 | | */ |
| | | 35 | | export class ParameterNotFoundError extends DomainError { |
| | | 36 | | constructor(paramName: string) { |
| | 0 | 37 | | super(`Parameter not found: ${paramName}`); |
| | 0 | 38 | | this.paramName = paramName; |
| | | 39 | | } |
| | | 40 | | |
| | | 41 | | readonly paramName: string; |
| | | 42 | | } |
| | | 43 | | |
| | | 44 | | /** |
| | | 45 | | * Error thrown when AWS credentials or the security token are expired or invalid. |
| | | 46 | | */ |
| | | 47 | | export class ExpiredCredentialsError extends DomainError { |
| | | 48 | | readonly cause?: unknown; |
| | | 49 | | |
| | | 50 | | constructor(cause?: unknown) { |
| | 8 | 51 | | super( |
| | | 52 | | 'AWS credentials are expired or invalid. Your security token or SSO ' + |
| | | 53 | | 'session may have expired. Refresh your credentials and retry ' + |
| | | 54 | | '(for SSO, run: aws sso login).', |
| | | 55 | | ); |
| | 8 | 56 | | this.cause = cause; |
| | | 57 | | } |
| | | 58 | | } |
| | | 59 | | |
| | | 60 | | /** |
| | | 61 | | * Error thrown when the AWS SSO session could not be resolved or loaded. |
| | | 62 | | */ |
| | | 63 | | export class SsoSessionExpiredError extends DomainError { |
| | | 64 | | readonly profileName?: string; |
| | | 65 | | readonly cause?: unknown; |
| | | 66 | | |
| | | 67 | | constructor(profileName?: string, cause?: unknown) { |
| | 35 | 68 | | super(SsoSessionExpiredError.buildMessage(profileName)); |
| | 35 | 69 | | this.profileName = profileName; |
| | 35 | 70 | | this.cause = cause; |
| | | 71 | | } |
| | | 72 | | |
| | | 73 | | private static buildMessage(profileName?: string): string { |
| | 35 | 74 | | if (profileName) { |
| | 32 | 75 | | return ( |
| | | 76 | | `Your AWS SSO session for profile '${profileName}' could not be ` + |
| | | 77 | | `loaded or has expired. Run: aws sso login --profile ${profileName} ` + |
| | | 78 | | 'and then re-run this command.' |
| | | 79 | | ); |
| | | 80 | | } |
| | 3 | 81 | | return ( |
| | | 82 | | 'Your AWS SSO session could not be loaded or has expired. Run: ' + |
| | | 83 | | 'aws sso login and then re-run this command.' |
| | | 84 | | ); |
| | | 85 | | } |
| | | 86 | | } |
| | | 87 | | |
| | | 88 | | /** |
| | | 89 | | * Describes a single secret that could not be resolved during a pull operation. |
| | | 90 | | */ |
| | | 91 | | export type SecretFetchFailure = { |
| | | 92 | | envVar: string; |
| | | 93 | | path: string; |
| | | 94 | | reason: string; |
| | | 95 | | }; |
| | | 96 | | |
| | | 97 | | /** |
| | | 98 | | * Error thrown when one or more secrets could not be fetched during a pull. |
| | | 99 | | */ |
| | | 100 | | export class SecretsFetchError extends DomainError { |
| | 18 | 101 | | constructor(readonly failures: ReadonlyArray<SecretFetchFailure>) { |
| | 18 | 102 | | super('Some secrets could not be fetched'); |
| | | 103 | | } |
| | | 104 | | } |
| | | 105 | | |
| | | 106 | | /** |
| | | 107 | | * Error thrown when the command passed to exec mode cannot be found. |
| | | 108 | | */ |
| | | 109 | | export class CommandNotFoundError extends DomainError { |
| | 3 | 110 | | constructor(readonly command: string) { |
| | 3 | 111 | | super(`Command not found: ${command}`); |
| | | 112 | | } |
| | | 113 | | } |
| | | 114 | | |
| | | 115 | | /** |
| | | 116 | | * Error thrown when the command passed to exec mode exists but cannot be |
| | | 117 | | * executed (for example, a script without the executable bit). |
| | | 118 | | */ |
| | | 119 | | export class CommandNotExecutableError extends DomainError { |
| | | 120 | | /** |
| | | 121 | | * @param reason - Why the command cannot be executed. Without it the |
| | | 122 | | * message is `Permission denied: <command>`. |
| | | 123 | | */ |
| | | 124 | | constructor( |
| | 12 | 125 | | readonly command: string, |
| | | 126 | | reason?: string, |
| | | 127 | | ) { |
| | 12 | 128 | | super( |
| | | 129 | | reason === undefined |
| | | 130 | | ? `Permission denied: ${command}` |
| | | 131 | | : `Cannot execute ${command}: ${reason}`, |
| | | 132 | | ); |
| | | 133 | | } |
| | | 134 | | } |
| | | 135 | | |
| | | 136 | | /** |
| | | 137 | | * Error thrown when Envilder could not start the command for a reason that is |
| | | 138 | | * not about the command itself, for example exhausted system resources. The |
| | | 139 | | * message names the command, never its arguments. |
| | | 140 | | */ |
| | | 141 | | export class CommandStartError extends DomainError { |
| | | 142 | | constructor( |
| | 5 | 143 | | readonly command: string, |
| | | 144 | | reason: string, |
| | | 145 | | ) { |
| | 5 | 146 | | super(`Cannot start ${command}: ${reason}`); |
| | | 147 | | } |
| | | 148 | | } |
| | | 149 | | |
| | | 150 | | /** |
| | | 151 | | * Error thrown when the child environment exceeds the operating system limit. |
| | | 152 | | */ |
| | | 153 | | export class EnvironmentTooLargeError extends DomainError { |
| | | 154 | | constructor() { |
| | 2 | 155 | | super('Environment too large to start the command (E2BIG).'); |
| | | 156 | | } |
| | | 157 | | } |
| | | 158 | | |
| | | 159 | | /** |
| | | 160 | | * Error thrown when exec mode fails after it started supervising the child |
| | | 161 | | * (from the mask flush onward). It is deliberately not an SSO or |
| | | 162 | | * credentials error, so recovery never retries the run and the child is |
| | | 163 | | * never started twice. The message only carries the cause's message. |
| | | 164 | | */ |
| | | 165 | | export class ExecInterruptedError extends DomainError { |
| | | 166 | | readonly cause: unknown; |
| | | 167 | | |
| | | 168 | | constructor(cause: unknown) { |
| | | 169 | | const reason = |
| | 4 | 170 | | cause instanceof Error && cause.message ? cause.message : String(cause); |
| | 4 | 171 | | super(`The command could not be supervised after it started: ${reason}`); |
| | 4 | 172 | | this.cause = cause; |
| | | 173 | | } |
| | | 174 | | } |