@walkeros/core 4.6.1 → 4.7.0-next-1790245733116
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/CHANGELOG.md +67 -0
- package/dist/dev.d.mts +637 -60
- package/dist/dev.d.ts +637 -60
- package/dist/dev.js +1 -1
- package/dist/dev.js.map +1 -1
- package/dist/dev.mjs +1 -1
- package/dist/dev.mjs.map +1 -1
- package/dist/index.d.mts +500 -74
- package/dist/index.d.ts +500 -74
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +244 -0
- package/dist/node.d.ts +244 -0
- package/dist/node.js +1 -0
- package/dist/node.js.map +1 -0
- package/dist/node.mjs +1 -0
- package/dist/node.mjs.map +1 -0
- package/package.json +6 -1
package/dist/node.d.mts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared secret redactor. One set of patterns for every path that egresses a
|
|
3
|
+
* log line: the CLI logger handler and the runtime logger handler (scrubbing
|
|
4
|
+
* console and the error ring), and the runtime heartbeat (scrubbing the ring
|
|
5
|
+
* snapshot before the POST). A pattern added here covers all of them.
|
|
6
|
+
*
|
|
7
|
+
* Two entry points:
|
|
8
|
+
* - `scrubSecrets(line)`: mask secrets, keep the message length intact (for
|
|
9
|
+
* console/stderr legibility).
|
|
10
|
+
* - `redactLine(line)`: `scrubSecrets` plus truncation to the 256-char
|
|
11
|
+
* heartbeat wire contract.
|
|
12
|
+
*
|
|
13
|
+
* All regex are linear (single unambiguous quantifiers, no nested quantifiers),
|
|
14
|
+
* so there is no catastrophic backtracking even on a BEGIN-marker-with-no-END
|
|
15
|
+
* input or a long no-space line. Exported from `@walkeros/core/node` only: no
|
|
16
|
+
* browser consumer needs it, and it must not ride into web bundles.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Scrub credential material from a log line (or multi-line entry) WITHOUT
|
|
20
|
+
* truncating. This is the shared secret redactor used by the CLI logger handler
|
|
21
|
+
* (covers console/stderr and the ring before egress).
|
|
22
|
+
*
|
|
23
|
+
* Algorithm:
|
|
24
|
+
* 1. Mask JSON service-account fields (private_key, client_email,
|
|
25
|
+
* private_key_id, client_id, client_x509_cert_url) BEFORE splitting
|
|
26
|
+
* (service-account blobs embed PEM blocks as \\n-encoded strings; masking
|
|
27
|
+
* first prevents the BEGIN marker from appearing on its own line and dropping
|
|
28
|
+
* surrounding fields).
|
|
29
|
+
* 2. Split on \\n.
|
|
30
|
+
* 3. Remove PEM private-key blocks structurally (BEGIN…END inclusive,
|
|
31
|
+
* case-insensitive; a no-END block drops to end of entry).
|
|
32
|
+
* 4. For each surviving line: mask URL creds, KEY=secret, prefixed tokens,
|
|
33
|
+
* high-entropy/shape-based token runs.
|
|
34
|
+
* 5. Rejoin with \\n.
|
|
35
|
+
*/
|
|
36
|
+
declare function scrubSecrets(line: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Redact a log line and truncate to the heartbeat wire contract (256 chars).
|
|
39
|
+
* This is the heartbeat-egress variant: scrub secrets, then truncate AFTER
|
|
40
|
+
* masking so a token straddling char 256 is masked, not left partially visible.
|
|
41
|
+
*
|
|
42
|
+
* The app's heartbeat schema enforces message .max(256); a 257-char string
|
|
43
|
+
* would fail zod .parse and drop the whole heartbeat. Reserve one char for the
|
|
44
|
+
* ellipsis so the TOTAL length is at most MAX_LENGTH (256).
|
|
45
|
+
*/
|
|
46
|
+
declare function redactLine(line: string): string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Log levels from most to least severe
|
|
50
|
+
*/
|
|
51
|
+
declare enum Level {
|
|
52
|
+
ERROR = 0,
|
|
53
|
+
WARN = 1,
|
|
54
|
+
INFO = 2,
|
|
55
|
+
DEBUG = 3
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Normalized error context extracted from Error objects
|
|
59
|
+
*/
|
|
60
|
+
interface ErrorContext {
|
|
61
|
+
message: string;
|
|
62
|
+
name: string;
|
|
63
|
+
stack?: string;
|
|
64
|
+
cause?: unknown;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Context passed to log handlers
|
|
68
|
+
* If an Error was passed, it's normalized into the error property
|
|
69
|
+
*/
|
|
70
|
+
interface LogContext {
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
error?: ErrorContext;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log message function signature
|
|
76
|
+
* Accepts string or Error as message, with optional context
|
|
77
|
+
*/
|
|
78
|
+
type LogFn = (message: string | Error, context?: unknown | Error) => void;
|
|
79
|
+
/**
|
|
80
|
+
* Throw function signature - logs error then throws
|
|
81
|
+
* Returns never as it always throws
|
|
82
|
+
*/
|
|
83
|
+
type ThrowFn = (message: string | Error, context?: unknown) => never;
|
|
84
|
+
/**
|
|
85
|
+
* Default handler function (passed to custom handlers for chaining)
|
|
86
|
+
*/
|
|
87
|
+
type DefaultHandler = (level: Level, message: string, context: LogContext, scope: string[]) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Custom log handler function
|
|
90
|
+
* Receives originalHandler to allow middleware-style chaining
|
|
91
|
+
*/
|
|
92
|
+
type Handler = (level: Level, message: string, context: LogContext, scope: string[], originalHandler: DefaultHandler) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Logger instance with scoping support
|
|
95
|
+
* All logs automatically include trace path from scoping
|
|
96
|
+
*/
|
|
97
|
+
interface Instance {
|
|
98
|
+
/**
|
|
99
|
+
* Log an error message (always visible unless silenced)
|
|
100
|
+
*/
|
|
101
|
+
error: LogFn;
|
|
102
|
+
/**
|
|
103
|
+
* Log a warning (degraded state, config issues, transient failures)
|
|
104
|
+
*/
|
|
105
|
+
warn: LogFn;
|
|
106
|
+
/**
|
|
107
|
+
* Log an informational message
|
|
108
|
+
*/
|
|
109
|
+
info: LogFn;
|
|
110
|
+
/**
|
|
111
|
+
* Log a debug message
|
|
112
|
+
*/
|
|
113
|
+
debug: LogFn;
|
|
114
|
+
/**
|
|
115
|
+
* Log an error message and throw an Error
|
|
116
|
+
* Combines logging and throwing in one call
|
|
117
|
+
*/
|
|
118
|
+
throw: ThrowFn;
|
|
119
|
+
/**
|
|
120
|
+
* Output structured JSON data
|
|
121
|
+
*/
|
|
122
|
+
json: (data: unknown) => void;
|
|
123
|
+
/**
|
|
124
|
+
* Create a scoped child logger with automatic trace path
|
|
125
|
+
* @param name - Scope name (e.g., destination type, destination key)
|
|
126
|
+
* @returns A new logger instance with the scope applied
|
|
127
|
+
*/
|
|
128
|
+
scope: (name: string) => Instance;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Logger configuration options
|
|
132
|
+
*/
|
|
133
|
+
interface Config {
|
|
134
|
+
/**
|
|
135
|
+
* Minimum log level to display
|
|
136
|
+
* @default Level.ERROR
|
|
137
|
+
*/
|
|
138
|
+
level?: Level | keyof typeof Level;
|
|
139
|
+
/**
|
|
140
|
+
* Custom log handler function
|
|
141
|
+
* Receives originalHandler to preserve default behavior
|
|
142
|
+
*/
|
|
143
|
+
handler?: Handler;
|
|
144
|
+
/** Custom handler for json() output. Default: console.log(JSON.stringify(data, null, 2)) */
|
|
145
|
+
jsonHandler?: (data: unknown) => void;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Node entry point (`@walkeros/core/node`).
|
|
150
|
+
*
|
|
151
|
+
* Helpers shared by `@walkeros/cli` and `@walkeros/runner` that do not belong
|
|
152
|
+
* in the browser `.` entry: the temp-path helpers import node builtins, the
|
|
153
|
+
* terminal logger config writes to the console, and the secret redactor has
|
|
154
|
+
* no browser consumer (in `.` it was not tree-shaken out of walker.js). Core gains no dependency
|
|
155
|
+
* for them: the colouriser is injected by the caller, so chalk stays in the
|
|
156
|
+
* packages that already depend on it.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get a path within the temp directory.
|
|
161
|
+
*
|
|
162
|
+
* @param tmpDir - Custom temp directory (optional, for --tmp-dir flag)
|
|
163
|
+
* @param segments - Path segments to join
|
|
164
|
+
* @returns Absolute path within temp directory
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* getTmpPath() // → "/tmp"
|
|
169
|
+
* getTmpPath(undefined, 'entry.js') // → "/tmp/entry.js"
|
|
170
|
+
* getTmpPath(undefined, 'cache', 'builds') // → "/tmp/cache/builds"
|
|
171
|
+
* getTmpPath('/custom', 'cache') // → "/custom/cache"
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare function getTmpPath(tmpDir?: string, ...segments: string[]): string;
|
|
175
|
+
/**
|
|
176
|
+
* A temp path resolver with the root directory baked in.
|
|
177
|
+
*
|
|
178
|
+
* Use {@link createTmpResolver} at entry points to capture the temp root once,
|
|
179
|
+
* then pass the resolver to downstream functions. This prevents the class of
|
|
180
|
+
* bugs where callers forget to pass tmpDir.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const tmp = createTmpResolver(buildOptions.tempDir);
|
|
185
|
+
* const cacheDir = tmp('cache', 'packages'); // root is baked in
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
type TmpResolver = (...segments: string[]) => string;
|
|
189
|
+
declare function createTmpResolver(tmpDir?: string): TmpResolver;
|
|
190
|
+
/**
|
|
191
|
+
* Get the default temp root directory.
|
|
192
|
+
*/
|
|
193
|
+
declare function getDefaultTmpRoot(): string;
|
|
194
|
+
interface CLILoggerOptions {
|
|
195
|
+
verbose?: boolean;
|
|
196
|
+
silent?: boolean;
|
|
197
|
+
json?: boolean;
|
|
198
|
+
stderr?: boolean;
|
|
199
|
+
onLine?: (level: Level, message: string) => void;
|
|
200
|
+
}
|
|
201
|
+
/** Formats one already-scrubbed line for the terminal. */
|
|
202
|
+
type LineFormatter = (line: string) => string;
|
|
203
|
+
/**
|
|
204
|
+
* Per-level terminal formatters. Every level defaults to identity, so a caller
|
|
205
|
+
* that passes nothing gets plain uncoloured output.
|
|
206
|
+
*/
|
|
207
|
+
interface CLILoggerColors {
|
|
208
|
+
error?: LineFormatter;
|
|
209
|
+
warn?: LineFormatter;
|
|
210
|
+
info?: LineFormatter;
|
|
211
|
+
debug?: LineFormatter;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build the `Logger.Config` (level + handler + jsonHandler) that backs a
|
|
215
|
+
* terminal logger. Returned separately so the runtime can hand the SAME
|
|
216
|
+
* handler (including the `onLine` ring tap) to the deployed bundle's
|
|
217
|
+
* collector.
|
|
218
|
+
*
|
|
219
|
+
* The collector in a deployed bundle builds its own logger from this config
|
|
220
|
+
* (`config.logger`), so its destination errors flow through the identical
|
|
221
|
+
* `onLine` tap the runtime logger uses, landing in the shared ErrorRing.
|
|
222
|
+
* There is no parallel ring: one handler, one tap.
|
|
223
|
+
*
|
|
224
|
+
* Level: `Level.DEBUG` so the handler sees every line and controls visibility
|
|
225
|
+
* itself (verbose/silent gating). ERROR is therefore always emitted into the
|
|
226
|
+
* ring regardless of `--verbose`.
|
|
227
|
+
*
|
|
228
|
+
* `colors` formats each level for the terminal. It is applied to console
|
|
229
|
+
* output only, never to the line handed to `onLine`.
|
|
230
|
+
*/
|
|
231
|
+
declare function createCLILoggerConfig(options?: CLILoggerOptions, colors?: CLILoggerColors): Config;
|
|
232
|
+
/**
|
|
233
|
+
* Create a core Logger.Instance with terminal-appropriate behavior.
|
|
234
|
+
*
|
|
235
|
+
* Behavior:
|
|
236
|
+
* - ERROR: always shown (via console.error, `colors.error`) unless --json
|
|
237
|
+
* - WARN: shown unless --silent or --json
|
|
238
|
+
* - INFO: shown unless --silent or --json
|
|
239
|
+
* - DEBUG: shown only with --verbose (and not --silent/--json)
|
|
240
|
+
* - json(): shown unless --silent
|
|
241
|
+
*/
|
|
242
|
+
declare function createCLILogger(options?: CLILoggerOptions, colors?: CLILoggerColors): Instance;
|
|
243
|
+
|
|
244
|
+
export { type CLILoggerColors, type CLILoggerOptions, type LineFormatter, type TmpResolver, createCLILogger, createCLILoggerConfig, createTmpResolver, getDefaultTmpRoot, getTmpPath, redactLine, scrubSecrets };
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared secret redactor. One set of patterns for every path that egresses a
|
|
3
|
+
* log line: the CLI logger handler and the runtime logger handler (scrubbing
|
|
4
|
+
* console and the error ring), and the runtime heartbeat (scrubbing the ring
|
|
5
|
+
* snapshot before the POST). A pattern added here covers all of them.
|
|
6
|
+
*
|
|
7
|
+
* Two entry points:
|
|
8
|
+
* - `scrubSecrets(line)`: mask secrets, keep the message length intact (for
|
|
9
|
+
* console/stderr legibility).
|
|
10
|
+
* - `redactLine(line)`: `scrubSecrets` plus truncation to the 256-char
|
|
11
|
+
* heartbeat wire contract.
|
|
12
|
+
*
|
|
13
|
+
* All regex are linear (single unambiguous quantifiers, no nested quantifiers),
|
|
14
|
+
* so there is no catastrophic backtracking even on a BEGIN-marker-with-no-END
|
|
15
|
+
* input or a long no-space line. Exported from `@walkeros/core/node` only: no
|
|
16
|
+
* browser consumer needs it, and it must not ride into web bundles.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Scrub credential material from a log line (or multi-line entry) WITHOUT
|
|
20
|
+
* truncating. This is the shared secret redactor used by the CLI logger handler
|
|
21
|
+
* (covers console/stderr and the ring before egress).
|
|
22
|
+
*
|
|
23
|
+
* Algorithm:
|
|
24
|
+
* 1. Mask JSON service-account fields (private_key, client_email,
|
|
25
|
+
* private_key_id, client_id, client_x509_cert_url) BEFORE splitting
|
|
26
|
+
* (service-account blobs embed PEM blocks as \\n-encoded strings; masking
|
|
27
|
+
* first prevents the BEGIN marker from appearing on its own line and dropping
|
|
28
|
+
* surrounding fields).
|
|
29
|
+
* 2. Split on \\n.
|
|
30
|
+
* 3. Remove PEM private-key blocks structurally (BEGIN…END inclusive,
|
|
31
|
+
* case-insensitive; a no-END block drops to end of entry).
|
|
32
|
+
* 4. For each surviving line: mask URL creds, KEY=secret, prefixed tokens,
|
|
33
|
+
* high-entropy/shape-based token runs.
|
|
34
|
+
* 5. Rejoin with \\n.
|
|
35
|
+
*/
|
|
36
|
+
declare function scrubSecrets(line: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Redact a log line and truncate to the heartbeat wire contract (256 chars).
|
|
39
|
+
* This is the heartbeat-egress variant: scrub secrets, then truncate AFTER
|
|
40
|
+
* masking so a token straddling char 256 is masked, not left partially visible.
|
|
41
|
+
*
|
|
42
|
+
* The app's heartbeat schema enforces message .max(256); a 257-char string
|
|
43
|
+
* would fail zod .parse and drop the whole heartbeat. Reserve one char for the
|
|
44
|
+
* ellipsis so the TOTAL length is at most MAX_LENGTH (256).
|
|
45
|
+
*/
|
|
46
|
+
declare function redactLine(line: string): string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Log levels from most to least severe
|
|
50
|
+
*/
|
|
51
|
+
declare enum Level {
|
|
52
|
+
ERROR = 0,
|
|
53
|
+
WARN = 1,
|
|
54
|
+
INFO = 2,
|
|
55
|
+
DEBUG = 3
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Normalized error context extracted from Error objects
|
|
59
|
+
*/
|
|
60
|
+
interface ErrorContext {
|
|
61
|
+
message: string;
|
|
62
|
+
name: string;
|
|
63
|
+
stack?: string;
|
|
64
|
+
cause?: unknown;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Context passed to log handlers
|
|
68
|
+
* If an Error was passed, it's normalized into the error property
|
|
69
|
+
*/
|
|
70
|
+
interface LogContext {
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
error?: ErrorContext;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log message function signature
|
|
76
|
+
* Accepts string or Error as message, with optional context
|
|
77
|
+
*/
|
|
78
|
+
type LogFn = (message: string | Error, context?: unknown | Error) => void;
|
|
79
|
+
/**
|
|
80
|
+
* Throw function signature - logs error then throws
|
|
81
|
+
* Returns never as it always throws
|
|
82
|
+
*/
|
|
83
|
+
type ThrowFn = (message: string | Error, context?: unknown) => never;
|
|
84
|
+
/**
|
|
85
|
+
* Default handler function (passed to custom handlers for chaining)
|
|
86
|
+
*/
|
|
87
|
+
type DefaultHandler = (level: Level, message: string, context: LogContext, scope: string[]) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Custom log handler function
|
|
90
|
+
* Receives originalHandler to allow middleware-style chaining
|
|
91
|
+
*/
|
|
92
|
+
type Handler = (level: Level, message: string, context: LogContext, scope: string[], originalHandler: DefaultHandler) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Logger instance with scoping support
|
|
95
|
+
* All logs automatically include trace path from scoping
|
|
96
|
+
*/
|
|
97
|
+
interface Instance {
|
|
98
|
+
/**
|
|
99
|
+
* Log an error message (always visible unless silenced)
|
|
100
|
+
*/
|
|
101
|
+
error: LogFn;
|
|
102
|
+
/**
|
|
103
|
+
* Log a warning (degraded state, config issues, transient failures)
|
|
104
|
+
*/
|
|
105
|
+
warn: LogFn;
|
|
106
|
+
/**
|
|
107
|
+
* Log an informational message
|
|
108
|
+
*/
|
|
109
|
+
info: LogFn;
|
|
110
|
+
/**
|
|
111
|
+
* Log a debug message
|
|
112
|
+
*/
|
|
113
|
+
debug: LogFn;
|
|
114
|
+
/**
|
|
115
|
+
* Log an error message and throw an Error
|
|
116
|
+
* Combines logging and throwing in one call
|
|
117
|
+
*/
|
|
118
|
+
throw: ThrowFn;
|
|
119
|
+
/**
|
|
120
|
+
* Output structured JSON data
|
|
121
|
+
*/
|
|
122
|
+
json: (data: unknown) => void;
|
|
123
|
+
/**
|
|
124
|
+
* Create a scoped child logger with automatic trace path
|
|
125
|
+
* @param name - Scope name (e.g., destination type, destination key)
|
|
126
|
+
* @returns A new logger instance with the scope applied
|
|
127
|
+
*/
|
|
128
|
+
scope: (name: string) => Instance;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Logger configuration options
|
|
132
|
+
*/
|
|
133
|
+
interface Config {
|
|
134
|
+
/**
|
|
135
|
+
* Minimum log level to display
|
|
136
|
+
* @default Level.ERROR
|
|
137
|
+
*/
|
|
138
|
+
level?: Level | keyof typeof Level;
|
|
139
|
+
/**
|
|
140
|
+
* Custom log handler function
|
|
141
|
+
* Receives originalHandler to preserve default behavior
|
|
142
|
+
*/
|
|
143
|
+
handler?: Handler;
|
|
144
|
+
/** Custom handler for json() output. Default: console.log(JSON.stringify(data, null, 2)) */
|
|
145
|
+
jsonHandler?: (data: unknown) => void;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Node entry point (`@walkeros/core/node`).
|
|
150
|
+
*
|
|
151
|
+
* Helpers shared by `@walkeros/cli` and `@walkeros/runner` that do not belong
|
|
152
|
+
* in the browser `.` entry: the temp-path helpers import node builtins, the
|
|
153
|
+
* terminal logger config writes to the console, and the secret redactor has
|
|
154
|
+
* no browser consumer (in `.` it was not tree-shaken out of walker.js). Core gains no dependency
|
|
155
|
+
* for them: the colouriser is injected by the caller, so chalk stays in the
|
|
156
|
+
* packages that already depend on it.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get a path within the temp directory.
|
|
161
|
+
*
|
|
162
|
+
* @param tmpDir - Custom temp directory (optional, for --tmp-dir flag)
|
|
163
|
+
* @param segments - Path segments to join
|
|
164
|
+
* @returns Absolute path within temp directory
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* getTmpPath() // → "/tmp"
|
|
169
|
+
* getTmpPath(undefined, 'entry.js') // → "/tmp/entry.js"
|
|
170
|
+
* getTmpPath(undefined, 'cache', 'builds') // → "/tmp/cache/builds"
|
|
171
|
+
* getTmpPath('/custom', 'cache') // → "/custom/cache"
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare function getTmpPath(tmpDir?: string, ...segments: string[]): string;
|
|
175
|
+
/**
|
|
176
|
+
* A temp path resolver with the root directory baked in.
|
|
177
|
+
*
|
|
178
|
+
* Use {@link createTmpResolver} at entry points to capture the temp root once,
|
|
179
|
+
* then pass the resolver to downstream functions. This prevents the class of
|
|
180
|
+
* bugs where callers forget to pass tmpDir.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const tmp = createTmpResolver(buildOptions.tempDir);
|
|
185
|
+
* const cacheDir = tmp('cache', 'packages'); // root is baked in
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
type TmpResolver = (...segments: string[]) => string;
|
|
189
|
+
declare function createTmpResolver(tmpDir?: string): TmpResolver;
|
|
190
|
+
/**
|
|
191
|
+
* Get the default temp root directory.
|
|
192
|
+
*/
|
|
193
|
+
declare function getDefaultTmpRoot(): string;
|
|
194
|
+
interface CLILoggerOptions {
|
|
195
|
+
verbose?: boolean;
|
|
196
|
+
silent?: boolean;
|
|
197
|
+
json?: boolean;
|
|
198
|
+
stderr?: boolean;
|
|
199
|
+
onLine?: (level: Level, message: string) => void;
|
|
200
|
+
}
|
|
201
|
+
/** Formats one already-scrubbed line for the terminal. */
|
|
202
|
+
type LineFormatter = (line: string) => string;
|
|
203
|
+
/**
|
|
204
|
+
* Per-level terminal formatters. Every level defaults to identity, so a caller
|
|
205
|
+
* that passes nothing gets plain uncoloured output.
|
|
206
|
+
*/
|
|
207
|
+
interface CLILoggerColors {
|
|
208
|
+
error?: LineFormatter;
|
|
209
|
+
warn?: LineFormatter;
|
|
210
|
+
info?: LineFormatter;
|
|
211
|
+
debug?: LineFormatter;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Build the `Logger.Config` (level + handler + jsonHandler) that backs a
|
|
215
|
+
* terminal logger. Returned separately so the runtime can hand the SAME
|
|
216
|
+
* handler (including the `onLine` ring tap) to the deployed bundle's
|
|
217
|
+
* collector.
|
|
218
|
+
*
|
|
219
|
+
* The collector in a deployed bundle builds its own logger from this config
|
|
220
|
+
* (`config.logger`), so its destination errors flow through the identical
|
|
221
|
+
* `onLine` tap the runtime logger uses, landing in the shared ErrorRing.
|
|
222
|
+
* There is no parallel ring: one handler, one tap.
|
|
223
|
+
*
|
|
224
|
+
* Level: `Level.DEBUG` so the handler sees every line and controls visibility
|
|
225
|
+
* itself (verbose/silent gating). ERROR is therefore always emitted into the
|
|
226
|
+
* ring regardless of `--verbose`.
|
|
227
|
+
*
|
|
228
|
+
* `colors` formats each level for the terminal. It is applied to console
|
|
229
|
+
* output only, never to the line handed to `onLine`.
|
|
230
|
+
*/
|
|
231
|
+
declare function createCLILoggerConfig(options?: CLILoggerOptions, colors?: CLILoggerColors): Config;
|
|
232
|
+
/**
|
|
233
|
+
* Create a core Logger.Instance with terminal-appropriate behavior.
|
|
234
|
+
*
|
|
235
|
+
* Behavior:
|
|
236
|
+
* - ERROR: always shown (via console.error, `colors.error`) unless --json
|
|
237
|
+
* - WARN: shown unless --silent or --json
|
|
238
|
+
* - INFO: shown unless --silent or --json
|
|
239
|
+
* - DEBUG: shown only with --verbose (and not --silent/--json)
|
|
240
|
+
* - json(): shown unless --silent
|
|
241
|
+
*/
|
|
242
|
+
declare function createCLILogger(options?: CLILoggerOptions, colors?: CLILoggerColors): Instance;
|
|
243
|
+
|
|
244
|
+
export { type CLILoggerColors, type CLILoggerOptions, type LineFormatter, type TmpResolver, createCLILogger, createCLILoggerConfig, createTmpResolver, getDefaultTmpRoot, getTmpPath, redactLine, scrubSecrets };
|
package/dist/node.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e,t=Object.create,r=Object.defineProperty,n=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,c=(e,t,s,c)=>{if(t&&"object"==typeof t||"function"==typeof t)for(let a of o(t))l.call(e,a)||a===s||r(e,a,{get:()=>t[a],enumerable:!(c=n(t,a))||c.enumerable});return e},a=(e,n,o)=>(o=null!=e?t(s(e)):{},c(!n&&e&&e.__esModule?o:r(o,"default",{value:e,enumerable:!0}),e)),i={};((e,t)=>{for(var n in t)r(e,n,{get:t[n],enumerable:!0})})(i,{createCLILogger:()=>q,createCLILoggerConfig:()=>J,createTmpResolver:()=>C,getDefaultTmpRoot:()=>F,getTmpPath:()=>B,redactLine:()=>S,scrubSecrets:()=>M}),module.exports=(e=i,c(r({},"__esModule",{value:!0}),e));var u=a(require("os")),f=a(require("path")),g=(e=>(e[e.ERROR=0]="ERROR",e[e.WARN=1]="WARN",e[e.INFO=2]="INFO",e[e.DEBUG=3]="DEBUG",e))(g||{});function p(e){return{message:e.message,name:e.name,stack:e.stack,cause:e.cause}}function d(e,t){let r,n={};return e instanceof Error?(r=e.message,n.error=p(e)):r=e,void 0!==t&&(t instanceof Error?n.error=p(t):"object"==typeof t&&null!==t?(n={...n,...t},"error"in n&&n.error instanceof Error&&(n.error=p(n.error))):n.value=t),{message:r,context:n}}var v=(e,t,r,n)=>{const o=`${g[e]}${n.length>0?` [${n.join(":")}]`:""}`,s=Object.keys(r).length>0,l=0===e?console.error:1===e?console.warn:console.log;s?l(o,t,r):l(o,t)};function h(e={}){return m({level:void 0!==e.level?function(e){return"string"==typeof e?g[e]:e}(e.level):0,handler:e.handler,jsonHandler:e.jsonHandler,scope:[]})}function m(e){const{level:t,handler:r,jsonHandler:n,scope:o}=e,s=(e,n,s)=>{if(e<=t){const t=d(n,s);r?r(e,t.message,t.context,o,v):v(e,t.message,t.context,o)}};return{error:(e,t)=>s(0,e,t),warn:(e,t)=>s(1,e,t),info:(e,t)=>s(2,e,t),debug:(e,t)=>s(3,e,t),throw:(e,t)=>{const n=d(e,t);throw r?r(0,n.message,n.context,o,v):v(0,n.message,n.context,o),new Error(n.message)},json:e=>{n?n(e):console.log(JSON.stringify(e,null,2))},scope:e=>m({level:t,handler:r,jsonHandler:n,scope:[...o,e]})}}var j=256,$=20,b=4,y=/(:\/\/[^/:@\s]+:)[^@\s]+(@)/g,O=/("(?:private_key|client_email|private_key_id|client_id|client_x509_cert_url)"\s*:\s*)"[^"]*"/g,_=/^\s*-----BEGIN [A-Z ]*PRIVATE KEY-----/i,x=/-----END[A-Z -]*-----/i,E="[A-Za-z0-9+/._-]",A=new RegExp(`(^|\\s)([A-Za-z_][A-Za-z0-9_.]{0,63}\\s*[=:]\\s*)(${E}{12,}={0,2})`,"g"),R=new RegExp(`${E}{${$},}`,"g");var w=["sk-","sk_","pk_","ghp_","gho_","xoxb-","xoxp-","AKIA"].sort((e,t)=>t.length-e.length).map(function(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}).join("|"),N=new RegExp(`(?:${w})${E}*`,"g");var k=/^[0-9a-fA-F]+$/,I=/^[0-9]+$/,P=/[+=]/,L=/[0-9]/,Z=/[A-Za-z]/;function z(e){return!!k.test(e)||(!!I.test(e)||(!!P.test(e)||(!(!L.test(e)||!Z.test(e))||function(e){if(0===e.length)return 0;const t=new Map;for(const r of e)t.set(r,(t.get(r)??0)+1);let r=0;for(const n of t.values()){const t=n/e.length;r-=t*Math.log2(t)}return r}(e)>=b)))}function D(e){return e.includes("/")?e.split("/").filter(e=>e.length>=$).some(z):z(e)}function H(e){let t=e;return t=t.replace(y,"$1***$2"),t=t.replace(A,(e,t,r,n)=>D(n)?`${t}${r}***`:e),t=t.replace(N,"***"),t=t.replace(R,e=>D(e)?"***":e),t}function M(e){return function(e){const t=[];let r=!1;for(const n of e)if(r)x.test(n)&&(r=!1);else{if(_.test(n)){r=!0;continue}t.push(n)}return t}(e.replace(O,'$1"***"').split("\n")).map(H).join("\n")}function S(e){const t=M(e);return t.length>j?t.slice(0,j-1)+"…":t}var T=u.default.tmpdir();function B(e,...t){const r=e||T,n=f.default.isAbsolute(r)?r:f.default.resolve(r);return f.default.join(n,...t)}function C(e){const t=e||T,r=f.default.isAbsolute(t)?t:f.default.resolve(t);return(...e)=>f.default.join(r,...e)}function F(){return T}var G=e=>e;function J(e={},t={}){const{verbose:r=!1,silent:n=!1,json:o=!1,stderr:s=!1}=e,l=s?console.error:console.log,c=t.error??G,a=t.warn??G,i=t.info??G,u=t.debug??G;return{level:3,handler:(t,s,f,g)=>{const p=g.length>0?`[${g.join(":")}] `:"";let d="";if(Object.keys(f).length>0)try{d=` ${JSON.stringify(f)}`}catch{d=" [unserializable context]"}const v=M(`${p}${s}${d}`);try{e.onLine?.(t,v)}catch{}if(0!==t){if(!n&&!o)if(3!==t)l(1===t?a(v):i(v));else{if(!r)return;l(` ${u(v)}`)}}else o||console.error(c(v))},jsonHandler:e=>{n||l(JSON.stringify(e,null,2))}}}function q(e={},t={}){return h(J(e,t))}//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/node.ts","../src/types/logger.ts","../src/logger.ts","../src/redactLine.ts"],"sourcesContent":["/**\n * Node entry point (`@walkeros/core/node`).\n *\n * Helpers shared by `@walkeros/cli` and `@walkeros/runner` that do not belong\n * in the browser `.` entry: the temp-path helpers import node builtins, the\n * terminal logger config writes to the console, and the secret redactor has\n * no browser consumer (in `.` it was not tree-shaken out of walker.js). Core gains no dependency\n * for them: the colouriser is injected by the caller, so chalk stays in the\n * packages that already depend on it.\n */\n\n/* eslint-disable no-console */\nimport os from 'os';\nimport path from 'path';\nimport { createLogger } from './logger';\nimport { scrubSecrets } from './redactLine';\n\nexport { scrubSecrets, redactLine } from './redactLine';\nimport type { Config, Instance } from './types/logger';\nimport { Level } from './types/logger';\n\nconst DEFAULT_TMP_ROOT = os.tmpdir();\n\n/**\n * Get a path within the temp directory.\n *\n * @param tmpDir - Custom temp directory (optional, for --tmp-dir flag)\n * @param segments - Path segments to join\n * @returns Absolute path within temp directory\n *\n * @example\n * ```typescript\n * getTmpPath() // → \"/tmp\"\n * getTmpPath(undefined, 'entry.js') // → \"/tmp/entry.js\"\n * getTmpPath(undefined, 'cache', 'builds') // → \"/tmp/cache/builds\"\n * getTmpPath('/custom', 'cache') // → \"/custom/cache\"\n * ```\n */\nexport function getTmpPath(tmpDir?: string, ...segments: string[]): string {\n const root = tmpDir || DEFAULT_TMP_ROOT;\n // Always return absolute path (esbuild requirement)\n const absoluteRoot = path.isAbsolute(root) ? root : path.resolve(root);\n return path.join(absoluteRoot, ...segments);\n}\n\n/**\n * A temp path resolver with the root directory baked in.\n *\n * Use {@link createTmpResolver} at entry points to capture the temp root once,\n * then pass the resolver to downstream functions. This prevents the class of\n * bugs where callers forget to pass tmpDir.\n *\n * @example\n * ```typescript\n * const tmp = createTmpResolver(buildOptions.tempDir);\n * const cacheDir = tmp('cache', 'packages'); // root is baked in\n * ```\n */\nexport type TmpResolver = (...segments: string[]) => string;\n\nexport function createTmpResolver(tmpDir?: string): TmpResolver {\n const root = tmpDir || DEFAULT_TMP_ROOT;\n const absoluteRoot = path.isAbsolute(root) ? root : path.resolve(root);\n return (...segments: string[]) => path.join(absoluteRoot, ...segments);\n}\n\n/**\n * Get the default temp root directory.\n */\nexport function getDefaultTmpRoot(): string {\n return DEFAULT_TMP_ROOT;\n}\n\nexport interface CLILoggerOptions {\n verbose?: boolean;\n silent?: boolean;\n json?: boolean;\n stderr?: boolean;\n onLine?: (level: Level, message: string) => void;\n}\n\n/** Formats one already-scrubbed line for the terminal. */\nexport type LineFormatter = (line: string) => string;\n\n/**\n * Per-level terminal formatters. Every level defaults to identity, so a caller\n * that passes nothing gets plain uncoloured output.\n */\nexport interface CLILoggerColors {\n error?: LineFormatter;\n warn?: LineFormatter;\n info?: LineFormatter;\n debug?: LineFormatter;\n}\n\nconst identity: LineFormatter = (line) => line;\n\n/**\n * Build the `Logger.Config` (level + handler + jsonHandler) that backs a\n * terminal logger. Returned separately so the runtime can hand the SAME\n * handler (including the `onLine` ring tap) to the deployed bundle's\n * collector.\n *\n * The collector in a deployed bundle builds its own logger from this config\n * (`config.logger`), so its destination errors flow through the identical\n * `onLine` tap the runtime logger uses, landing in the shared ErrorRing.\n * There is no parallel ring: one handler, one tap.\n *\n * Level: `Level.DEBUG` so the handler sees every line and controls visibility\n * itself (verbose/silent gating). ERROR is therefore always emitted into the\n * ring regardless of `--verbose`.\n *\n * `colors` formats each level for the terminal. It is applied to console\n * output only, never to the line handed to `onLine`.\n */\nexport function createCLILoggerConfig(\n options: CLILoggerOptions = {},\n colors: CLILoggerColors = {},\n): Config {\n const {\n verbose = false,\n silent = false,\n json = false,\n stderr = false,\n } = options;\n const out = stderr ? console.error : console.log;\n const errorColor = colors.error ?? identity;\n const warnColor = colors.warn ?? identity;\n const infoColor = colors.info ?? identity;\n const debugColor = colors.debug ?? identity;\n\n return {\n // Let handler control visibility: pass everything through. With the gate\n // at DEBUG, ERROR always reaches the handler (and the ring) even without\n // --verbose.\n level: Level.DEBUG,\n handler: (level, message, context, scope) => {\n // Build formatted message\n const scopePath = scope.length > 0 ? `[${scope.join(':')}] ` : '';\n // Serialize the structured context into the line so error details (gRPC\n // status codes, row counts, target tables) reach stderr and the ring.\n // Serialization happens BEFORE scrubSecrets so redaction covers context\n // values too; the heartbeat path's 256-char cap stays as the wire\n // backstop. A context that cannot stringify (circular) must never break\n // logging.\n let meta = '';\n if (Object.keys(context).length > 0) {\n try {\n meta = ` ${JSON.stringify(context)}`;\n } catch {\n meta = ' [unserializable context]';\n }\n }\n // Redact secrets ONCE here, before BOTH the onLine ring tap and the\n // console.* output. stderr is shipped directly by the log collector, so\n // the heartbeat-egress redactor alone would miss it; doing it in the\n // handler scrubs every line routed through this logger (collector and\n // steps) on both paths. Length is preserved here (no truncation); the\n // heartbeat path applies the 256-char wire cap separately as a backstop\n // on already-redacted text.\n const fullMessage = scrubSecrets(`${scopePath}${message}${meta}`);\n\n // Tap every line before any early return so no level is dropped from capture.\n try {\n options.onLine?.(level, fullMessage);\n } catch {\n // Swallow: a throwing consumer must never break logging (and we must\n // not call logger methods here to avoid infinite recursion).\n }\n\n // ERROR: always shown unless json mode\n if (level === Level.ERROR) {\n if (!json) console.error(errorColor(fullMessage));\n return;\n }\n\n // Non-errors suppressed in silent or json mode\n if (silent || json) return;\n\n // DEBUG: only with verbose\n if (level === Level.DEBUG) {\n if (!verbose) return;\n out(` ${debugColor(fullMessage)}`);\n return;\n }\n\n // WARN / INFO: normal output\n out(\n level === Level.WARN ? warnColor(fullMessage) : infoColor(fullMessage),\n );\n },\n jsonHandler: (data) => {\n if (!silent) out(JSON.stringify(data, null, 2));\n },\n };\n}\n\n/**\n * Create a core Logger.Instance with terminal-appropriate behavior.\n *\n * Behavior:\n * - ERROR: always shown (via console.error, `colors.error`) unless --json\n * - WARN: shown unless --silent or --json\n * - INFO: shown unless --silent or --json\n * - DEBUG: shown only with --verbose (and not --silent/--json)\n * - json(): shown unless --silent\n */\nexport function createCLILogger(\n options: CLILoggerOptions = {},\n colors: CLILoggerColors = {},\n): Instance {\n return createLogger(createCLILoggerConfig(options, colors));\n}\n","/**\n * Log levels from most to least severe\n */\nexport enum Level {\n ERROR = 0,\n WARN = 1,\n INFO = 2,\n DEBUG = 3,\n}\n\n/**\n * Normalized error context extracted from Error objects\n */\nexport interface ErrorContext {\n message: string;\n name: string;\n stack?: string;\n cause?: unknown;\n}\n\n/**\n * Context passed to log handlers\n * If an Error was passed, it's normalized into the error property\n */\nexport interface LogContext {\n [key: string]: unknown;\n error?: ErrorContext;\n}\n\n/**\n * Log message function signature\n * Accepts string or Error as message, with optional context\n */\nexport type LogFn = (\n message: string | Error,\n context?: unknown | Error,\n) => void;\n\n/**\n * Throw function signature - logs error then throws\n * Returns never as it always throws\n */\nexport type ThrowFn = (message: string | Error, context?: unknown) => never;\n\n/**\n * Default handler function (passed to custom handlers for chaining)\n */\nexport type DefaultHandler = (\n level: Level,\n message: string,\n context: LogContext,\n scope: string[],\n) => void;\n\n/**\n * Custom log handler function\n * Receives originalHandler to allow middleware-style chaining\n */\nexport type Handler = (\n level: Level,\n message: string,\n context: LogContext,\n scope: string[],\n originalHandler: DefaultHandler,\n) => void;\n\n/**\n * Logger instance with scoping support\n * All logs automatically include trace path from scoping\n */\nexport interface Instance {\n /**\n * Log an error message (always visible unless silenced)\n */\n error: LogFn;\n\n /**\n * Log a warning (degraded state, config issues, transient failures)\n */\n warn: LogFn;\n\n /**\n * Log an informational message\n */\n info: LogFn;\n\n /**\n * Log a debug message\n */\n debug: LogFn;\n\n /**\n * Log an error message and throw an Error\n * Combines logging and throwing in one call\n */\n throw: ThrowFn;\n\n /**\n * Output structured JSON data\n */\n json: (data: unknown) => void;\n\n /**\n * Create a scoped child logger with automatic trace path\n * @param name - Scope name (e.g., destination type, destination key)\n * @returns A new logger instance with the scope applied\n */\n scope: (name: string) => Instance;\n}\n\n/**\n * Logger configuration options\n */\nexport interface Config {\n /**\n * Minimum log level to display\n * @default Level.ERROR\n */\n level?: Level | keyof typeof Level;\n\n /**\n * Custom log handler function\n * Receives originalHandler to preserve default behavior\n */\n handler?: Handler;\n\n /** Custom handler for json() output. Default: console.log(JSON.stringify(data, null, 2)) */\n jsonHandler?: (data: unknown) => void;\n}\n\n/**\n * Internal config with resolved values and scope\n */\nexport interface InternalConfig {\n level: Level;\n handler?: Handler;\n jsonHandler?: (data: unknown) => void;\n scope: string[];\n}\n\n/**\n * Logger factory function type\n */\nexport type Factory = (config?: Config) => Instance;\n","import type {\n Config,\n DefaultHandler,\n ErrorContext,\n Handler,\n Instance,\n InternalConfig,\n LogContext,\n} from './types/logger';\nimport { Level } from './types/logger';\n\n/**\n * Normalize an Error object into ErrorContext\n */\nfunction normalizeError(err: Error): ErrorContext {\n return {\n message: err.message,\n name: err.name,\n stack: err.stack,\n cause: (err as Error & { cause?: unknown }).cause,\n };\n}\n\n/**\n * Normalize message and context parameters\n * Handles Error objects passed as message or context\n */\nfunction normalizeParams(\n message: string | Error,\n context?: unknown | Error,\n): { message: string; context: LogContext } {\n let normalizedMessage: string;\n let normalizedContext: LogContext = {};\n\n // Handle message\n if (message instanceof Error) {\n normalizedMessage = message.message;\n normalizedContext.error = normalizeError(message);\n } else {\n normalizedMessage = message;\n }\n\n // Handle context\n if (context !== undefined) {\n if (context instanceof Error) {\n normalizedContext.error = normalizeError(context);\n } else if (typeof context === 'object' && context !== null) {\n normalizedContext = { ...normalizedContext, ...(context as object) };\n // If context has an error property that's an Error, normalize it\n if (\n 'error' in normalizedContext &&\n normalizedContext.error instanceof Error\n ) {\n normalizedContext.error = normalizeError(\n normalizedContext.error as unknown as Error,\n );\n }\n } else {\n normalizedContext.value = context;\n }\n }\n\n return { message: normalizedMessage, context: normalizedContext };\n}\n\n/**\n * Default console-based log handler\n */\nconst defaultHandler: DefaultHandler = (level, message, context, scope) => {\n const levelName = Level[level];\n const scopePath = scope.length > 0 ? ` [${scope.join(':')}]` : '';\n const prefix = `${levelName}${scopePath}`;\n\n const hasContext = Object.keys(context).length > 0;\n\n const consoleFn =\n level === Level.ERROR\n ? console.error\n : level === Level.WARN\n ? console.warn\n : console.log;\n\n if (hasContext) {\n consoleFn(prefix, message, context);\n } else {\n consoleFn(prefix, message);\n }\n};\n\n/**\n * Normalize log level from string or enum to enum value\n */\nfunction normalizeLevel(level: Level | keyof typeof Level): Level {\n if (typeof level === 'string') {\n return Level[level as keyof typeof Level];\n }\n return level;\n}\n\n/**\n * Create a logger instance\n *\n * @param config - Logger configuration\n * @returns Logger instance with all log methods and scoping support\n *\n * @example\n * ```typescript\n * // Basic usage\n * const logger = createLogger({ level: 'DEBUG' });\n * logger.info('Hello world');\n *\n * // With scoping\n * const destLogger = logger.scope('gtag').scope('myInstance');\n * destLogger.debug('Processing event'); // DEBUG [gtag:myInstance] Processing event\n *\n * // With custom handler\n * const logger = createLogger({\n * handler: (level, message, context, scope, originalHandler) => {\n * // Custom logic (e.g., send to Sentry)\n * originalHandler(level, message, context, scope);\n * }\n * });\n * ```\n *\n * // TODO: Consider compile-time stripping of debug logs in production builds\n * // e.g., if (__DEV__) { logger.debug(...) }\n */\nexport function createLogger(config: Config = {}): Instance {\n const level =\n config.level !== undefined ? normalizeLevel(config.level) : Level.ERROR;\n const customHandler = config.handler;\n const jsonHandler = config.jsonHandler;\n const scope: string[] = [];\n\n return createLoggerInternal({\n level,\n handler: customHandler,\n jsonHandler,\n scope,\n });\n}\n\n/**\n * Internal logger creation with resolved config\n */\nfunction createLoggerInternal(config: InternalConfig): Instance {\n const { level, handler, jsonHandler, scope } = config;\n\n /**\n * Internal log function that checks level and delegates to handler\n */\n const log = (\n logLevel: Level,\n message: string | Error,\n context?: unknown | Error,\n ): void => {\n if (logLevel <= level) {\n const normalized = normalizeParams(message, context);\n\n if (handler) {\n // Custom handler with access to default handler\n handler(\n logLevel,\n normalized.message,\n normalized.context,\n scope,\n defaultHandler,\n );\n } else {\n defaultHandler(logLevel, normalized.message, normalized.context, scope);\n }\n }\n };\n\n /**\n * Log and throw - combines logging and throwing\n */\n const logAndThrow = (message: string | Error, context?: unknown): never => {\n // Always log errors regardless of level\n const normalized = normalizeParams(message, context);\n\n if (handler) {\n handler(\n Level.ERROR,\n normalized.message,\n normalized.context,\n scope,\n defaultHandler,\n );\n } else {\n defaultHandler(\n Level.ERROR,\n normalized.message,\n normalized.context,\n scope,\n );\n }\n\n // Throw with the message\n throw new Error(normalized.message);\n };\n\n return {\n error: (message, context) => log(Level.ERROR, message, context),\n warn: (message, context) => log(Level.WARN, message, context),\n info: (message, context) => log(Level.INFO, message, context),\n debug: (message, context) => log(Level.DEBUG, message, context),\n throw: logAndThrow,\n json: (data: unknown) => {\n if (jsonHandler) {\n jsonHandler(data);\n } else {\n // eslint-disable-next-line no-console\n console.log(JSON.stringify(data, null, 2));\n }\n },\n scope: (name: string) =>\n createLoggerInternal({\n level,\n handler,\n jsonHandler,\n scope: [...scope, name],\n }),\n };\n}\n\n// Re-export Level enum for convenience\nexport { Level };\n","/**\n * Shared secret redactor. One set of patterns for every path that egresses a\n * log line: the CLI logger handler and the runtime logger handler (scrubbing\n * console and the error ring), and the runtime heartbeat (scrubbing the ring\n * snapshot before the POST). A pattern added here covers all of them.\n *\n * Two entry points:\n * - `scrubSecrets(line)`: mask secrets, keep the message length intact (for\n * console/stderr legibility).\n * - `redactLine(line)`: `scrubSecrets` plus truncation to the 256-char\n * heartbeat wire contract.\n *\n * All regex are linear (single unambiguous quantifiers, no nested quantifiers),\n * so there is no catastrophic backtracking even on a BEGIN-marker-with-no-END\n * input or a long no-space line. Exported from `@walkeros/core/node` only: no\n * browser consumer needs it, and it must not ride into web bundles.\n */\n\nconst MAX_LENGTH = 256;\n\n// Minimum length for a standalone run to be considered a candidate token.\nconst MIN_TOKEN_LEN = 20;\n\n// Shannon entropy threshold (bits/char). Random tokens score high (~4.5-6),\n// natural-language words and identifiers score low (~2-3.5).\nconst ENTROPY_THRESHOLD = 4.0;\n\n// Known secret prefixes that force-mask their run regardless of entropy/shape.\nconst FORCE_MASK_PREFIXES = [\n 'sk-',\n 'sk_',\n 'pk_',\n 'ghp_',\n 'gho_',\n 'xoxb-',\n 'xoxp-',\n 'AKIA',\n];\n\n// ── Regex constants (all linear, no nested quantifiers) ─────────────────────\n\n// URL credentials: scheme://user:password@host, keep user, mask password.\nconst RE_URL_CREDS = /(:\\/\\/[^/:@\\s]+:)[^@\\s]+(@)/g;\n\n// JSON service-account field values, catches service-account blobs.\n// `private_key` holds the PEM body; `client_email`, `private_key_id`,\n// `client_id`, and `client_x509_cert_url` identify and pair with the leaked\n// credential and must not ship either (the cert url embeds the URL-encoded\n// client email). Naming them explicitly beats relying on the token-run\n// heuristics, which can miss an email or a URL. The value may contain escaped\n// newlines (\\n as literal backslash-n) which do not split the line. [^\"] is\n// safe: these values contain no embedded quotes. One alternation over the field\n// names keeps the scan single-pass and linear.\nconst RE_JSON_SA_FIELD =\n /(\"(?:private_key|client_email|private_key_id|client_id|client_x509_cert_url)\"\\s*:\\s*)\"[^\"]*\"/g;\n\n// PEM block boundaries (structural removal, not regex masking).\n// Case-insensitive, tolerate leading whitespace so a lowercase or indented\n// `-----begin private key-----` block does not leak its body.\nconst RE_PEM_BEGIN = /^\\s*-----BEGIN [A-Z ]*PRIVATE KEY-----/i;\nconst RE_PEM_END = /-----END[A-Z -]*-----/i;\n\n// KEY=value / KEY: value secret pattern.\n// ReDoS-safe: the key is anchored to start-of-line or whitespace and bounded to\n// 64 chars ({0,63} after the first char), so there is no O(n²) backtracking on\n// long no-space lines. The value class includes - and . so hyphenated/dotted\n// tokens are captured whole. Two capture groups are preserved in the\n// replacement: the leading (^|\\s) boundary and the key=.\nconst TOKEN_VALUE_CLASS = '[A-Za-z0-9+/._-]';\nconst RE_KV_SECRET = new RegExp(\n `(^|\\\\s)([A-Za-z_][A-Za-z0-9_.]{0,63}\\\\s*[=:]\\\\s*)(${TOKEN_VALUE_CLASS}{12,}={0,2})`,\n 'g',\n);\n\n// Standalone candidate runs: any run of token chars (incl. - and .) ≥ 20.\n// The decision to mask happens in the callback (shouldMaskToken), keeping the\n// regex itself trivial and linear.\nconst RE_TOKEN_RUN = new RegExp(`${TOKEN_VALUE_CLASS}{${MIN_TOKEN_LEN},}`, 'g');\n\n// Force-mask prefix detector for runs that carry a known secret prefix.\n// Matches a known prefix followed by token chars (any length), so e.g.\n// `ghp_xxxxxxxx` or `xoxb-2384-2384-AbCdEf` is masked even under 20 chars.\n// Built from FORCE_MASK_PREFIXES so the list is the single source of truth.\n// Prefixes are regex-escaped (only `-`/`_` appear, both literal here, but escape\n// defensively) and ordered longest-first so the alternation is unambiguous.\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\nconst PREFIX_ALTERNATION = [...FORCE_MASK_PREFIXES]\n .sort((a, b) => b.length - a.length)\n .map(escapeRegex)\n .join('|');\nconst RE_PREFIXED_TOKEN = new RegExp(\n `(?:${PREFIX_ALTERNATION})${TOKEN_VALUE_CLASS}*`,\n 'g',\n);\n\n// ── Entropy ──────────────────────────────────────────────────────────────────\n\n/** Shannon entropy in bits per character. Linear in input length. */\nfunction shannonEntropy(s: string): number {\n if (s.length === 0) return 0;\n const counts = new Map<string, number>();\n for (const ch of s) counts.set(ch, (counts.get(ch) ?? 0) + 1);\n let entropy = 0;\n for (const count of counts.values()) {\n const p = count / s.length;\n entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\n// ── Token masking decision ─────────────────────────────────────────────────\n\nconst RE_ALL_HEX = /^[0-9a-fA-F]+$/;\nconst RE_ALL_DIGIT = /^[0-9]+$/;\n// Real base64 padding/special chars. `/` is intentionally EXCLUDED: it is a\n// structural path/URL separator (FQNs, gs:// paths, request paths, googleapis\n// URLs), not a secret signal. Since redaction now runs on every console line,\n// treating `/` as a secret char nuked legitimate BigQuery/GCS diagnostics. Real\n// base64 secrets still carry `+`/`=` padding, are all-hex, or are high-entropy.\nconst RE_BASE64_SPECIAL = /[+=]/;\nconst RE_HAS_DIGIT = /[0-9]/;\nconst RE_HAS_LETTER = /[A-Za-z]/;\n\n/**\n * Decide whether a candidate run (a single token, no `/`) is a secret to mask.\n *\n * Mask when ANY of:\n * - all-hex (digests, SHA, etc.)\n * - all-digit (numeric tokens/ids)\n * - contains a base64 special char (+ =)\n * - contains both a digit and a letter (mixed token)\n * - Shannon entropy ≥ 4.0 bits/char (random all-letter / mixed-case tokens)\n */\nfunction isSecretSegment(run: string): boolean {\n if (RE_ALL_HEX.test(run)) return true;\n if (RE_ALL_DIGIT.test(run)) return true;\n if (RE_BASE64_SPECIAL.test(run)) return true;\n if (RE_HAS_DIGIT.test(run) && RE_HAS_LETTER.test(run)) return true;\n if (shannonEntropy(run) >= ENTROPY_THRESHOLD) return true;\n return false;\n}\n\n/**\n * Decide whether a ≥20-char candidate run is a secret to mask.\n *\n * A run containing `/` is treated as a path/URL structure, not one opaque token.\n * Paths and URLs split into short alphanumeric segments (`v2`, `projects`,\n * `12345`), each of which trips the digit+letter or entropy heuristic on its own\n * even though the whole thing is legible diagnostics. So a `/`-bearing run is\n * masked only when one of its long (≥20-char) segments independently looks like\n * a secret (e.g. a base64 blob embedded in a URL path). A base64 secret with `/`\n * still carries `+`/`=` (handled per-segment) or is hex/high-entropy, so real\n * secrets remain masked while FQNs, gs:// paths, request paths, and googleapis\n * URLs survive.\n *\n * ACCEPTED best-effort limitation: a bare all-letters run with no digit, no\n * special char, no known prefix, and entropy < 4.0 (e.g. `supercalifragilistic`\n * or a long camelCase identifier like `getUserAccountSettings`) may pass through\n * unmasked. Masking every such run would destroy log readability by redacting\n * ordinary identifiers and words, which defeats the purpose of legible\n * diagnostics. This is a deliberate trade-off, not an oversight.\n */\nfunction shouldMaskToken(run: string): boolean {\n if (run.includes('/')) {\n // Per-segment: only mask if a long segment is itself secret-shaped. Short\n // path segments (the bulk of any URL) never qualify, keeping URLs legible.\n return run\n .split('/')\n .filter((segment) => segment.length >= MIN_TOKEN_LEN)\n .some(isSecretSegment);\n }\n return isSecretSegment(run);\n}\n\n// ── PEM block removal ────────────────────────────────────────────────────────\n\n/**\n * Remove all PEM private-key blocks from an array of lines.\n * A block starts at a BEGIN PRIVATE KEY marker and ends at the matching END\n * marker (inclusive). If no END is found, everything to end of entry is dropped.\n */\nfunction removePemBlocks(lines: string[]): string[] {\n const out: string[] = [];\n let inBlock = false;\n\n for (const line of lines) {\n if (!inBlock) {\n if (RE_PEM_BEGIN.test(line)) {\n inBlock = true;\n continue; // start-of-block line dropped\n }\n out.push(line);\n } else {\n if (RE_PEM_END.test(line)) {\n inBlock = false;\n }\n // drop every in-block line, including the END marker\n }\n }\n\n return out;\n}\n\n// ── Per-line secret masking ──────────────────────────────────────────────────\n\n/**\n * Mask secrets in a single (non-PEM) line.\n * All patterns are applied in order; all regex are linear (no nested quantifiers).\n */\nfunction maskLine(line: string): string {\n let s = line;\n\n // 1. URL credentials: ://user:secret@host → ://user:***@host\n s = s.replace(RE_URL_CREDS, '$1***$2');\n\n // 2. KEY=secret / KEY: secret (anchored, bounded key, ReDoS-safe).\n // Mask the value only when it is secret-shaped. This stops `scheme://host/...`\n // (matched as `gs:` / `https:` key + `//...` value) from masking legitimate\n // URLs/paths, while real `TOKEN=secret` values still mask. The `/`-aware\n // shouldMaskToken keeps path-shaped values legible.\n s = s.replace(\n RE_KV_SECRET,\n (match: string, boundary: string, keyPart: string, value: string) =>\n shouldMaskToken(value) ? `${boundary}${keyPart}***` : match,\n );\n\n // 3. Known-prefix tokens (force-mask regardless of length/entropy)\n s = s.replace(RE_PREFIXED_TOKEN, '***');\n\n // 4. Standalone candidate runs ≥ 20 chars, mask by shape/entropy\n s = s.replace(RE_TOKEN_RUN, (match) =>\n shouldMaskToken(match) ? '***' : match,\n );\n\n return s;\n}\n\n// ── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Scrub credential material from a log line (or multi-line entry) WITHOUT\n * truncating. This is the shared secret redactor used by the CLI logger handler\n * (covers console/stderr and the ring before egress).\n *\n * Algorithm:\n * 1. Mask JSON service-account fields (private_key, client_email,\n * private_key_id, client_id, client_x509_cert_url) BEFORE splitting\n * (service-account blobs embed PEM blocks as \\\\n-encoded strings; masking\n * first prevents the BEGIN marker from appearing on its own line and dropping\n * surrounding fields).\n * 2. Split on \\\\n.\n * 3. Remove PEM private-key blocks structurally (BEGIN…END inclusive,\n * case-insensitive; a no-END block drops to end of entry).\n * 4. For each surviving line: mask URL creds, KEY=secret, prefixed tokens,\n * high-entropy/shape-based token runs.\n * 5. Rejoin with \\\\n.\n */\nexport function scrubSecrets(line: string): string {\n // Step 1: JSON service-account field masking before any line splitting\n const withoutJsonKey = line.replace(RE_JSON_SA_FIELD, '$1\"***\"');\n\n // Step 2: split\n const rawLines = withoutJsonKey.split('\\n');\n\n // Step 3: remove PEM blocks (any remaining standalone markers after step 1)\n const cleanLines = removePemBlocks(rawLines);\n\n // Step 4: mask each surviving line\n const maskedLines = cleanLines.map(maskLine);\n\n // Step 5: rejoin\n return maskedLines.join('\\n');\n}\n\n/**\n * Redact a log line and truncate to the heartbeat wire contract (256 chars).\n * This is the heartbeat-egress variant: scrub secrets, then truncate AFTER\n * masking so a token straddling char 256 is masked, not left partially visible.\n *\n * The app's heartbeat schema enforces message .max(256); a 257-char string\n * would fail zod .parse and drop the whole heartbeat. Reserve one char for the\n * ellipsis so the TOTAL length is at most MAX_LENGTH (256).\n */\nexport function redactLine(line: string): string {\n const scrubbed = scrubSecrets(line);\n\n if (scrubbed.length > MAX_LENGTH) {\n return scrubbed.slice(0, MAX_LENGTH - 1) + '…';\n }\n\n return scrubbed;\n}\n"],"mappings":"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","names":["Level","os","path"]}
|
package/dist/node.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"os";import n from"path";var r=(e=>(e[e.ERROR=0]="ERROR",e[e.WARN=1]="WARN",e[e.INFO=2]="INFO",e[e.DEBUG=3]="DEBUG",e))(r||{});function t(e){return{message:e.message,name:e.name,stack:e.stack,cause:e.cause}}function o(e,n){let r,o={};return e instanceof Error?(r=e.message,o.error=t(e)):r=e,void 0!==n&&(n instanceof Error?o.error=t(n):"object"==typeof n&&null!==n?(o={...o,...n},"error"in o&&o.error instanceof Error&&(o.error=t(o.error))):o.value=n),{message:r,context:o}}var s=(e,n,t,o)=>{const s=`${r[e]}${o.length>0?` [${o.join(":")}]`:""}`,l=Object.keys(t).length>0,c=0===e?console.error:1===e?console.warn:console.log;l?c(s,n,t):c(s,n)};function l(e={}){return c({level:void 0!==e.level?function(e){return"string"==typeof e?r[e]:e}(e.level):0,handler:e.handler,jsonHandler:e.jsonHandler,scope:[]})}function c(e){const{level:n,handler:r,jsonHandler:t,scope:l}=e,i=(e,t,c)=>{if(e<=n){const n=o(t,c);r?r(e,n.message,n.context,l,s):s(e,n.message,n.context,l)}};return{error:(e,n)=>i(0,e,n),warn:(e,n)=>i(1,e,n),info:(e,n)=>i(2,e,n),debug:(e,n)=>i(3,e,n),throw:(e,n)=>{const t=o(e,n);throw r?r(0,t.message,t.context,l,s):s(0,t.message,t.context,l),new Error(t.message)},json:e=>{t?t(e):console.log(JSON.stringify(e,null,2))},scope:e=>c({level:n,handler:r,jsonHandler:t,scope:[...l,e]})}}var i=/(:\/\/[^/:@\s]+:)[^@\s]+(@)/g,a=/("(?:private_key|client_email|private_key_id|client_id|client_x509_cert_url)"\s*:\s*)"[^"]*"/g,u=/^\s*-----BEGIN [A-Z ]*PRIVATE KEY-----/i,f=/-----END[A-Z -]*-----/i,g="[A-Za-z0-9+/._-]",p=new RegExp(`(^|\\s)([A-Za-z_][A-Za-z0-9_.]{0,63}\\s*[=:]\\s*)(${g}{12,}={0,2})`,"g"),h=new RegExp(`${g}{20,}`,"g");var v=["sk-","sk_","pk_","ghp_","gho_","xoxb-","xoxp-","AKIA"].sort((e,n)=>n.length-e.length).map(function(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}).join("|"),$=new RegExp(`(?:${v})${g}*`,"g");var m=/^[0-9a-fA-F]+$/,d=/^[0-9]+$/,j=/[+=]/,x=/[0-9]/,E=/[A-Za-z]/;function _(e){return!!m.test(e)||(!!d.test(e)||(!!j.test(e)||(!(!x.test(e)||!E.test(e))||function(e){if(0===e.length)return 0;const n=new Map;for(const r of e)n.set(r,(n.get(r)??0)+1);let r=0;for(const t of n.values()){const n=t/e.length;r-=n*Math.log2(n)}return r}(e)>=4)))}function A(e){return e.includes("/")?e.split("/").filter(e=>e.length>=20).some(_):_(e)}function R(e){let n=e;return n=n.replace(i,"$1***$2"),n=n.replace(p,(e,n,r,t)=>A(t)?`${n}${r}***`:e),n=n.replace($,"***"),n=n.replace(h,e=>A(e)?"***":e),n}function y(e){return function(e){const n=[];let r=!1;for(const t of e)if(r)f.test(t)&&(r=!1);else{if(u.test(t)){r=!0;continue}n.push(t)}return n}(e.replace(a,'$1"***"').split("\n")).map(R).join("\n")}function b(e){const n=y(e);return n.length>256?n.slice(0,255)+"…":n}var w=e.tmpdir();function k(e,...r){const t=e||w,o=n.isAbsolute(t)?t:n.resolve(t);return n.join(o,...r)}function N(e){const r=e||w,t=n.isAbsolute(r)?r:n.resolve(r);return(...e)=>n.join(t,...e)}function O(){return w}var Z=e=>e;function z(e={},n={}){const{verbose:r=!1,silent:t=!1,json:o=!1,stderr:s=!1}=e,l=s?console.error:console.log,c=n.error??Z,i=n.warn??Z,a=n.info??Z,u=n.debug??Z;return{level:3,handler:(n,s,f,g)=>{const p=g.length>0?`[${g.join(":")}] `:"";let h="";if(Object.keys(f).length>0)try{h=` ${JSON.stringify(f)}`}catch{h=" [unserializable context]"}const v=y(`${p}${s}${h}`);try{e.onLine?.(n,v)}catch{}if(0!==n){if(!t&&!o)if(3!==n)l(1===n?i(v):a(v));else{if(!r)return;l(` ${u(v)}`)}}else o||console.error(c(v))},jsonHandler:e=>{t||l(JSON.stringify(e,null,2))}}}function H(e={},n={}){return l(z(e,n))}export{H as createCLILogger,z as createCLILoggerConfig,N as createTmpResolver,O as getDefaultTmpRoot,k as getTmpPath,b as redactLine,y as scrubSecrets};//# sourceMappingURL=node.mjs.map
|