@heroku/heroku-cli-util 9.0.2 → 9.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/errors/ambiguous.d.ts +16 -0
- package/dist/{types/errors → errors}/ambiguous.js +5 -1
- package/dist/errors/not-found.d.ts +20 -0
- package/dist/errors/not-found.js +24 -0
- package/dist/index.d.ts +16 -12
- package/dist/index.js +23 -12
- package/dist/types/pg/data-api.d.ts +35 -6
- package/dist/types/pg/tunnel.d.ts +20 -10
- package/dist/utils/addons/resolve.d.ts +11 -7
- package/dist/utils/addons/resolve.js +30 -23
- package/dist/utils/pg/bastion.d.ts +68 -27
- package/dist/utils/pg/bastion.js +184 -69
- package/dist/utils/pg/config-vars.d.ts +33 -7
- package/dist/utils/pg/config-vars.js +52 -18
- package/dist/utils/pg/databases.d.ts +74 -10
- package/dist/utils/pg/databases.js +170 -114
- package/dist/utils/pg/psql.d.ts +109 -21
- package/dist/utils/pg/psql.js +222 -144
- package/package.json +5 -16
- package/dist/types/errors/ambiguous.d.ts +0 -15
- package/dist/types/errors/not-found.d.ts +0 -5
- package/dist/types/errors/not-found.js +0 -12
package/dist/utils/pg/psql.js
CHANGED
|
@@ -1,162 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Tunnel =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.psqlQueryOptions = psqlQueryOptions;
|
|
7
|
-
exports.execPSQL = execPSQL;
|
|
8
|
-
exports.runWithTunnel = runWithTunnel;
|
|
9
|
-
exports.waitForPSQLExit = waitForPSQLExit;
|
|
10
|
-
const debug_1 = require("debug");
|
|
3
|
+
exports.Tunnel = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const debug_1 = tslib_1.__importDefault(require("debug"));
|
|
11
6
|
const node_child_process_1 = require("node:child_process");
|
|
12
7
|
const node_events_1 = require("node:events");
|
|
13
8
|
const node_stream_1 = require("node:stream");
|
|
14
9
|
const promises_1 = require("node:stream/promises");
|
|
15
10
|
const bastion_1 = require("./bastion");
|
|
16
11
|
const pgDebug = (0, debug_1.default)('pg');
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// eslint-disable-next-line no-async-promise-executor
|
|
21
|
-
const promise = new Promise(async (resolve, reject) => {
|
|
22
|
-
try {
|
|
23
|
-
await (0, promises_1.finished)(throughStream);
|
|
24
|
-
resolve(result);
|
|
25
|
-
}
|
|
26
|
-
catch (error) {
|
|
27
|
-
reject(error);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
// eslint-disable-next-line no-return-assign
|
|
31
|
-
throughStream.on('data', chunk => result += chunk.toString());
|
|
32
|
-
inputStream.pipe(throughStream);
|
|
33
|
-
return promise;
|
|
34
|
-
}
|
|
35
|
-
async function exec(db, query, cmdArgs = []) {
|
|
36
|
-
const configs = (0, bastion_1.getConfigs)(db);
|
|
37
|
-
const options = psqlQueryOptions(query, configs.dbEnv, cmdArgs);
|
|
38
|
-
return runWithTunnel(db, configs.dbTunnelConfig, options);
|
|
39
|
-
}
|
|
40
|
-
function psqlQueryOptions(query, dbEnv, cmdArgs = []) {
|
|
41
|
-
pgDebug('Running query: %s', query.trim());
|
|
42
|
-
const psqlArgs = ['-c', query, '--set', 'sslmode=require', ...cmdArgs];
|
|
43
|
-
const childProcessOptions = {
|
|
44
|
-
stdio: ['ignore', 'pipe', 'inherit'],
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
childProcessOptions,
|
|
48
|
-
dbEnv,
|
|
49
|
-
psqlArgs,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function execPSQL({ childProcessOptions, dbEnv, psqlArgs }) {
|
|
53
|
-
const options = Object.assign({ env: dbEnv }, childProcessOptions);
|
|
54
|
-
pgDebug('opening psql process');
|
|
55
|
-
const psql = (0, node_child_process_1.spawn)('psql', psqlArgs, options);
|
|
56
|
-
psql.once('spawn', () => pgDebug('psql process spawned'));
|
|
57
|
-
return psql;
|
|
58
|
-
}
|
|
59
|
-
// According to node.js docs, sending a kill to a process won't cause an error
|
|
60
|
-
// but could have unintended consequences if the PID gets reassigned:
|
|
61
|
-
// https://nodejs.org/docs/latest-v14.x/api/child_process.html#child_process_subprocess_kill_signal
|
|
62
|
-
// To be on the safe side, check if the process was already killed before sending the signal
|
|
63
|
-
function kill(childProcess, signal) {
|
|
64
|
-
if (!childProcess.killed) {
|
|
65
|
-
pgDebug('killing psql child process');
|
|
66
|
-
childProcess.kill(signal);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
async function runWithTunnel(db, tunnelConfig, options) {
|
|
70
|
-
const tunnel = await Tunnel.connect(db, tunnelConfig);
|
|
71
|
-
pgDebug('after create tunnel');
|
|
72
|
-
const psql = execPSQL(options);
|
|
73
|
-
// interactive opens with stdio: 'inherit'
|
|
74
|
-
// which gives the child process the same stdin,stdout,stderr of the node process (global `process`)
|
|
75
|
-
// https://nodejs.org/api/child_process.html#child_process_options_stdio
|
|
76
|
-
// psql.stdout will be null in this case
|
|
77
|
-
// return a string for consistency but ideally we should return the child process from this function
|
|
78
|
-
// and let the caller decide what to do with stdin/stdout/stderr
|
|
79
|
-
const stdoutPromise = psql.stdout ? consumeStream(psql.stdout) : Promise.resolve('');
|
|
80
|
-
const cleanupSignalTraps = (0, exports.trapAndForwardSignalsToChildProcess)(psql);
|
|
81
|
-
try {
|
|
82
|
-
pgDebug('waiting for psql or tunnel to exit');
|
|
83
|
-
// wait for either psql or tunnel to exit;
|
|
84
|
-
// the important bit is that we ensure both processes are
|
|
85
|
-
// always cleaned up in the `finally` block below
|
|
86
|
-
await Promise.race([
|
|
87
|
-
waitForPSQLExit(psql),
|
|
88
|
-
tunnel.waitForClose(),
|
|
89
|
-
]);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
pgDebug('wait for psql or tunnel error', error);
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
finally {
|
|
96
|
-
pgDebug('begin tunnel cleanup');
|
|
97
|
-
cleanupSignalTraps();
|
|
98
|
-
tunnel.close();
|
|
99
|
-
kill(psql, 'SIGKILL');
|
|
100
|
-
pgDebug('end tunnel cleanup');
|
|
101
|
-
}
|
|
102
|
-
return stdoutPromise;
|
|
103
|
-
}
|
|
104
|
-
// trap SIGINT so that ctrl+c can be used by psql without killing the
|
|
105
|
-
// parent node process.
|
|
106
|
-
// you can use ctrl+c in psql to kill running queries
|
|
107
|
-
// while keeping the psql process open.
|
|
108
|
-
// This code is to stop the parent node process (heroku CLI)
|
|
109
|
-
// from exiting. If the parent Heroku CLI node process exits, then psql will exit as it
|
|
110
|
-
// is a child process of the Heroku CLI node process.
|
|
111
|
-
const trapAndForwardSignalsToChildProcess = (childProcess) => {
|
|
112
|
-
const signalsToTrap = ['SIGINT'];
|
|
113
|
-
const signalTraps = signalsToTrap.map(signal => {
|
|
114
|
-
process.removeAllListeners(signal);
|
|
115
|
-
const listener = () => kill(childProcess, signal);
|
|
116
|
-
process.on(signal, listener);
|
|
117
|
-
return [signal, listener];
|
|
118
|
-
});
|
|
119
|
-
// restores the built-in node ctrl+c and other handlers
|
|
120
|
-
return () => {
|
|
121
|
-
for (const [signal, listener] of signalTraps) {
|
|
122
|
-
process.removeListener(signal, listener);
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
};
|
|
126
|
-
exports.trapAndForwardSignalsToChildProcess = trapAndForwardSignalsToChildProcess;
|
|
127
|
-
async function waitForPSQLExit(psql) {
|
|
128
|
-
let errorToThrow = null;
|
|
129
|
-
try {
|
|
130
|
-
const [exitCode] = await (0, node_events_1.once)(psql, 'close');
|
|
131
|
-
pgDebug(`psql exited with code ${exitCode}`);
|
|
132
|
-
if (exitCode > 0) {
|
|
133
|
-
errorToThrow = new Error(`psql exited with code ${exitCode}`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
pgDebug('psql process error', error);
|
|
138
|
-
const { code } = error;
|
|
139
|
-
if (code === 'ENOENT') {
|
|
140
|
-
errorToThrow = new Error('The local psql command could not be located. For help installing psql, see https://devcenter.heroku.com/articles/heroku-postgresql#local-setup');
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (errorToThrow) {
|
|
144
|
-
throw errorToThrow;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
// a small wrapper around tunnel-ssh
|
|
148
|
-
// so that other code doesn't have to worry about
|
|
149
|
-
// whether there is or is not a tunnel
|
|
12
|
+
/**
|
|
13
|
+
* A small wrapper around tunnel-ssh so that other code doesn't have to worry about whether there is or is not a tunnel.
|
|
14
|
+
*/
|
|
150
15
|
class Tunnel {
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new Tunnel instance.
|
|
18
|
+
*
|
|
19
|
+
* @param bastionTunnel - The SSH tunnel server or void if no tunnel is needed
|
|
20
|
+
*/
|
|
151
21
|
constructor(bastionTunnel) {
|
|
152
22
|
this.bastionTunnel = bastionTunnel;
|
|
153
23
|
// eslint-disable-next-line unicorn/prefer-event-target
|
|
154
24
|
this.events = new node_events_1.EventEmitter();
|
|
155
25
|
}
|
|
156
|
-
|
|
157
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Creates and connects to an SSH tunnel.
|
|
28
|
+
*
|
|
29
|
+
* @param connectionDetails - The database connection details with attachment information
|
|
30
|
+
* @param tunnelConfig - The tunnel configuration object
|
|
31
|
+
* @param tunnelFn - The function to create the SSH tunnel (default: sshTunnel)
|
|
32
|
+
* @returns Promise that resolves to a new Tunnel instance
|
|
33
|
+
*/
|
|
34
|
+
static async connect(connectionDetails, tunnelConfig, tunnelFn) {
|
|
35
|
+
const tunnel = await tunnelFn(connectionDetails, tunnelConfig);
|
|
158
36
|
return new Tunnel(tunnel);
|
|
159
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Closes the tunnel if it exists, or emits a fake close event if no tunnel is needed.
|
|
40
|
+
*
|
|
41
|
+
* @returns void
|
|
42
|
+
*/
|
|
160
43
|
close() {
|
|
161
44
|
if (this.bastionTunnel) {
|
|
162
45
|
pgDebug('close tunnel');
|
|
@@ -167,6 +50,12 @@ class Tunnel {
|
|
|
167
50
|
this.events.emit('close', 0);
|
|
168
51
|
}
|
|
169
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Waits for the tunnel to close.
|
|
55
|
+
*
|
|
56
|
+
* @returns Promise that resolves when the tunnel closes
|
|
57
|
+
* @throws Error if the secure tunnel fails
|
|
58
|
+
*/
|
|
170
59
|
async waitForClose() {
|
|
171
60
|
if (this.bastionTunnel) {
|
|
172
61
|
try {
|
|
@@ -180,9 +69,198 @@ class Tunnel {
|
|
|
180
69
|
}
|
|
181
70
|
}
|
|
182
71
|
else {
|
|
183
|
-
pgDebug('no
|
|
72
|
+
pgDebug('no tunnel required; waiting for fake close event');
|
|
184
73
|
await (0, node_events_1.once)(this.events, 'close');
|
|
185
74
|
}
|
|
186
75
|
}
|
|
187
76
|
}
|
|
188
77
|
exports.Tunnel = Tunnel;
|
|
78
|
+
class PsqlService {
|
|
79
|
+
constructor(connectionDetails, getPsqlConfigsFn = bastion_1.getPsqlConfigs, spawnFn = node_child_process_1.spawn, tunnelFn = bastion_1.sshTunnel) {
|
|
80
|
+
this.connectionDetails = connectionDetails;
|
|
81
|
+
this.getPsqlConfigsFn = getPsqlConfigsFn;
|
|
82
|
+
this.spawnFn = spawnFn;
|
|
83
|
+
this.tunnelFn = tunnelFn;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Executes a PostgreSQL query using the instance's database connection details.
|
|
87
|
+
* It uses the `getPsqlConfigs` function to get the configuration for the database and the tunnel,
|
|
88
|
+
* and then calls the `runWithTunnel` function to execute the query.
|
|
89
|
+
*
|
|
90
|
+
* @param query - The SQL query to execute
|
|
91
|
+
* @param psqlCmdArgs - Additional command-line arguments for psql (default: [])
|
|
92
|
+
* @returns Promise that resolves to the query result as a string
|
|
93
|
+
*/
|
|
94
|
+
async execQuery(query, psqlCmdArgs = []) {
|
|
95
|
+
const configs = this.getPsqlConfigsFn(this.connectionDetails);
|
|
96
|
+
const options = this.psqlQueryOptions(query, configs.dbEnv, psqlCmdArgs);
|
|
97
|
+
return this.runWithTunnel(configs.dbTunnelConfig, options);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Consumes a stream and returns its content as a string.
|
|
101
|
+
*
|
|
102
|
+
* @param inputStream - The input stream to consume
|
|
103
|
+
* @returns Promise that resolves to the stream content as a string
|
|
104
|
+
*/
|
|
105
|
+
consumeStream(inputStream) {
|
|
106
|
+
let result = '';
|
|
107
|
+
const throughStream = new node_stream_1.Stream.PassThrough();
|
|
108
|
+
// eslint-disable-next-line no-async-promise-executor
|
|
109
|
+
const promise = new Promise(async (resolve, reject) => {
|
|
110
|
+
try {
|
|
111
|
+
await (0, promises_1.finished)(throughStream);
|
|
112
|
+
resolve(result);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
reject(error);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
// eslint-disable-next-line no-return-assign
|
|
119
|
+
throughStream.on('data', chunk => result += chunk.toString());
|
|
120
|
+
inputStream.pipe(throughStream);
|
|
121
|
+
return promise;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Kills a child process if it hasn't been killed already.
|
|
125
|
+
* According to node.js docs, sending a kill to a process won't cause an error
|
|
126
|
+
* but could have unintended consequences if the PID gets reassigned.
|
|
127
|
+
* To be on the safe side, check if the process was already killed before sending the signal.
|
|
128
|
+
*
|
|
129
|
+
* @param childProcess - The child process to kill
|
|
130
|
+
* @param signal - The signal to send to the process
|
|
131
|
+
* @returns void
|
|
132
|
+
*/
|
|
133
|
+
kill(childProcess, signal) {
|
|
134
|
+
if (!childProcess.killed) {
|
|
135
|
+
pgDebug('killing psql child process');
|
|
136
|
+
childProcess.kill(signal);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Creates the options for spawning the psql process.
|
|
141
|
+
*
|
|
142
|
+
* @param query - The SQL query to execute
|
|
143
|
+
* @param dbEnv - The database environment variables
|
|
144
|
+
* @param psqlCmdArgs - Additional command-line arguments for psql (default: [])
|
|
145
|
+
* @returns Object containing child process options, database environment, and psql arguments
|
|
146
|
+
*/
|
|
147
|
+
psqlQueryOptions(query, dbEnv, psqlCmdArgs = []) {
|
|
148
|
+
pgDebug('Running query: %s', query.trim());
|
|
149
|
+
const psqlArgs = ['-c', query, '--set', 'sslmode=require', ...psqlCmdArgs];
|
|
150
|
+
const childProcessOptions = {
|
|
151
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
152
|
+
};
|
|
153
|
+
return {
|
|
154
|
+
childProcessOptions,
|
|
155
|
+
dbEnv,
|
|
156
|
+
psqlArgs,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Runs the psql command with tunnel support.
|
|
161
|
+
*
|
|
162
|
+
* @param tunnelConfig - The tunnel configuration object
|
|
163
|
+
* @param options - The options for spawning the psql process
|
|
164
|
+
* @returns Promise that resolves to the query result as a string
|
|
165
|
+
*/
|
|
166
|
+
async runWithTunnel(tunnelConfig, options) {
|
|
167
|
+
const tunnel = await Tunnel.connect(this.connectionDetails, tunnelConfig, this.tunnelFn);
|
|
168
|
+
pgDebug('after create tunnel');
|
|
169
|
+
const psql = this.spawnPsql(options);
|
|
170
|
+
// Note: In non-interactive mode, psql.stdout is available for capturing output.
|
|
171
|
+
// In interactive mode, stdio: 'inherit' would make psql.stdout null.
|
|
172
|
+
// Return a string for consistency but ideally we should return the child process from this function
|
|
173
|
+
// and let the caller decide what to do with stdin/stdout/stderr
|
|
174
|
+
const stdoutPromise = psql.stdout ? this.consumeStream(psql.stdout) : Promise.resolve('');
|
|
175
|
+
const cleanupSignalTraps = this.trapAndForwardSignalsToChildProcess(psql);
|
|
176
|
+
try {
|
|
177
|
+
pgDebug('waiting for psql or tunnel to exit');
|
|
178
|
+
// wait for either psql or tunnel to exit;
|
|
179
|
+
// the important bit is that we ensure both processes are
|
|
180
|
+
// always cleaned up in the `finally` block below
|
|
181
|
+
await Promise.race([
|
|
182
|
+
this.waitForPSQLExit(psql),
|
|
183
|
+
tunnel.waitForClose(),
|
|
184
|
+
]);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
pgDebug('wait for psql or tunnel error', error);
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
pgDebug('begin tunnel cleanup');
|
|
192
|
+
cleanupSignalTraps();
|
|
193
|
+
tunnel.close();
|
|
194
|
+
this.kill(psql, 'SIGKILL');
|
|
195
|
+
pgDebug('end tunnel cleanup');
|
|
196
|
+
}
|
|
197
|
+
return stdoutPromise;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Spawns the psql process with the given options.
|
|
201
|
+
*
|
|
202
|
+
* @param options - The options for spawning the psql process
|
|
203
|
+
* @returns The spawned child process
|
|
204
|
+
*/
|
|
205
|
+
spawnPsql(options) {
|
|
206
|
+
const { childProcessOptions, dbEnv, psqlArgs } = options;
|
|
207
|
+
const spawnOptions = Object.assign({ env: dbEnv }, childProcessOptions);
|
|
208
|
+
pgDebug('opening psql process');
|
|
209
|
+
const psql = this.spawnFn('psql', psqlArgs, spawnOptions);
|
|
210
|
+
psql.once('spawn', () => pgDebug('psql process spawned'));
|
|
211
|
+
return psql;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Traps SIGINT so that ctrl+c can be used by psql without killing the parent node process.
|
|
215
|
+
* You can use ctrl+c in psql to kill running queries while keeping the psql process open.
|
|
216
|
+
* This code is to stop the parent node process (heroku CLI) from exiting.
|
|
217
|
+
* If the parent Heroku CLI node process exits, then psql will exit as it is a child process.
|
|
218
|
+
*
|
|
219
|
+
* @param childProcess - The child process to forward signals to
|
|
220
|
+
* @returns Function to restore the original signal handlers
|
|
221
|
+
*/
|
|
222
|
+
trapAndForwardSignalsToChildProcess(childProcess) {
|
|
223
|
+
const signalsToTrap = ['SIGINT'];
|
|
224
|
+
const signalTraps = signalsToTrap.map(signal => {
|
|
225
|
+
process.removeAllListeners(signal);
|
|
226
|
+
const listener = () => this.kill(childProcess, signal);
|
|
227
|
+
process.on(signal, listener);
|
|
228
|
+
return [signal, listener];
|
|
229
|
+
});
|
|
230
|
+
// restores the built-in node ctrl+c and other handlers
|
|
231
|
+
return () => {
|
|
232
|
+
for (const [signal, listener] of signalTraps) {
|
|
233
|
+
process.removeListener(signal, listener);
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Waits for the psql process to exit and handles any errors.
|
|
239
|
+
*
|
|
240
|
+
* @param psql - The psql process event emitter
|
|
241
|
+
* @throws Error if psql exits with non-zero code or if psql command is not found
|
|
242
|
+
* @returns Promise that resolves to void when psql exits
|
|
243
|
+
*/
|
|
244
|
+
async waitForPSQLExit(psql) {
|
|
245
|
+
let errorToThrow = null;
|
|
246
|
+
try {
|
|
247
|
+
const [exitCode] = await (0, node_events_1.once)(psql, 'close');
|
|
248
|
+
pgDebug(`psql exited with code ${exitCode}`);
|
|
249
|
+
if (exitCode > 0) {
|
|
250
|
+
errorToThrow = new Error(`psql exited with code ${exitCode}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
pgDebug('psql process error', error);
|
|
255
|
+
const { code } = error;
|
|
256
|
+
if (code === 'ENOENT') {
|
|
257
|
+
errorToThrow = new Error('The local psql command could not be located. For help installing psql, see '
|
|
258
|
+
+ 'https://devcenter.heroku.com/articles/heroku-postgresql#local-setup');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (errorToThrow) {
|
|
262
|
+
throw errorToThrow;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
exports.default = PsqlService;
|
package/package.json
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"type": "commonjs",
|
|
3
2
|
"name": "@heroku/heroku-cli-util",
|
|
4
|
-
"version": "9.
|
|
3
|
+
"version": "9.1.1",
|
|
5
4
|
"description": "Set of helpful CLI utilities",
|
|
6
5
|
"author": "Heroku",
|
|
7
6
|
"license": "ISC",
|
|
@@ -19,9 +18,9 @@
|
|
|
19
18
|
"@types/mocha": "^10.0.10",
|
|
20
19
|
"@types/node": "^22.15.3",
|
|
21
20
|
"@types/sinon": "^17.0.4",
|
|
22
|
-
"@types/
|
|
21
|
+
"@types/sinon-chai": "^4.0.0",
|
|
23
22
|
"chai": "^4.4.1",
|
|
24
|
-
"chai-as-promised": "^
|
|
23
|
+
"chai-as-promised": "^7.1.2",
|
|
25
24
|
"eslint": "^8.57.0",
|
|
26
25
|
"eslint-config-oclif": "^5.0.0",
|
|
27
26
|
"eslint-config-oclif-typescript": "^3.1.14",
|
|
@@ -31,6 +30,7 @@
|
|
|
31
30
|
"nock": "^13.2.9",
|
|
32
31
|
"nyc": "^17.1.0",
|
|
33
32
|
"sinon": "^18.0.1",
|
|
33
|
+
"sinon-chai": "^3.7.0",
|
|
34
34
|
"stdout-stderr": "^0.1.13",
|
|
35
35
|
"strip-ansi": "^6",
|
|
36
36
|
"ts-node": "^10.9.2",
|
|
@@ -44,22 +44,11 @@
|
|
|
44
44
|
"@heroku/http-call": "^5.4.0",
|
|
45
45
|
"@oclif/core": "^2.16.0",
|
|
46
46
|
"debug": "^4.4.0",
|
|
47
|
-
"tunnel-ssh": "
|
|
47
|
+
"tunnel-ssh": "5.2.0"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=20"
|
|
51
51
|
},
|
|
52
|
-
"mocha": {
|
|
53
|
-
"require": [
|
|
54
|
-
"ts-node/register",
|
|
55
|
-
"source-map-support/register",
|
|
56
|
-
"test/hooks.ts"
|
|
57
|
-
],
|
|
58
|
-
"watch-extensions": "ts",
|
|
59
|
-
"recursive": true,
|
|
60
|
-
"reporter": "spec",
|
|
61
|
-
"timeout": 360000
|
|
62
|
-
},
|
|
63
52
|
"scripts": {
|
|
64
53
|
"build": "npm run clean && tsc",
|
|
65
54
|
"clean": "rm -rf dist",
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare class AmbiguousError extends Error {
|
|
2
|
-
readonly matches: {
|
|
3
|
-
name?: string;
|
|
4
|
-
}[];
|
|
5
|
-
readonly type: string;
|
|
6
|
-
readonly body: {
|
|
7
|
-
id: string;
|
|
8
|
-
message: string;
|
|
9
|
-
};
|
|
10
|
-
readonly message: string;
|
|
11
|
-
readonly statusCode = 422;
|
|
12
|
-
constructor(matches: {
|
|
13
|
-
name?: string;
|
|
14
|
-
}[], type: string);
|
|
15
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NotFound = void 0;
|
|
4
|
-
class NotFound extends Error {
|
|
5
|
-
constructor() {
|
|
6
|
-
super(...arguments);
|
|
7
|
-
this.id = 'not_found';
|
|
8
|
-
this.message = 'Couldn\'t find that addon.';
|
|
9
|
-
this.statusCode = 404;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
exports.NotFound = NotFound;
|