diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 9b87796cd..ec9429439 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -118,6 +118,7 @@ "@types/ejs": "^3.1.5", "@types/jest": "^29.5.8", "@types/js-yaml": "^4.0.9", + "@types/node": "^18.19.5", "@types/node-fetch": "^2.6.9", "@types/proxy-from-env": "^1.0.4", "@types/semver": "^7.5.5", @@ -3851,9 +3852,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.16.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.16.tgz", - "integrity": "sha512-NpaM49IGQQAUlBhHMF82QH80J08os4ZmyF9MkpCzWAGuOHqE4gTEbhzd7L3l5LmWuZ6E0OiC1FweQ4tsiW35+g==" + "version": "18.19.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.5.tgz", + "integrity": "sha512-22MG6T02Hos2JWfa1o5jsIByn+bc5iOt1IS4xyg6OG68Bu+wMonVZzdrgCw693++rpLE9RUT/Bx15BeDzO0j+g==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/node-fetch": { "version": "2.6.9", @@ -12773,6 +12777,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -16361,9 +16370,12 @@ "dev": true }, "@types/node": { - "version": "18.16.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.16.tgz", - "integrity": "sha512-NpaM49IGQQAUlBhHMF82QH80J08os4ZmyF9MkpCzWAGuOHqE4gTEbhzd7L3l5LmWuZ6E0OiC1FweQ4tsiW35+g==" + "version": "18.19.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.5.tgz", + "integrity": "sha512-22MG6T02Hos2JWfa1o5jsIByn+bc5iOt1IS4xyg6OG68Bu+wMonVZzdrgCw693++rpLE9RUT/Bx15BeDzO0j+g==", + "requires": { + "undici-types": "~5.26.4" + } }, "@types/node-fetch": { "version": "2.6.9", @@ -22840,6 +22852,11 @@ "which-boxed-primitive": "^1.0.2" } }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/package.json b/package.json index 0fb6f2667..8cca3daf8 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "@types/ejs": "^3.1.5", "@types/jest": "^29.5.8", "@types/js-yaml": "^4.0.9", + "@types/node": "^18.19.5", "@types/node-fetch": "^2.6.9", "@types/proxy-from-env": "^1.0.4", "@types/semver": "^7.5.5", diff --git a/src/lib/cli/command.js b/src/lib/cli/command.js index 861bf04da..741f10beb 100644 --- a/src/lib/cli/command.js +++ b/src/lib/cli/command.js @@ -20,7 +20,7 @@ function uncaughtError( err ) { return; } if ( err instanceof UserError ) { - exit.withError( err.message ); + exit.withError( err ); } console.log( chalk.red( '✕' ), 'Please contact VIP Support with the following information:' ); diff --git a/src/lib/cli/exit.ts b/src/lib/cli/exit.ts index 3b16b18b0..994ab1fef 100644 --- a/src/lib/cli/exit.ts +++ b/src/lib/cli/exit.ts @@ -1,9 +1,11 @@ import { red, yellow } from 'chalk'; +import debug from 'debug'; import env from '../../lib/env'; export function withError( message: Error | string ): never { - console.error( `${ red( 'Error: ' ) } ${ message.toString().replace( /^Error:\s*/, '' ) }` ); + const msg = message instanceof Error ? message.message : message; + console.error( `${ red( 'Error: ' ) } ${ msg.replace( /^Error:\s*/, '' ) }` ); // Debug ouput is printed below error output both for information // hierarchy and to make it more likely that the user copies it to their @@ -11,8 +13,12 @@ export function withError( message: Error | string ): never { console.log( `${ yellow( 'Debug: ' ) } VIP-CLI v${ env.app.version }, Node ${ env.node.version }, ${ env.os.name - } ${ env.os.version }` + } ${ env.os.version } ${ env.os.arch }` ); + if ( debug.names.length > 0 && message instanceof Error ) { + console.error( yellow( 'Debug: ' ), message ); + } + process.exit( 1 ); } diff --git a/src/lib/cli/progress.ts b/src/lib/cli/progress.ts index 9456938f6..b62db0009 100644 --- a/src/lib/cli/progress.ts +++ b/src/lib/cli/progress.ts @@ -33,7 +33,7 @@ export interface StepFromServer { export class ProgressTracker { hasFailure: boolean; hasPrinted: boolean; - printInterval: NodeJS.Timer | undefined; + printInterval: NodeJS.Timeout | undefined; // Track the state of each step stepsFromCaller: Map< string, Step >; diff --git a/src/lib/client-file-uploader.ts b/src/lib/client-file-uploader.ts index b95be05f9..33ffbe795 100644 --- a/src/lib/client-file-uploader.ts +++ b/src/lib/client-file-uploader.ts @@ -90,7 +90,9 @@ export const getFileHash = async ( await pipeline( src, dst ); return dst.digest().toString( 'hex' ); } catch ( err ) { - throw new Error( `could not generate file hash: ${ ( err as Error ).message }` ); + throw new Error( `Could not generate file hash: ${ ( err as Error ).message }`, { + cause: err, + } ); } finally { src.close(); } @@ -104,7 +106,7 @@ const gzipFile = async ( uncompressedFileName: string, compressedFileName: strin createWriteStream( compressedFileName ) ); } catch ( err ) { - throw new Error( `could not compress file: ${ ( err as Error ).message }` ); + throw new Error( `Could not compress file: ${ ( err as Error ).message }`, { cause: err } ); } }; @@ -173,7 +175,8 @@ export async function uploadImportSqlFileToS3( { tmpDir = await getWorkingTempDir(); } catch ( err ) { throw new Error( - `Unable to create temporary working directory: ${ ( err as Error ).message }` + `Unable to create temporary working directory: ${ ( err as Error ).message }`, + { cause: err } ); } @@ -305,7 +308,9 @@ async function uploadUsingPutObject( { try { parsedResponse = ( await parser.parseStringPromise( result ) ) as UploadErrorResponse; } catch ( err ) { - throw new Error( `Invalid response from cloud service. ${ ( err as Error ).message }` ); + throw new Error( `Invalid response from cloud service. ${ ( err as Error ).message }`, { + cause: err, + } ); } const { Code, Message } = parsedResponse.Error; diff --git a/src/lib/dev-environment/dev-environment-cli.ts b/src/lib/dev-environment/dev-environment-cli.ts index f456a91dc..b50fbf540 100644 --- a/src/lib/dev-environment/dev-environment-cli.ts +++ b/src/lib/dev-environment/dev-environment-cli.ts @@ -129,7 +129,9 @@ const verifyDNSResolution = async ( slug: string ): Promise< void > => { address = await lookup( testDomain, 4 ); debug( `Got DNS response ${ address.address }` ); } catch ( error ) { - throw new UserError( `DNS resolution for ${ testDomain } failed. ${ advice }` ); + throw new UserError( `DNS resolution for ${ testDomain } failed. ${ advice }`, { + cause: error, + } ); } if ( address.address !== expectedIP ) { diff --git a/src/lib/dev-environment/dev-environment-core.ts b/src/lib/dev-environment/dev-environment-core.ts index 40ba7cdb0..181288fe1 100644 --- a/src/lib/dev-environment/dev-environment-core.ts +++ b/src/lib/dev-environment/dev-environment-core.ts @@ -408,7 +408,8 @@ export function readEnvironmentData( slug: string ): InstanceData { } catch ( error: unknown ) { const err = error as Error; throw new UserError( - `There was an error reading file "${ instanceDataTargetPath }": ${ err.message }.` + `There was an error reading file "${ instanceDataTargetPath }": ${ err.message }.`, + { cause: error } ); } @@ -417,7 +418,8 @@ export function readEnvironmentData( slug: string ): InstanceData { } catch ( error: unknown ) { const err = error as Error; throw new UserError( - `There was an error parsing file "${ instanceDataTargetPath }": ${ err.message }. You may need to recreate the environment.` + `There was an error parsing file "${ instanceDataTargetPath }": ${ err.message }. You may need to recreate the environment.`, + { cause: error } ); } diff --git a/src/lib/env.ts b/src/lib/env.ts index 8967831f6..6c9261947 100644 --- a/src/lib/env.ts +++ b/src/lib/env.ts @@ -1,4 +1,4 @@ -import { platform, release } from 'node:os'; +import { arch, platform, release } from 'node:os'; import pkg from '../../package.json'; @@ -10,6 +10,7 @@ interface AppInfo { interface OSInfo { name: string; version: string; + arch: string; } interface NodeInfo { @@ -31,6 +32,7 @@ const app: AppInfo = { const os: OSInfo = { name: platform(), version: release(), + arch: arch(), }; const node: NodeInfo = { diff --git a/src/lib/media-import/progress.ts b/src/lib/media-import/progress.ts index 7ccad03b8..e8739a9dd 100644 --- a/src/lib/media-import/progress.ts +++ b/src/lib/media-import/progress.ts @@ -14,7 +14,7 @@ type MediaImportStatus = Pick< export class MediaImportProgressTracker { hasFailure: boolean; hasPrinted: boolean; - printInterval: NodeJS.Timer | undefined; + printInterval: NodeJS.Timeout | undefined; status: MediaImportStatus; // Spinnerz go brrrr diff --git a/src/lib/user-error.ts b/src/lib/user-error.ts index edec36b9c..1b161b543 100644 --- a/src/lib/user-error.ts +++ b/src/lib/user-error.ts @@ -1,6 +1,6 @@ export default class UserError extends Error { - constructor( message: string ) { - super( message ); + constructor( message: string, options?: ErrorOptions ) { + super( message, options ); this.name = 'UserError'; } } diff --git a/src/lib/validations/line-by-line.ts b/src/lib/validations/line-by-line.ts index 430fb620d..e5b298e9c 100644 --- a/src/lib/validations/line-by-line.ts +++ b/src/lib/validations/line-by-line.ts @@ -55,7 +55,7 @@ export async function fileLineValidations( } ); readInterface.on( 'error', ( err: Error ) => { - throw new Error( ` Error validating input file: ${ err.toString() }` ); + throw new Error( `Error validating input file: ${ err.toString() }`, { cause: err } ); } ); // Block until the processing completes diff --git a/tsconfig.json b/tsconfig.json index 614d143bd..f4f617301 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "lib": [ "es2021" ], + "lib": [ "ES2022" ], "module": "node16", "strict": true, "esModuleInterop": true, @@ -9,7 +9,7 @@ "moduleResolution": "node16", // Target latest version of ECMAScript. - "target": "esnext", + "target": "ES2022", // Don't parse types from JS as TS doesn't play well with Flow-ish JS. "allowJs": false, // Don't emit; allow Babel to transform files.