@maz-ui/node 5.0.0-beta.24 → 5.0.0-beta.26
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/index.d.mts +89 -9
- package/dist/index.d.ts +89 -9
- package/dist/index.mjs +64 -10
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExecOptions } from 'node:child_process';
|
|
1
2
|
import * as consola from 'consola';
|
|
2
3
|
import { ConsolaOptions, InputLogObject, ConsolaReporter, ConsolaInstance } from 'consola';
|
|
3
4
|
export { ConsolaOptions } from 'consola';
|
|
@@ -51,28 +52,88 @@ interface CustomLogger {
|
|
|
51
52
|
warn: (message: string, ...args: any[]) => void;
|
|
52
53
|
debug: (message: string, ...args: any[]) => void;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Options for {@link execPromise}.
|
|
57
|
+
*
|
|
58
|
+
* The following fields are forwarded as-is to `child_process.exec`:
|
|
59
|
+
* - `cwd` - working directory of the command. Defaults to the current one.
|
|
60
|
+
* - `env` - environment variables, **merged on top of `process.env`**.
|
|
61
|
+
* - `timeout` - maximum run time in milliseconds before the command is killed. No timeout by default.
|
|
62
|
+
* - `maxBuffer` - maximum bytes allowed on stdout/stderr before the command is killed. Defaults to `1024 * 1024` (1 MiB).
|
|
63
|
+
* - `killSignal` - signal used to kill the command on timeout or abort. Defaults to `'SIGTERM'`.
|
|
64
|
+
* - `shell` - shell used to run the command. Defaults to `/bin/sh` (Unix) or `cmd.exe` (Windows).
|
|
65
|
+
* - `signal` - an `AbortSignal` that, once aborted, kills the command and rejects the promise.
|
|
66
|
+
*/
|
|
67
|
+
type ExecPromiseOptions = Pick<ExecOptions, 'cwd' | 'timeout' | 'env' | 'maxBuffer' | 'killSignal' | 'shell' | 'signal'> & {
|
|
68
|
+
/**
|
|
69
|
+
* Custom logger used for every output. Falls back to the package logger.
|
|
70
|
+
*/
|
|
55
71
|
logger?: CustomLogger;
|
|
72
|
+
/**
|
|
73
|
+
* Prefix added to every log line, formatted as `[packageName]: `.
|
|
74
|
+
*/
|
|
56
75
|
packageName?: string;
|
|
57
76
|
/**
|
|
58
|
-
* Don't log success message
|
|
77
|
+
* Don't log the success message.
|
|
78
|
+
* @default false
|
|
59
79
|
*/
|
|
60
80
|
noSuccess?: boolean;
|
|
61
81
|
/**
|
|
62
|
-
* Don't log stdout
|
|
82
|
+
* Don't log stdout.
|
|
83
|
+
* @default false
|
|
63
84
|
*/
|
|
64
85
|
noStdout?: boolean;
|
|
65
86
|
/**
|
|
66
|
-
* Don't log stderr
|
|
87
|
+
* Don't log stderr.
|
|
88
|
+
* @default false
|
|
67
89
|
*/
|
|
68
90
|
noStderr?: boolean;
|
|
69
91
|
/**
|
|
70
|
-
* Don't log error
|
|
92
|
+
* Don't log the error when the command fails.
|
|
93
|
+
* @default false
|
|
71
94
|
*/
|
|
72
95
|
noError?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Logging level applied to the default logger before running the command.
|
|
98
|
+
*/
|
|
73
99
|
logLevel?: LogLevel;
|
|
74
|
-
|
|
75
|
-
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Runs a shell command and resolves with its `stdout` and `stderr`.
|
|
103
|
+
*
|
|
104
|
+
* Secrets (npm auth tokens, `--token`/`--password` flags, provider tokens,
|
|
105
|
+
* JWTs, basic-auth URLs) are automatically masked in every log line and in the
|
|
106
|
+
* rejected error via {@link redactSecrets}. The resolved `stdout`/`stderr` are
|
|
107
|
+
* returned untouched.
|
|
108
|
+
*
|
|
109
|
+
* @param command - The shell command to execute.
|
|
110
|
+
* @returns A promise resolving with the command `stdout` and `stderr`.
|
|
111
|
+
* @throws If the command exits with a non-zero code, times out, is aborted, or
|
|
112
|
+
* exceeds `maxBuffer`. The rejected error is redacted.
|
|
113
|
+
*
|
|
114
|
+
* @example Basic usage
|
|
115
|
+
* ```ts
|
|
116
|
+
* const { stdout } = await execPromise('node --version')
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example Fail the command after 5 seconds
|
|
120
|
+
* ```ts
|
|
121
|
+
* await execPromise('pnpm install', { timeout: 5000 })
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @example Inject environment variables (merged on top of `process.env`)
|
|
125
|
+
* ```ts
|
|
126
|
+
* await execPromise('node build.mjs', { env: { NODE_ENV: 'production' } })
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @example Cancel the command with an `AbortController`
|
|
130
|
+
* ```ts
|
|
131
|
+
* const controller = new AbortController()
|
|
132
|
+
* const promise = execPromise('long-task', { signal: controller.signal })
|
|
133
|
+
* controller.abort()
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare function execPromise(command: string, { logger, packageName, noSuccess, noStdout, noStderr, noError, logLevel, cwd, timeout, env, maxBuffer, killSignal, shell, signal, }?: ExecPromiseOptions): Promise<{
|
|
76
137
|
stdout: string;
|
|
77
138
|
stderr: string;
|
|
78
139
|
}>;
|
|
@@ -88,5 +149,24 @@ declare function printBanner({ name, version, options, }: {
|
|
|
88
149
|
};
|
|
89
150
|
}): void;
|
|
90
151
|
|
|
91
|
-
|
|
92
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Masks secrets that have a recognizable syntactic context inside a string.
|
|
154
|
+
*
|
|
155
|
+
* Only deterministic patterns are redacted (npm auth tokens, named secret flags
|
|
156
|
+
* such as `--token`/`--password`, prefixed provider tokens like `npm_`/`ghp_`,
|
|
157
|
+
* JWTs, and basic-auth credentials in URLs). Context-free random strings are left
|
|
158
|
+
* untouched because they cannot be detected without false positives.
|
|
159
|
+
*
|
|
160
|
+
* Tokens long enough (>= 16 chars) keep their first and last 4 characters visible
|
|
161
|
+
* (e.g. `npm_***J1iF`) so the right credential can still be recognized; shorter
|
|
162
|
+
* secrets are fully masked.
|
|
163
|
+
*/
|
|
164
|
+
declare function redactSecrets(input: string): string;
|
|
165
|
+
/**
|
|
166
|
+
* Returns the given error with its `message`, `cmd` and `stack` redacted via
|
|
167
|
+
* {@link redactSecrets}, so a thrown command never carries secrets to callers.
|
|
168
|
+
*/
|
|
169
|
+
declare function redactError<T>(error: T): T;
|
|
170
|
+
|
|
171
|
+
export { createLogger, execPromise, logger, printBanner, redactError, redactSecrets };
|
|
172
|
+
export type { ExecPromiseOptions, LogLevel, Logger, LoggerOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ExecOptions } from 'node:child_process';
|
|
1
2
|
import * as consola from 'consola';
|
|
2
3
|
import { ConsolaOptions, InputLogObject, ConsolaReporter, ConsolaInstance } from 'consola';
|
|
3
4
|
export { ConsolaOptions } from 'consola';
|
|
@@ -51,28 +52,88 @@ interface CustomLogger {
|
|
|
51
52
|
warn: (message: string, ...args: any[]) => void;
|
|
52
53
|
debug: (message: string, ...args: any[]) => void;
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Options for {@link execPromise}.
|
|
57
|
+
*
|
|
58
|
+
* The following fields are forwarded as-is to `child_process.exec`:
|
|
59
|
+
* - `cwd` - working directory of the command. Defaults to the current one.
|
|
60
|
+
* - `env` - environment variables, **merged on top of `process.env`**.
|
|
61
|
+
* - `timeout` - maximum run time in milliseconds before the command is killed. No timeout by default.
|
|
62
|
+
* - `maxBuffer` - maximum bytes allowed on stdout/stderr before the command is killed. Defaults to `1024 * 1024` (1 MiB).
|
|
63
|
+
* - `killSignal` - signal used to kill the command on timeout or abort. Defaults to `'SIGTERM'`.
|
|
64
|
+
* - `shell` - shell used to run the command. Defaults to `/bin/sh` (Unix) or `cmd.exe` (Windows).
|
|
65
|
+
* - `signal` - an `AbortSignal` that, once aborted, kills the command and rejects the promise.
|
|
66
|
+
*/
|
|
67
|
+
type ExecPromiseOptions = Pick<ExecOptions, 'cwd' | 'timeout' | 'env' | 'maxBuffer' | 'killSignal' | 'shell' | 'signal'> & {
|
|
68
|
+
/**
|
|
69
|
+
* Custom logger used for every output. Falls back to the package logger.
|
|
70
|
+
*/
|
|
55
71
|
logger?: CustomLogger;
|
|
72
|
+
/**
|
|
73
|
+
* Prefix added to every log line, formatted as `[packageName]: `.
|
|
74
|
+
*/
|
|
56
75
|
packageName?: string;
|
|
57
76
|
/**
|
|
58
|
-
* Don't log success message
|
|
77
|
+
* Don't log the success message.
|
|
78
|
+
* @default false
|
|
59
79
|
*/
|
|
60
80
|
noSuccess?: boolean;
|
|
61
81
|
/**
|
|
62
|
-
* Don't log stdout
|
|
82
|
+
* Don't log stdout.
|
|
83
|
+
* @default false
|
|
63
84
|
*/
|
|
64
85
|
noStdout?: boolean;
|
|
65
86
|
/**
|
|
66
|
-
* Don't log stderr
|
|
87
|
+
* Don't log stderr.
|
|
88
|
+
* @default false
|
|
67
89
|
*/
|
|
68
90
|
noStderr?: boolean;
|
|
69
91
|
/**
|
|
70
|
-
* Don't log error
|
|
92
|
+
* Don't log the error when the command fails.
|
|
93
|
+
* @default false
|
|
71
94
|
*/
|
|
72
95
|
noError?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Logging level applied to the default logger before running the command.
|
|
98
|
+
*/
|
|
73
99
|
logLevel?: LogLevel;
|
|
74
|
-
|
|
75
|
-
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Runs a shell command and resolves with its `stdout` and `stderr`.
|
|
103
|
+
*
|
|
104
|
+
* Secrets (npm auth tokens, `--token`/`--password` flags, provider tokens,
|
|
105
|
+
* JWTs, basic-auth URLs) are automatically masked in every log line and in the
|
|
106
|
+
* rejected error via {@link redactSecrets}. The resolved `stdout`/`stderr` are
|
|
107
|
+
* returned untouched.
|
|
108
|
+
*
|
|
109
|
+
* @param command - The shell command to execute.
|
|
110
|
+
* @returns A promise resolving with the command `stdout` and `stderr`.
|
|
111
|
+
* @throws If the command exits with a non-zero code, times out, is aborted, or
|
|
112
|
+
* exceeds `maxBuffer`. The rejected error is redacted.
|
|
113
|
+
*
|
|
114
|
+
* @example Basic usage
|
|
115
|
+
* ```ts
|
|
116
|
+
* const { stdout } = await execPromise('node --version')
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @example Fail the command after 5 seconds
|
|
120
|
+
* ```ts
|
|
121
|
+
* await execPromise('pnpm install', { timeout: 5000 })
|
|
122
|
+
* ```
|
|
123
|
+
*
|
|
124
|
+
* @example Inject environment variables (merged on top of `process.env`)
|
|
125
|
+
* ```ts
|
|
126
|
+
* await execPromise('node build.mjs', { env: { NODE_ENV: 'production' } })
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* @example Cancel the command with an `AbortController`
|
|
130
|
+
* ```ts
|
|
131
|
+
* const controller = new AbortController()
|
|
132
|
+
* const promise = execPromise('long-task', { signal: controller.signal })
|
|
133
|
+
* controller.abort()
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
declare function execPromise(command: string, { logger, packageName, noSuccess, noStdout, noStderr, noError, logLevel, cwd, timeout, env, maxBuffer, killSignal, shell, signal, }?: ExecPromiseOptions): Promise<{
|
|
76
137
|
stdout: string;
|
|
77
138
|
stderr: string;
|
|
78
139
|
}>;
|
|
@@ -88,5 +149,24 @@ declare function printBanner({ name, version, options, }: {
|
|
|
88
149
|
};
|
|
89
150
|
}): void;
|
|
90
151
|
|
|
91
|
-
|
|
92
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Masks secrets that have a recognizable syntactic context inside a string.
|
|
154
|
+
*
|
|
155
|
+
* Only deterministic patterns are redacted (npm auth tokens, named secret flags
|
|
156
|
+
* such as `--token`/`--password`, prefixed provider tokens like `npm_`/`ghp_`,
|
|
157
|
+
* JWTs, and basic-auth credentials in URLs). Context-free random strings are left
|
|
158
|
+
* untouched because they cannot be detected without false positives.
|
|
159
|
+
*
|
|
160
|
+
* Tokens long enough (>= 16 chars) keep their first and last 4 characters visible
|
|
161
|
+
* (e.g. `npm_***J1iF`) so the right credential can still be recognized; shorter
|
|
162
|
+
* secrets are fully masked.
|
|
163
|
+
*/
|
|
164
|
+
declare function redactSecrets(input: string): string;
|
|
165
|
+
/**
|
|
166
|
+
* Returns the given error with its `message`, `cmd` and `stack` redacted via
|
|
167
|
+
* {@link redactSecrets}, so a thrown command never carries secrets to callers.
|
|
168
|
+
*/
|
|
169
|
+
declare function redactError<T>(error: T): T;
|
|
170
|
+
|
|
171
|
+
export { createLogger, execPromise, logger, printBanner, redactError, redactSecrets };
|
|
172
|
+
export type { ExecPromiseOptions, LogLevel, Logger, LoggerOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -53,6 +53,43 @@ function createLogger(options) {
|
|
|
53
53
|
}
|
|
54
54
|
const logger = createLogger();
|
|
55
55
|
|
|
56
|
+
const MASK = "***";
|
|
57
|
+
const VISIBLE_PREFIX = 4;
|
|
58
|
+
const MIN_LENGTH_TO_REVEAL = 16;
|
|
59
|
+
const SECRET_FLAG_NAMES = "password|passwd|pwd|pass|token|api[-_]?key|secret|authorization|auth[-_]?token|access[-_]?token|refresh[-_]?token|client[-_]?secret|private[-_]?key|credentials?|auth";
|
|
60
|
+
const keepEnds = (value) => value.length < MIN_LENGTH_TO_REVEAL ? MASK : `${value.slice(0, VISIBLE_PREFIX)}${MASK}${value.slice(-4)}`;
|
|
61
|
+
const keepPrefix = (_match, prefix, value) => `${prefix}${keepEnds(value)}`;
|
|
62
|
+
const REDACTION_RULES = [
|
|
63
|
+
[/(:?_authToken=)([^\s&]+)/gi, keepPrefix],
|
|
64
|
+
[new RegExp(`(--(?:${SECRET_FLAG_NAMES})=)(\\S+)`, "gi"), keepPrefix],
|
|
65
|
+
[new RegExp(`(--(?:${SECRET_FLAG_NAMES})\\s+)(?!-)(\\S+)`, "gi"), keepPrefix],
|
|
66
|
+
[/(\/\/[^/:@\s]+:)([^/@\s]+)@/g, (_match, prefix, value) => `${prefix}${keepEnds(value)}@`],
|
|
67
|
+
[/npm_[A-Za-z0-9]{10,}/g, keepEnds],
|
|
68
|
+
[/gh[posru]_[A-Za-z0-9]{20,}/g, keepEnds],
|
|
69
|
+
[/github_pat_\w{20,}/g, keepEnds],
|
|
70
|
+
[/glpat-[\w-]{15,}/g, keepEnds],
|
|
71
|
+
[/xox[baprs]-[A-Za-z0-9-]{10,}/g, keepEnds],
|
|
72
|
+
[/AKIA[0-9A-Z]{16}/g, keepEnds],
|
|
73
|
+
[/sk-[\w-]{16,}/g, keepEnds],
|
|
74
|
+
[/eyJ[\w-]+\.eyJ[\w-]+\.[\w-]+/g, keepEnds]
|
|
75
|
+
];
|
|
76
|
+
const REDACTABLE_ERROR_KEYS = ["message", "cmd", "stack"];
|
|
77
|
+
function redactSecrets(input) {
|
|
78
|
+
return REDACTION_RULES.reduce((acc, [pattern, replacement]) => acc.replace(pattern, replacement), input);
|
|
79
|
+
}
|
|
80
|
+
function redactError(error) {
|
|
81
|
+
if (!error || typeof error !== "object") {
|
|
82
|
+
return error;
|
|
83
|
+
}
|
|
84
|
+
for (const key of REDACTABLE_ERROR_KEYS) {
|
|
85
|
+
const value = error[key];
|
|
86
|
+
if (typeof value === "string") {
|
|
87
|
+
error[key] = redactSecrets(value);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return error;
|
|
91
|
+
}
|
|
92
|
+
|
|
56
93
|
async function execPromise(command, {
|
|
57
94
|
logger: logger$1,
|
|
58
95
|
packageName,
|
|
@@ -61,35 +98,52 @@ async function execPromise(command, {
|
|
|
61
98
|
noStderr = false,
|
|
62
99
|
noError = false,
|
|
63
100
|
logLevel,
|
|
64
|
-
cwd
|
|
101
|
+
cwd,
|
|
102
|
+
timeout,
|
|
103
|
+
env,
|
|
104
|
+
maxBuffer,
|
|
105
|
+
killSignal,
|
|
106
|
+
shell,
|
|
107
|
+
signal
|
|
65
108
|
} = {}) {
|
|
66
109
|
if (logLevel) {
|
|
67
110
|
logger.setLevel(logLevel);
|
|
68
111
|
}
|
|
69
112
|
const internalLogger = logger$1 ?? logger;
|
|
70
113
|
const packageNameStr = packageName ? `[${packageName}]: ` : "";
|
|
114
|
+
const safeCommand = redactSecrets(command);
|
|
71
115
|
return await new Promise((resolve, reject) => {
|
|
72
|
-
exec(command, {
|
|
116
|
+
exec(command, {
|
|
117
|
+
cwd,
|
|
118
|
+
timeout,
|
|
119
|
+
maxBuffer,
|
|
120
|
+
killSignal,
|
|
121
|
+
shell,
|
|
122
|
+
signal,
|
|
123
|
+
env: env ? { ...process$1.env, ...env } : void 0
|
|
124
|
+
}, (error, stdout, stderr) => {
|
|
73
125
|
if (stdout) {
|
|
74
|
-
internalLogger.debug(`${
|
|
126
|
+
internalLogger.debug(`${safeCommand} - stdout output:`, redactSecrets(stdout));
|
|
75
127
|
}
|
|
76
128
|
if (stderr) {
|
|
77
|
-
internalLogger.debug(`${
|
|
129
|
+
internalLogger.debug(`${safeCommand} - stderr output:`, redactSecrets(stderr));
|
|
78
130
|
}
|
|
79
131
|
if (stdout && !noStdout) {
|
|
80
|
-
internalLogger.log(`${packageNameStr}stdout -`, stdout.trim());
|
|
132
|
+
internalLogger.log(`${packageNameStr}stdout -`, redactSecrets(stdout.trim()));
|
|
81
133
|
}
|
|
82
134
|
if (stderr && !noStderr) {
|
|
83
|
-
internalLogger.log(`${packageNameStr}stderr -`, stderr.trim());
|
|
135
|
+
internalLogger.log(`${packageNameStr}stderr -`, redactSecrets(stderr.trim()));
|
|
84
136
|
}
|
|
85
137
|
if (error) {
|
|
138
|
+
const safeError = redactError(error);
|
|
86
139
|
if (!noError) {
|
|
87
|
-
|
|
140
|
+
const reason = error.killed && timeout ? `timed out after ${timeout}ms` : "failed";
|
|
141
|
+
internalLogger.error(`${packageNameStr}${safeCommand} ${reason}`, safeError);
|
|
88
142
|
}
|
|
89
|
-
reject(
|
|
143
|
+
reject(safeError);
|
|
90
144
|
} else {
|
|
91
145
|
if (!noSuccess) {
|
|
92
|
-
internalLogger.info(`${packageNameStr}${
|
|
146
|
+
internalLogger.info(`${packageNameStr}${safeCommand} - Success!`);
|
|
93
147
|
}
|
|
94
148
|
resolve({ stdout, stderr });
|
|
95
149
|
}
|
|
@@ -126,4 +180,4 @@ function printBanner({
|
|
|
126
180
|
logger.break();
|
|
127
181
|
}
|
|
128
182
|
|
|
129
|
-
export { createLogger, execPromise, logger, printBanner };
|
|
183
|
+
export { createLogger, execPromise, logger, printBanner, redactError, redactSecrets };
|