@orkestrel/console 0.0.12 → 0.0.13

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.
@@ -1,8 +1,8 @@
1
- import { EmitterErrorHandler } from '@orkestrel/emitter';
2
- import { EmitterHooks } from '@orkestrel/emitter';
3
- import { EmitterInterface } from '@orkestrel/emitter';
4
- import { LogLevel } from '@orkestrel/console';
5
- import { SinkInterface } from '@orkestrel/console';
1
+ import type { EmitterErrorHandler } from '@orkestrel/emitter';
2
+ import type { EmitterHooks } from '@orkestrel/emitter';
3
+ import type { EmitterInterface } from '@orkestrel/emitter';
4
+ import type { LogLevel } from '@orkestrel/console';
5
+ import type { SinkInterface } from '@orkestrel/console';
6
6
 
7
7
  /**
8
8
  * Represents one intercepted process-stream write — the immutable, serializable record a
@@ -25,21 +25,20 @@ export declare interface CapturedChunk {
25
25
  }
26
26
 
27
27
  /**
28
- * Creates the server TTY {@link ServerSinkInterface} — the server output backend, the
29
- * env-symmetric sibling of `createBrowserSink` / core's `createConsoleSink`. `write(text, level?)`
30
- * routes by level to the process streams and uses construction-time styled facts: it sends ANSI
31
- * straight to a styled target (with a leading `\r` overwriting a terminal line natively) but
32
- * {@link import('@src/core').strip}s ANSI to clean text for a plain target.
28
+ * Creates the server TTY {@link ServerSinkInterface} — the server output backend, whose
29
+ * `write(text, level?)` routes by level to the process streams and uses construction-time styled
30
+ * facts: it sends ANSI straight to a styled target (with a leading `\r` overwriting a terminal
31
+ * line natively) but {@link import('@orkestrel/console').strip}s ANSI to clean text for a plain target.
33
32
  *
34
33
  * @param options - See {@link ServerSinkOptions}
35
- * @returns A {@link ServerSinkInterface} — a {@link import('@src/core').SinkInterface} that also
34
+ * @returns A {@link ServerSinkInterface} — a {@link import('@orkestrel/console').SinkInterface} that also
36
35
  * exposes the terminal `columns` width
37
36
  *
38
37
  * @remarks
39
38
  * - **Routes by level.** `error` / `warn` → the error stream (`process.stderr` by default), every
40
39
  * other level (and an omitted level) → the `stdout` stream (`process.stdout`) — the same routing
41
40
  * as core's `createConsoleSink`, so a logger's `error` reaches `stderr`. Both call the one
42
- * {@link import('@src/core').selectWriter} leaf, which is what keeps them identical.
41
+ * {@link import('@orkestrel/console').selectWriter} leaf, which is what keeps them identical.
43
42
  * - **Per-target styled facts.** At construction, each target uses `options.styled` when supplied;
44
43
  * otherwise {@link inferStyled} applies the injected `environment` (default `process.env`) and
45
44
  * then that target's `isTTY`.
@@ -55,16 +54,29 @@ export declare interface CapturedChunk {
55
54
  * the sink (and the isTTY-strip path) with a fake stream that never touches the real process
56
55
  * streams.
57
56
  *
58
- * @example
57
+ * @example The server — a TTY sink and a process capture
59
58
  * ```ts
60
59
  * import { createStyler, Logger, Reporter } from '@orkestrel/console'
61
- * import { createServerSink } from '@orkestrel/console/server'
60
+ * import { createServerSink, ProcessCapture } from '@orkestrel/console/server'
61
+ *
62
+ * const sink = createServerSink() // FORCE_COLOR, then NO_COLOR, then isTTY — per target, at construction
63
+ * const styler = createStyler({ enabled: sink.styled }) // keep generated ANSI paired with the sink's stdout stripping
64
+ * const logger = new Logger({ name: 'server', sink, styler })
65
+ * logger.error('boom') // → process.stderr (the error stream)
66
+ * const reporter = new Reporter({ sink, width: sink.columns }) // size the layout to the live terminal
67
+ *
68
+ * // `styled` overrides the inference outright — for a CI log that renders ANSI off a TTY, say.
69
+ * const forced = createServerSink({ styled: true })
70
+ * forced.styled // true, whatever the environment and the streams say
62
71
  *
63
- * const sink = createServerSink()
64
- * const styler = createStyler({ enabled: sink.styled })
65
- * const logger = new Logger({ name: 'app', sink, styler })
66
- * logger.error('boom') // process.stderr, ANSI rendered on a TTY / stripped to a pipe
67
- * const reporter = new Reporter({ sink, width: sink.columns })
72
+ * // Own every output path — a direct process.stdout.write, library output, child-process pipes:
73
+ * const capture = new ProcessCapture({ levels: ['stderr'], mirror: true })
74
+ * capture.start()
75
+ * process.stderr.write('a library diagnostic\n') // captured and still shown (mirror: true)
76
+ * capture.messages('stderr') // [{ level: 'stderr', text: 'a library diagnostic\n', time: }]
77
+ * capture.clear() // drop buffered chunks; interception is unaffected
78
+ * capture.stop()
79
+ * capture.destroy() // stop() then tear down the emitter
68
80
  * ```
69
81
  */
70
82
  export declare function createServerSink(options?: ServerSinkOptions): ServerSinkInterface;
@@ -103,24 +115,29 @@ export declare function decodeChunk(chunk: unknown, encoding?: unknown): string;
103
115
 
104
116
  /**
105
117
  * Sets the terminal width {@link import('./factories.js').createServerSink} reports through
106
- * {@link import('./types.js').ServerSinkInterface.columns} when the `stdout` stream is not a TTY (so
107
- * `.columns` is `undefined`) and no explicit `options.columns` was supplied — the conventional
118
+ * {@link import('./types.js').ServerSinkInterface.columns} when the `stdout` stream is not a TTY
119
+ * (so `.columns` is `undefined`) and no explicit `options.columns` was supplied — the conventional
108
120
  * 80-column default a non-interactive context (a pipe, a CI log) assumes.
109
121
  */
110
122
  export declare const DEFAULT_COLUMNS = 80;
111
123
 
112
124
  /**
113
- * Sets the default bounded-buffer cap for a {@link import('./types.js').ProcessCaptureInterface} — at
114
- * most this many recent {@link import('./types.js').CapturedChunk}s are retained per buffer (the
115
- * total buffer and each per-stream bucket; oldest dropped first). Mirrors the core `Capture`'s
116
- * `DEFAULT_CAPTURE_LIMIT`; a consumer overrides it through `options.limit`.
125
+ * Sets the default bounded-buffer cap for a {@link import('./types.js').ProcessCaptureInterface} —
126
+ * `1000`, so at most that many recent {@link import('./types.js').CapturedChunk}s are retained per
127
+ * buffer (the total buffer and each per-stream bucket; oldest dropped first) and retention is
128
+ * always bounded.
129
+ *
130
+ * @remarks
131
+ * It mirrors the core `Capture`'s `DEFAULT_CAPTURE_LIMIT`; a consumer overrides the cap through
132
+ * `options.limit`.
117
133
  */
118
134
  export declare const DEFAULT_STREAM_LIMIT = 1000;
119
135
 
120
136
  /**
121
- * Infers the width in character cells of a stream target — its live `columns` when it is a TTY, else
122
- * the non-interactive {@link DEFAULT_COLUMNS} fallback. The basis a {@link import('./types.js').ServerSinkInterface}
123
- * reports through `columns` so a `Reporter` / `Progress` can size its layout to the terminal.
137
+ * Infers the width in character cells of a stream target — its live `columns` when it is a TTY,
138
+ * else the non-interactive {@link DEFAULT_COLUMNS} fallback. The basis a
139
+ * {@link import('./types.js').ServerSinkInterface} reports through `columns` so a `Reporter` /
140
+ * `Progress` can size its layout to the terminal.
124
141
  *
125
142
  * @remarks
126
143
  * Reads `target.columns` on each call (so a getter-backed real stream reflects a live resize) and
@@ -133,14 +150,14 @@ export declare const DEFAULT_STREAM_LIMIT = 1000;
133
150
  export declare function inferColumns(target: StreamTargetInterface): number;
134
151
 
135
152
  /**
136
- * Infers whether one stream target receives styled output. The result is a construction-time
137
- * target fact for {@link import('./factories.js').createServerSink}; this helper is pure and never
138
- * reads process globals itself.
153
+ * Infers whether one stream target receives styled output a present `FORCE_COLOR` first, then a
154
+ * non-empty `NO_COLOR`, then `target.isTTY === true`.
139
155
  *
140
156
  * @remarks
141
- * A present `FORCE_COLOR` key has first precedence: only the exact value `'0'` disables styling.
142
- * Next, a non-empty `NO_COLOR` disables styling. Otherwise styling follows
143
- * `target.isTTY === true`.
157
+ * The result is a construction-time target fact for
158
+ * {@link import('./factories.js').createServerSink}; this helper is pure and
159
+ * never reads process globals itself. Under `FORCE_COLOR` only the exact value `'0'` disables
160
+ * styling.
144
161
  *
145
162
  * @param target - The stream target whose terminal capability is the fallback
146
163
  * @param environment - The environment record supplying `FORCE_COLOR` and `NO_COLOR`
@@ -155,9 +172,9 @@ export declare function inferColumns(target: StreamTargetInterface): number;
155
172
  export declare function inferStyled(target: StreamTargetInterface, environment: Readonly<Record<string, string | undefined>>): boolean;
156
173
 
157
174
  /**
158
- * Checks whether `encoding` is a {@link BufferEncoding} accepted by `Buffer.prototype.toString` — a total
159
- * guard used by {@link import('./helpers.js').decodeChunk} to honor a process-write `encoding`
160
- * argument only when it is a real Node encoding (otherwise utf-8 is assumed).
175
+ * Checks whether `encoding` is a {@link BufferEncoding} accepted by `Buffer.prototype.toString` — a
176
+ * total guard used by {@link import('./helpers.js').decodeChunk} to honor a process-write
177
+ * `encoding` argument only when it is a real Node encoding (otherwise utf-8 is assumed).
161
178
  *
162
179
  * @param encoding - The candidate encoding (the second `write` argument, possibly a callback)
163
180
  * @returns True if `encoding` names a supported buffer encoding; false otherwise
@@ -250,10 +267,13 @@ export declare class ProcessCapture implements ProcessCaptureInterface {
250
267
  }
251
268
 
252
269
  /**
253
- * Declares the observable events a {@link ProcessCaptureInterface} emits — mirrors the core
254
- * `Capture`'s `CaptureEventMap`, but the captured record is a {@link CapturedChunk} (stream-keyed).
270
+ * Declares the observable events a {@link ProcessCaptureInterface} emits — `capture(chunk)` per
271
+ * intercepted write, plus the `start` and `stop` signals.
255
272
  *
256
273
  * @remarks
274
+ * The map mirrors the core `Capture`'s `CaptureEventMap`, and the captured record is a
275
+ * {@link CapturedChunk} (stream-keyed).
276
+ *
257
277
  * - `capture` — an intercepted `process.stdout` / `process.stderr` write, carrying the frozen
258
278
  * {@link CapturedChunk}. The hook a live log viewer / tee subscribes to.
259
279
  * - `start` / `stop` — the interception toggled on / off (pure signals, empty tuples).
@@ -275,13 +295,14 @@ export declare type ProcessCaptureEventMap = {
275
295
  };
276
296
 
277
297
  /**
278
- * Declares an observable interceptor of the raw process output streams — the server's
279
- * "own all output" capture. Where the core `Capture` patches `console.*` (the high-level read
280
- * side), this patches `process.stdout.write` / `process.stderr.write` (the low-level stream), so it
281
- * catches direct `process.stdout.write`, third-party library output, and child-process pipes —
282
- * everything that reaches the streams, not only `console.*`.
298
+ * Declares an observable interceptor of the raw process output streams — the server's "own all
299
+ * output" capture, patching `process.stdout.write` / `process.stderr.write` on the low-level
300
+ * stream where the core `Capture` patches `console.*`.
283
301
  *
284
302
  * @remarks
303
+ * Patching the stream catches a direct `process.stdout.write`, third-party library output, and
304
+ * child-process pipes — everything that reaches the streams, not only `console.*`.
305
+ *
285
306
  * - **Snapshot-at-start (the no-capture-loop principle).** `start()` snapshots the current
286
307
  * `process[stream].write` for each configured {@link StreamLevel}, then installs the wrappers. The
287
308
  * mirror replays through that snapshot — so a server sink created from the same streams before the
@@ -307,7 +328,10 @@ export declare interface ProcessCaptureInterface {
307
328
  start(): void;
308
329
  /** Restores the pristine `process.*.write` references (idempotent; emits `stop`). */
309
330
  stop(): void;
310
- /** Returns a copy of the full captured buffer, oldest first (capped at `limit`). */
331
+ /**
332
+ * Returns a copy of the full captured buffer, oldest first (capped at `limit`), or — given a
333
+ * {@link StreamLevel} — a copy of only that stream's bucket.
334
+ */
311
335
  messages(): readonly CapturedChunk[];
312
336
  /** Returns a copy of the captured buffer for one {@link StreamLevel}, oldest first (capped at `limit`). */
313
337
  messages(level: StreamLevel): readonly CapturedChunk[];
@@ -318,9 +342,10 @@ export declare interface ProcessCaptureInterface {
318
342
  }
319
343
 
320
344
  /**
321
- * Holds the options for the {@link import('./ProcessCapture.js').ProcessCapture} constructor — every
322
- * field optional, so a bare `new ProcessCapture()` buffers both streams without mirroring or
323
- * forwarding.
345
+ * Holds the options for the {@link import('./ProcessCapture.js').ProcessCapture} constructor — the
346
+ * `on` / `error` emitter keys, the `levels` intercepted, the `mirror` pass-through, the `sink`
347
+ * forward, and the buffer `limit`. Every field is optional, so a bare `new ProcessCapture()`
348
+ * buffers both streams without mirroring or forwarding.
324
349
  *
325
350
  * @remarks
326
351
  * - `on` — initial {@link ProcessCaptureEventMap} listeners, wired at construction (for example
@@ -332,7 +357,7 @@ export declare interface ProcessCaptureInterface {
332
357
  * `write` (bound to its stream), so the output still reaches the terminal while being captured;
333
358
  * defaults to `false` (capture-only, the program's output is swallowed into the buffer).
334
359
  * - `sink` — an optional {@link SinkInterface} each intercepted chunk is also written to
335
- * (`sink.write(text, level)` with the {@link StreamLevel} mapped to a {@link import('@src/core').LogLevel} through
360
+ * (`sink.write(text, level)` with the {@link StreamLevel} mapped to a {@link import('@orkestrel/console').LogLevel} through
336
361
  * {@link import('./constants.js').STREAM_LEVEL_MAP}), to tee captured output into the logging
337
362
  * pipeline / a file. Absent by default.
338
363
  * - `limit` — the bounded-buffer cap (total and each per-stream bucket); defaults to
@@ -348,13 +373,16 @@ export declare interface ProcessCaptureOptions {
348
373
  }
349
374
 
350
375
  /**
351
- * Declares a {@link SinkInterface} that also exposes the target terminal's {@link columns} width — the shape
352
- * {@link import('./factories.js').createServerSink} returns. It is a drop-in {@link SinkInterface}
353
- * (so a `Logger` / `Reporter` / `Spinner` / `Progress` takes it as `sink`) whose extra `columns`
354
- * getter lets a consumer size a `Reporter`'s layout to the live terminal. Its `styled` fact lets
355
- * the same consumer enable or disable its styler for the `stdout` target.
376
+ * Declares a {@link SinkInterface} that also exposes the `stdout` target's construction-time
377
+ * `styled` fact and the terminal's live or fixed {@link columns} width — the shape
378
+ * {@link import('./factories.js').createServerSink} returns.
356
379
  *
357
380
  * @remarks
381
+ * It is a drop-in {@link SinkInterface} (so a `Logger` / `Reporter` / `Spinner` / `Progress`
382
+ * takes it as `sink`) whose extra `columns` getter lets a consumer size a `Reporter`'s layout to
383
+ * the live terminal, and whose `styled` fact lets the same consumer enable or disable its styler
384
+ * for the `stdout` target.
385
+ *
358
386
  * - `styled` is the `stdout` target's construction-time fact. The sink handles `stderr` through its
359
387
  * own independently inferred fact because the two targets can differ.
360
388
  * - `columns` is a getter, re-read on every access — so it reflects the current terminal width (a
@@ -366,8 +394,10 @@ export declare interface ServerSinkInterface extends SinkInterface {
366
394
  }
367
395
 
368
396
  /**
369
- * Holds the options for {@link import('./factories.js').createServerSink} — all optional, so a bare
370
- * `createServerSink()` writes to the real process streams.
397
+ * Holds the options for {@link import('./factories.js').createServerSink} — the `stdout` and
398
+ * `stderr` targets, the `styled` override, the `environment` inference reads, and an explicit
399
+ * `columns` width. All are optional, so a bare `createServerSink()` writes to the real process
400
+ * streams.
371
401
  *
372
402
  * @remarks
373
403
  * - `stdout` — the stream `info` / `debug` (and an omitted level) are written to; defaults to
@@ -391,48 +421,51 @@ export declare interface ServerSinkOptions {
391
421
  }
392
422
 
393
423
  /**
394
- * Maps each {@link StreamLevel} to its {@link LogLevel} for the optional sink forward — the projection a
395
- * process capture routes through when writing an intercepted chunk to a
396
- * {@link import('@src/core').SinkInterface}
397
- * (`sink.write(text, STREAM_LEVEL_MAP[level])`). `stderr` is conventionally the error/diagnostic
398
- * stream → `error`; `stdout` is the normal output stream → `info`. The source of truth for the
399
- * stream-to-log projection (the server analogue of the core `CAPTURE_LEVEL_MAP`).
424
+ * Maps each {@link StreamLevel} to its {@link LogLevel} for the optional sink forward — the
425
+ * projection a process capture routes through when writing an intercepted chunk to a
426
+ * {@link import('@orkestrel/console').SinkInterface}. `sink.write(text, STREAM_LEVEL_MAP[level])` is the
427
+ * call this map backs. `stderr` is conventionally the error/diagnostic stream → `error`; `stdout`
428
+ * is the normal output stream → `info`. The source of truth for the stream-to-log projection (the
429
+ * server analogue of the core `CAPTURE_LEVEL_MAP`).
400
430
  */
401
431
  export declare const STREAM_LEVEL_MAP: Readonly<Record<StreamLevel, LogLevel>>;
402
432
 
403
433
  /**
404
- * Lists the two process streams a {@link import('./types.js').ProcessCaptureInterface} can intercept, in
405
- * `stdout`-then-`stderr` order — the {@link StreamLevel} universe and the default configured set.
434
+ * Lists the process streams a {@link import('./types.js').ProcessCaptureInterface} can intercept,
435
+ * in `stdout`-then-`stderr` order — the {@link StreamLevel} universe and the default configured
436
+ * set.
406
437
  */
407
438
  export declare const STREAM_LEVELS: readonly StreamLevel[];
408
439
 
409
440
  /**
410
- * Names which process stream a {@link CapturedChunk} came from — the "level" axis of the process-stream
411
- * {@link ProcessCaptureInterface}, the server analogue of the core `Capture`'s `CaptureLevel`.
441
+ * Names which process stream a {@link CapturedChunk} came from — `stdout` or `stderr`, the
442
+ * "level" axis of the process-stream {@link ProcessCaptureInterface} and the server analogue of
443
+ * the core `Capture`'s `CaptureLevel`.
412
444
  *
413
445
  * @remarks
414
- * distinct from {@link import('@src/core').LogLevel}: a `StreamLevel` names the originating process stream
446
+ * distinct from {@link import('@orkestrel/console').LogLevel}: a `StreamLevel` names the originating process stream
415
447
  * (`process.stdout` vs `process.stderr`), not a severity. It is a named value family (it indexes
416
- * {@link import('./constants.js').STREAM_LEVEL_MAP} to a {@link import('@src/core').LogLevel} for the optional sink
448
+ * {@link import('./constants.js').STREAM_LEVEL_MAP} to a {@link import('@orkestrel/console').LogLevel} for the optional sink
417
449
  * forward), never a binary toggle — so it stays a union.
418
450
  */
419
451
  export declare type StreamLevel = 'stdout' | 'stderr';
420
452
 
421
453
  /**
422
- * Declares the minimal writable-stream shape the server sink and process capture address — exactly the
423
- * slice of a Node `tty.WriteStream` / `process.stdout` they touch, and no more. A
424
- * {@link ServerSinkOptions} target and a {@link ProcessCaptureInterface}'s patched streams are
425
- * narrowed to this through {@link import('./validators.js').isStreamTarget} (narrow the
426
- * boundary, never `as`), so a test can drive either with a hand-built fake stream that never
427
- * touches the real `process` streams.
454
+ * Declares the minimal writable-stream shape the server sink and process capture address — exactly
455
+ * the slice of a Node `tty.WriteStream` / `process.stdout` they touch and no more.
428
456
  *
429
457
  * @remarks
458
+ * A {@link ServerSinkOptions} target and a {@link ProcessCaptureInterface}'s patched streams are
459
+ * narrowed to this through {@link import('./validators.js').isStreamTarget} (narrow the boundary,
460
+ * never `as`), so a test can
461
+ * drive either with a hand-built fake stream that never touches the real `process` streams.
462
+ *
430
463
  * - `write(text)` — the one required method: push a chunk to the stream, returning the host's
431
464
  * backpressure boolean (`false` when the kernel buffer is full). A `process` stream returns it;
432
465
  * a fake may return `void` (read as truthy / no backpressure).
433
466
  * - `isTTY` — present and `true` on a real terminal, absent / `false` when the stream is piped to a
434
467
  * file or another process. When no explicit styling override exists, the sink reads it at
435
- * construction to decide whether to keep ANSI or {@link import('@src/core').strip} it to clean
468
+ * construction to decide whether to keep ANSI or {@link import('@orkestrel/console').strip} it to clean
436
469
  * text.
437
470
  * - `columns` — the terminal width in character cells when the stream is a TTY, `undefined`
438
471
  * otherwise; the sink surfaces it as {@link ServerSinkInterface.columns} so a consumer can feed a
@@ -445,8 +478,9 @@ export declare interface StreamTargetInterface {
445
478
  }
446
479
 
447
480
  /**
448
- * Names the completion callback `process.*.write` accepts as its last argument — the Node `write`
449
- * callback shape, and the {@link StreamWriteFunction} companion.
481
+ * Names the completion callback `process.*.write` accepts as its last argument —
482
+ * `(error?) => void`, the Node `write` callback shape and the {@link StreamWriteFunction}
483
+ * companion.
450
484
  *
451
485
  * @remarks
452
486
  * The capture wrapper forwards the callback verbatim to the mirror, so a caller's
@@ -455,11 +489,12 @@ export declare interface StreamTargetInterface {
455
489
  export declare type StreamWriteCallback = (error?: Error | null) => void;
456
490
 
457
491
  /**
458
- * Names the process-stream `write` method a {@link ProcessCaptureInterface} snapshots and swaps at
459
- * the patch boundary — the write-side analogue of {@link import('@src/core').ConsoleMethod}.
492
+ * Names the process-stream `write` method a {@link ProcessCaptureInterface} snapshots and swaps
493
+ * at the patch boundary — `NodeJS.WriteStream['write']` verbatim, the write-side analogue of
494
+ * {@link import('@orkestrel/console').ConsoleMethod}.
460
495
  *
461
496
  * @remarks
462
- * It is taken verbatim as `NodeJS.WriteStream['write']`, the overloaded
497
+ * The type is the overloaded
463
498
  * `(chunk, encoding?, callback?) => boolean` of `process.stdout.write` / `process.stderr.write`.
464
499
  * Using the canonical type rather than a hand-rolled approximation keeps snapshot and restore
465
500
  * exact and lets the wrapper assign cleanly. A {@link StreamLevel} (`'stdout' | 'stderr'`) is
@@ -3,31 +3,36 @@ import { Emitter } from "@orkestrel/emitter";
3
3
  import { Retention, selectWriter, strip, stripControls } from "../core/index.js";
4
4
  //#region src/server/constants.ts
5
5
  /**
6
- * Lists the two process streams a {@link import('./types.js').ProcessCaptureInterface} can intercept, in
7
- * `stdout`-then-`stderr` order — the {@link StreamLevel} universe and the default configured set.
6
+ * Lists the process streams a {@link import('./types.js').ProcessCaptureInterface} can intercept,
7
+ * in `stdout`-then-`stderr` order — the {@link StreamLevel} universe and the default configured
8
+ * set.
8
9
  */
9
10
  var STREAM_LEVELS = Object.freeze(["stdout", "stderr"]);
10
11
  /**
11
- * Sets the default bounded-buffer cap for a {@link import('./types.js').ProcessCaptureInterface} — at
12
- * most this many recent {@link import('./types.js').CapturedChunk}s are retained per buffer (the
13
- * total buffer and each per-stream bucket; oldest dropped first). Mirrors the core `Capture`'s
14
- * `DEFAULT_CAPTURE_LIMIT`; a consumer overrides it through `options.limit`.
12
+ * Sets the default bounded-buffer cap for a {@link import('./types.js').ProcessCaptureInterface} —
13
+ * `1000`, so at most that many recent {@link import('./types.js').CapturedChunk}s are retained per
14
+ * buffer (the total buffer and each per-stream bucket; oldest dropped first) and retention is
15
+ * always bounded.
16
+ *
17
+ * @remarks
18
+ * It mirrors the core `Capture`'s `DEFAULT_CAPTURE_LIMIT`; a consumer overrides the cap through
19
+ * `options.limit`.
15
20
  */
16
21
  var DEFAULT_STREAM_LIMIT = 1e3;
17
22
  /**
18
23
  * Sets the terminal width {@link import('./factories.js').createServerSink} reports through
19
- * {@link import('./types.js').ServerSinkInterface.columns} when the `stdout` stream is not a TTY (so
20
- * `.columns` is `undefined`) and no explicit `options.columns` was supplied — the conventional
24
+ * {@link import('./types.js').ServerSinkInterface.columns} when the `stdout` stream is not a TTY
25
+ * (so `.columns` is `undefined`) and no explicit `options.columns` was supplied — the conventional
21
26
  * 80-column default a non-interactive context (a pipe, a CI log) assumes.
22
27
  */
23
28
  var DEFAULT_COLUMNS = 80;
24
29
  /**
25
- * Maps each {@link StreamLevel} to its {@link LogLevel} for the optional sink forward — the projection a
26
- * process capture routes through when writing an intercepted chunk to a
27
- * {@link import('@src/core').SinkInterface}
28
- * (`sink.write(text, STREAM_LEVEL_MAP[level])`). `stderr` is conventionally the error/diagnostic
29
- * stream → `error`; `stdout` is the normal output stream → `info`. The source of truth for the
30
- * stream-to-log projection (the server analogue of the core `CAPTURE_LEVEL_MAP`).
30
+ * Maps each {@link StreamLevel} to its {@link LogLevel} for the optional sink forward — the
31
+ * projection a process capture routes through when writing an intercepted chunk to a
32
+ * {@link import('@src/core').SinkInterface}. `sink.write(text, STREAM_LEVEL_MAP[level])` is the
33
+ * call this map backs. `stderr` is conventionally the error/diagnostic stream → `error`; `stdout`
34
+ * is the normal output stream → `info`. The source of truth for the stream-to-log projection (the
35
+ * server analogue of the core `CAPTURE_LEVEL_MAP`).
31
36
  */
32
37
  var STREAM_LEVEL_MAP = Object.freeze({
33
38
  stdout: "info",
@@ -60,9 +65,9 @@ function isStreamTarget(value) {
60
65
  return typeof value === "object" && value !== null && "write" in value && typeof value.write === "function";
61
66
  }
62
67
  /**
63
- * Checks whether `encoding` is a {@link BufferEncoding} accepted by `Buffer.prototype.toString` — a total
64
- * guard used by {@link import('./helpers.js').decodeChunk} to honor a process-write `encoding`
65
- * argument only when it is a real Node encoding (otherwise utf-8 is assumed).
68
+ * Checks whether `encoding` is a {@link BufferEncoding} accepted by `Buffer.prototype.toString` — a
69
+ * total guard used by {@link import('./helpers.js').decodeChunk} to honor a process-write
70
+ * `encoding` argument only when it is a real Node encoding (otherwise utf-8 is assumed).
66
71
  *
67
72
  * @param encoding - The candidate encoding (the second `write` argument, possibly a callback)
68
73
  * @returns True if `encoding` names a supported buffer encoding; false otherwise
@@ -73,9 +78,10 @@ function isBufferEncoding(encoding) {
73
78
  //#endregion
74
79
  //#region src/server/helpers.ts
75
80
  /**
76
- * Infers the width in character cells of a stream target — its live `columns` when it is a TTY, else
77
- * the non-interactive {@link DEFAULT_COLUMNS} fallback. The basis a {@link import('./types.js').ServerSinkInterface}
78
- * reports through `columns` so a `Reporter` / `Progress` can size its layout to the terminal.
81
+ * Infers the width in character cells of a stream target — its live `columns` when it is a TTY,
82
+ * else the non-interactive {@link DEFAULT_COLUMNS} fallback. The basis a
83
+ * {@link import('./types.js').ServerSinkInterface} reports through `columns` so a `Reporter` /
84
+ * `Progress` can size its layout to the terminal.
79
85
  *
80
86
  * @remarks
81
87
  * Reads `target.columns` on each call (so a getter-backed real stream reflects a live resize) and
@@ -91,14 +97,14 @@ function inferColumns(target) {
91
97
  return 80;
92
98
  }
93
99
  /**
94
- * Infers whether one stream target receives styled output. The result is a construction-time
95
- * target fact for {@link import('./factories.js').createServerSink}; this helper is pure and never
96
- * reads process globals itself.
100
+ * Infers whether one stream target receives styled output a present `FORCE_COLOR` first, then a
101
+ * non-empty `NO_COLOR`, then `target.isTTY === true`.
97
102
  *
98
103
  * @remarks
99
- * A present `FORCE_COLOR` key has first precedence: only the exact value `'0'` disables styling.
100
- * Next, a non-empty `NO_COLOR` disables styling. Otherwise styling follows
101
- * `target.isTTY === true`.
104
+ * The result is a construction-time target fact for
105
+ * {@link import('./factories.js').createServerSink}; this helper is pure and
106
+ * never reads process globals itself. Under `FORCE_COLOR` only the exact value `'0'` disables
107
+ * styling.
102
108
  *
103
109
  * @param target - The stream target whose terminal capability is the fallback
104
110
  * @param environment - The environment record supplying `FORCE_COLOR` and `NO_COLOR`
@@ -314,11 +320,10 @@ var ProcessCapture = class {
314
320
  //#endregion
315
321
  //#region src/server/factories.ts
316
322
  /**
317
- * Creates the server TTY {@link ServerSinkInterface} — the server output backend, the
318
- * env-symmetric sibling of `createBrowserSink` / core's `createConsoleSink`. `write(text, level?)`
319
- * routes by level to the process streams and uses construction-time styled facts: it sends ANSI
320
- * straight to a styled target (with a leading `\r` overwriting a terminal line natively) but
321
- * {@link import('@src/core').strip}s ANSI to clean text for a plain target.
323
+ * Creates the server TTY {@link ServerSinkInterface} — the server output backend, whose
324
+ * `write(text, level?)` routes by level to the process streams and uses construction-time styled
325
+ * facts: it sends ANSI straight to a styled target (with a leading `\r` overwriting a terminal
326
+ * line natively) but {@link import('@src/core').strip}s ANSI to clean text for a plain target.
322
327
  *
323
328
  * @param options - See {@link ServerSinkOptions}
324
329
  * @returns A {@link ServerSinkInterface} — a {@link import('@src/core').SinkInterface} that also
@@ -344,16 +349,29 @@ var ProcessCapture = class {
344
349
  * the sink (and the isTTY-strip path) with a fake stream that never touches the real process
345
350
  * streams.
346
351
  *
347
- * @example
352
+ * @example The server — a TTY sink and a process capture
348
353
  * ```ts
349
354
  * import { createStyler, Logger, Reporter } from '@orkestrel/console'
350
- * import { createServerSink } from '@orkestrel/console/server'
355
+ * import { createServerSink, ProcessCapture } from '@orkestrel/console/server'
356
+ *
357
+ * const sink = createServerSink() // FORCE_COLOR, then NO_COLOR, then isTTY — per target, at construction
358
+ * const styler = createStyler({ enabled: sink.styled }) // keep generated ANSI paired with the sink's stdout stripping
359
+ * const logger = new Logger({ name: 'server', sink, styler })
360
+ * logger.error('boom') // → process.stderr (the error stream)
361
+ * const reporter = new Reporter({ sink, width: sink.columns }) // size the layout to the live terminal
351
362
  *
352
- * const sink = createServerSink()
353
- * const styler = createStyler({ enabled: sink.styled })
354
- * const logger = new Logger({ name: 'app', sink, styler })
355
- * logger.error('boom') // → process.stderr, ANSI rendered on a TTY / stripped to a pipe
356
- * const reporter = new Reporter({ sink, width: sink.columns })
363
+ * // `styled` overrides the inference outright — for a CI log that renders ANSI off a TTY, say.
364
+ * const forced = createServerSink({ styled: true })
365
+ * forced.styled // true, whatever the environment and the streams say
366
+ *
367
+ * // Own every output path a direct process.stdout.write, library output, child-process pipes:
368
+ * const capture = new ProcessCapture({ levels: ['stderr'], mirror: true })
369
+ * capture.start()
370
+ * process.stderr.write('a library diagnostic\n') // captured and still shown (mirror: true)
371
+ * capture.messages('stderr') // [{ level: 'stderr', text: 'a library diagnostic\n', time: … }]
372
+ * capture.clear() // drop buffered chunks; interception is unaffected
373
+ * capture.stop()
374
+ * capture.destroy() // stop() then tear down the emitter
357
375
  * ```
358
376
  */
359
377
  function createServerSink(options) {