@uipath/common 0.2.0 → 0.9.0
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/README.md +3 -3
- package/dist/catch-error.d.ts +5 -0
- package/dist/command-examples.d.ts +36 -0
- package/dist/command-help.d.ts +53 -0
- package/dist/command-walker.d.ts +14 -0
- package/dist/completer.d.ts +48 -0
- package/dist/console-guard.d.ts +24 -0
- package/dist/constants.d.ts +18 -0
- package/dist/env-reference.d.ts +10 -0
- package/dist/error-handler.d.ts +52 -0
- package/dist/error-instructions.d.ts +2 -0
- package/dist/formatter.d.ts +101 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +1316 -161
- package/dist/jsonpath.d.ts +11 -0
- package/dist/logger.d.ts +116 -0
- package/dist/option-validators.d.ts +33 -0
- package/dist/output-context.d.ts +28 -0
- package/dist/output-format-context.d.ts +27 -0
- package/dist/output-sink.d.ts +23 -0
- package/dist/polling/abort-controller.d.ts +1 -0
- package/dist/polling/format-utils.d.ts +13 -0
- package/dist/polling/index.d.ts +6 -0
- package/dist/polling/poll-until.d.ts +60 -0
- package/dist/polling/terminal-statuses.d.ts +50 -0
- package/dist/polling/types.d.ts +247 -0
- package/dist/registry.d.ts +6 -0
- package/dist/screen-logger.d.ts +9 -0
- package/dist/singleton.d.ts +42 -0
- package/dist/telemetry/browser-context-storage.d.ts +29 -0
- package/dist/telemetry/console-telemetry-provider.d.ts +12 -0
- package/dist/telemetry/context-storage.d.ts +19 -0
- package/dist/telemetry/debug-telemetry-provider.d.ts +12 -0
- package/dist/telemetry/detect-agent.d.ts +13 -0
- package/dist/telemetry/index.d.ts +7 -0
- package/dist/telemetry/index.js +256 -0
- package/dist/telemetry/logger-telemetry-provider.d.ts +15 -0
- package/dist/telemetry/node-appinsights-telemetry-provider.d.ts +62 -0
- package/dist/telemetry/node-context-storage.d.ts +11 -0
- package/dist/telemetry/node.d.ts +7 -0
- package/dist/telemetry/pii-redactor.d.ts +32 -0
- package/dist/telemetry/telemetry-events.d.ts +3 -0
- package/dist/telemetry/telemetry-init.d.ts +53 -0
- package/dist/telemetry/telemetry-provider.d.ts +27 -0
- package/dist/telemetry/telemetry-service.d.ts +157 -0
- package/dist/tool-provider.d.ts +6 -0
- package/dist/trackedAction.d.ts +38 -0
- package/package.json +14 -6
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Evaluate a JSONPath expression against arbitrary data.
|
|
3
|
+
*
|
|
4
|
+
* Returns a newline-separated string of matched values.
|
|
5
|
+
* Objects/arrays are serialized to compact JSON.
|
|
6
|
+
* Returns an empty string when nothing matches or the expression is unrecognised.
|
|
7
|
+
*/
|
|
8
|
+
export declare function evaluateJsonPath(data: unknown, expression: string): string;
|
|
9
|
+
export declare class JsonPathError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared logger for packages that don't have access to CliContext.
|
|
3
|
+
* Writes through the OutputSink abstraction so output is correctly
|
|
4
|
+
* routed in CLI, MCP, and browser contexts.
|
|
5
|
+
*
|
|
6
|
+
* By default, all messages are written to stderr via the sink.
|
|
7
|
+
* When a log file is configured (via --log-file), messages are
|
|
8
|
+
* appended to that file instead.
|
|
9
|
+
*
|
|
10
|
+
* Routing (default / stderr mode):
|
|
11
|
+
* all levels → writeErr (stderr), respecting the level threshold
|
|
12
|
+
*
|
|
13
|
+
* Routing (file mode, enabled via --log-file):
|
|
14
|
+
* all levels → file, respecting the level threshold
|
|
15
|
+
*/
|
|
16
|
+
import type { OutputSink } from "./output-sink";
|
|
17
|
+
export declare function setGlobalLogFilePath(path: string): void;
|
|
18
|
+
export declare function getGlobalLogFilePath(): string;
|
|
19
|
+
export declare enum LogLevel {
|
|
20
|
+
DEBUG = 0,
|
|
21
|
+
INFO = 1,
|
|
22
|
+
WARN = 2,
|
|
23
|
+
ERROR = 3
|
|
24
|
+
}
|
|
25
|
+
export declare const DEFAULT_LOG_LEVEL = LogLevel.ERROR;
|
|
26
|
+
export interface LoggerConfig {
|
|
27
|
+
/** Log level threshold. Messages below this level are suppressed. */
|
|
28
|
+
level?: LogLevel;
|
|
29
|
+
/** Output sink to set as the process-wide default. */
|
|
30
|
+
sink?: OutputSink;
|
|
31
|
+
/** Set to false to disable file logging. Defaults to false. */
|
|
32
|
+
fileLogging?: boolean;
|
|
33
|
+
/** Path to a log file. When set, enables file logging to this path. */
|
|
34
|
+
logFile?: string;
|
|
35
|
+
}
|
|
36
|
+
declare class SimpleLogger {
|
|
37
|
+
/** Brand marker for cross-bundle duck-type detection. */
|
|
38
|
+
readonly __brand: "SimpleLogger";
|
|
39
|
+
private level;
|
|
40
|
+
private logFilePath;
|
|
41
|
+
private fileLoggingEnabled;
|
|
42
|
+
private pendingWrites;
|
|
43
|
+
private pendingInit;
|
|
44
|
+
constructor();
|
|
45
|
+
static getInstance(): SimpleLogger;
|
|
46
|
+
/** Reset the singleton — intended for testing only. */
|
|
47
|
+
static resetInstance(): void;
|
|
48
|
+
private static readonly isNode;
|
|
49
|
+
private static resolveLevel;
|
|
50
|
+
private static parseLevel;
|
|
51
|
+
private format;
|
|
52
|
+
/** Check if file logging is active (local or cross-bundle via globalThis). */
|
|
53
|
+
private isFileLoggingActive;
|
|
54
|
+
private writeToFile;
|
|
55
|
+
debug(message: string, ...args: unknown[]): void;
|
|
56
|
+
info(message: string, ...args: unknown[]): void;
|
|
57
|
+
warn(message: string, ...args: unknown[]): void;
|
|
58
|
+
error(message: string, ...args: unknown[]): void;
|
|
59
|
+
/**
|
|
60
|
+
* Get the current log level.
|
|
61
|
+
*/
|
|
62
|
+
getLevel(): LogLevel;
|
|
63
|
+
/**
|
|
64
|
+
* Set the log level dynamically
|
|
65
|
+
*/
|
|
66
|
+
setLevel(level: LogLevel): void;
|
|
67
|
+
/**
|
|
68
|
+
* Enable or disable file logging.
|
|
69
|
+
*/
|
|
70
|
+
setFileLogging(enabled: boolean): void;
|
|
71
|
+
/**
|
|
72
|
+
* Set a log file path and enable file logging.
|
|
73
|
+
*/
|
|
74
|
+
setLogFile(path: string): void;
|
|
75
|
+
/** Drain pending async file I/O. For tests that read synchronously after logging. */
|
|
76
|
+
flushFile(): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Get the path to the current log file (empty string if no --log-file was provided).
|
|
79
|
+
*/
|
|
80
|
+
getLogFilePath(): string;
|
|
81
|
+
/**
|
|
82
|
+
* Log handler compatible with the SDK's LogHandler type.
|
|
83
|
+
* Accepts a LogMessage-shaped object and routes it through SimpleLogger.
|
|
84
|
+
*
|
|
85
|
+
* Usage: pass `logger.handleLog` as the `logHandler` option to
|
|
86
|
+
* `createNodeSolutionPackager` or `createNodeProjectPackager`.
|
|
87
|
+
*/
|
|
88
|
+
handleLog: (logMessage: {
|
|
89
|
+
message: string;
|
|
90
|
+
logLevel: string;
|
|
91
|
+
source?: string;
|
|
92
|
+
sourceTarget?: string;
|
|
93
|
+
}) => void;
|
|
94
|
+
}
|
|
95
|
+
export declare const logger: SimpleLogger;
|
|
96
|
+
/** Reset the logger singleton — intended for testing only. */
|
|
97
|
+
export declare function resetLoggerInstance(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Get the path to the current log file.
|
|
100
|
+
*/
|
|
101
|
+
export declare function getLogFilePath(): string;
|
|
102
|
+
/**
|
|
103
|
+
* Configure the logger and output sink in one call.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* // CLI entry point
|
|
107
|
+
* configureLogger({ sink: new TerminalSink() });
|
|
108
|
+
*
|
|
109
|
+
* // Browser entry point
|
|
110
|
+
* configureLogger({ sink: new BrowserSink() });
|
|
111
|
+
*
|
|
112
|
+
* // MCP — errors still surface via writeErr
|
|
113
|
+
* configureLogger({ level: LogLevel.ERROR, sink: new BufferSink() });
|
|
114
|
+
*/
|
|
115
|
+
export declare function configureLogger(config: LoggerConfig): void;
|
|
116
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared commander option-value validators.
|
|
3
|
+
*
|
|
4
|
+
* Use these as the third argument to `.option()` to coerce + validate
|
|
5
|
+
* raw string input before it reaches command handlers. Throws
|
|
6
|
+
* `commander.InvalidArgumentError` so commander emits a structured
|
|
7
|
+
* ValidationError result instead of letting bad input propagate.
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* .option("-l, --limit <number>", "Maximum results", parseLimit)
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Parse and validate a positive-integer `--limit` value.
|
|
14
|
+
* Accepts: integers in [1, max] (default max: 10000)
|
|
15
|
+
* Rejects: non-numeric, negative, zero, fractional, > max
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseLimit(raw: string, _previous?: number): number;
|
|
18
|
+
/**
|
|
19
|
+
* Parse and validate a non-negative-integer `--offset` value.
|
|
20
|
+
* Accepts: integers in [0, max] (default max: 1_000_000)
|
|
21
|
+
* Rejects: non-numeric, negative, fractional, > max
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseOffset(raw: string, _previous?: number): number;
|
|
24
|
+
/**
|
|
25
|
+
* Generic bounded-integer parser used by parseLimit/parseOffset.
|
|
26
|
+
* Accepts integers in [bounds.min, bounds.max] (inclusive).
|
|
27
|
+
* Use `min: 0` for non-negative, `min: 1` for strictly positive.
|
|
28
|
+
* Exposed so other commands can build custom-bounded validators.
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseBoundedInt(raw: string, optionName: string, bounds: {
|
|
31
|
+
min: number;
|
|
32
|
+
max: number;
|
|
33
|
+
}): number;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { OutputSink, SinkCapabilities } from "./output-sink";
|
|
2
|
+
/**
|
|
3
|
+
* Run a function with a specific OutputSink bound to the current async context.
|
|
4
|
+
* All code executed within `fn` (including async continuations) will see this sink
|
|
5
|
+
* via `getOutputSink()`.
|
|
6
|
+
*
|
|
7
|
+
* This is concurrency-safe: multiple simultaneous `runWithSink` scopes
|
|
8
|
+
* (e.g. concurrent MCP tool calls) each see their own sink.
|
|
9
|
+
*/
|
|
10
|
+
export declare function runWithSink<T>(sink: OutputSink, fn: () => T): T;
|
|
11
|
+
/**
|
|
12
|
+
* Get the OutputSink for the current execution context.
|
|
13
|
+
*
|
|
14
|
+
* Resolution order:
|
|
15
|
+
* 1. AsyncLocalStorage context (set by runWithSink)
|
|
16
|
+
* 2. Global fallback sink (set at process startup)
|
|
17
|
+
* 3. CONSOLE_FALLBACK (writes to process.stdout/stderr — last resort)
|
|
18
|
+
*/
|
|
19
|
+
export declare function getOutputSink(): OutputSink;
|
|
20
|
+
/**
|
|
21
|
+
* Set the process-wide default sink. Called once at CLI startup.
|
|
22
|
+
* This is NOT per-request — it is the global fallback when no
|
|
23
|
+
* AsyncLocalStorage context is active.
|
|
24
|
+
*
|
|
25
|
+
* Stored on globalThis so all bundled copies of @uipath/common share it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function setGlobalSink(sink: OutputSink): void;
|
|
28
|
+
export type { OutputSink, SinkCapabilities };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-wide output format & filter context.
|
|
3
|
+
*
|
|
4
|
+
* Stores the current OutputFormat and JMESPath filter expression so that
|
|
5
|
+
* OutputFormatter functions can apply them automatically without every
|
|
6
|
+
* command having to thread these values through.
|
|
7
|
+
*/
|
|
8
|
+
import type { OutputFormat } from "./formatter";
|
|
9
|
+
/**
|
|
10
|
+
* Set the process-wide output format.
|
|
11
|
+
* Called once at CLI startup (from extractFormatFromArgs for early use via --output)
|
|
12
|
+
* and updated by the preAction hook with the Commander-resolved value.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setOutputFormat(format: OutputFormat): void;
|
|
15
|
+
/**
|
|
16
|
+
* Get the current output format, defaulting to "json" if not set.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getOutputFormat(): OutputFormat;
|
|
19
|
+
/**
|
|
20
|
+
* Set the process-wide output filter expression.
|
|
21
|
+
* Called once at CLI startup after parsing the global --output-filter option.
|
|
22
|
+
*/
|
|
23
|
+
export declare function setOutputFilter(filter: string | undefined): void;
|
|
24
|
+
/**
|
|
25
|
+
* Get the current output filter expression, if any.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getOutputFilter(): string | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fundamental write target for all CLI output.
|
|
3
|
+
* Every output path (OutputFormatter, logger) writes through this.
|
|
4
|
+
*/
|
|
5
|
+
export interface OutputSink {
|
|
6
|
+
/** Write user-facing structured output (stdout equivalent) */
|
|
7
|
+
writeOut(str: string): void;
|
|
8
|
+
/** Write error output (stderr equivalent) */
|
|
9
|
+
writeErr(str: string): void;
|
|
10
|
+
/** Write diagnostic log messages (logger.info, logger.warn, logger.debug).
|
|
11
|
+
* Sinks decide the destination: stdout for CLI, no-op for MCP. */
|
|
12
|
+
writeLog(str: string): void;
|
|
13
|
+
/** Capabilities query — allows callers to adapt behavior */
|
|
14
|
+
readonly capabilities: SinkCapabilities;
|
|
15
|
+
}
|
|
16
|
+
export interface SinkCapabilities {
|
|
17
|
+
/** True when a human is reading (TTY). False for piped, MCP, browser. */
|
|
18
|
+
isInteractive: boolean;
|
|
19
|
+
/** True when ANSI escape codes are supported. */
|
|
20
|
+
supportsColor: boolean;
|
|
21
|
+
/** Terminal width, or a sensible default (80/120). */
|
|
22
|
+
outputWidth: number;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function createPollAbortController(): AbortController;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert milliseconds to a human-readable HH:MM:SS duration string.
|
|
3
|
+
*
|
|
4
|
+
* Returns `"00:00:00"` for invalid input (negative, NaN, Infinity).
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* msToDuration(5_023_000); // "01:23:43"
|
|
9
|
+
* msToDuration(45_000); // "00:00:45"
|
|
10
|
+
* msToDuration(0); // "00:00:00"
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function msToDuration(ms: number): string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createPollAbortController } from "./abort-controller";
|
|
2
|
+
export { msToDuration } from "./format-utils";
|
|
3
|
+
export { pollUntil } from "./poll-until";
|
|
4
|
+
export { isFailureStatus, isSuccessStatus, isTerminalStatus, } from "./terminal-statuses";
|
|
5
|
+
export type { BackoffConfig, OnErrorCallback, PollContext, PollUntilOptions, PollUntilResult, } from "./types";
|
|
6
|
+
export { BACKOFF_DEFAULTS, ErrorDecision, MIN_INTERVAL_MS, POLL_DEFAULTS, PollOutcome, } from "./types";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { PollUntilOptions, PollUntilResult } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Generic polling utility. Repeatedly calls `fn()` until `until(result)`
|
|
4
|
+
* returns `true`, a timeout is reached, a signal interrupts, or a consumer
|
|
5
|
+
* callback aborts.
|
|
6
|
+
*
|
|
7
|
+
* All lifecycle hooks are optional. The utility handles timing, retries,
|
|
8
|
+
* status tracking, backoff, progress logging, and cancellation. Consumers
|
|
9
|
+
* bring their domain logic via callbacks.
|
|
10
|
+
*
|
|
11
|
+
* @example Simple status polling
|
|
12
|
+
* ```ts
|
|
13
|
+
* const result = await pollUntil({
|
|
14
|
+
* fn: () => api.getJobStatus({ jobId }),
|
|
15
|
+
* until: (job) => TERMINAL.has(job.state),
|
|
16
|
+
* getStatus: (job) => job.state,
|
|
17
|
+
* label: `job ${jobId}`,
|
|
18
|
+
* intervalMs: 5000,
|
|
19
|
+
* timeoutMs: 360_000,
|
|
20
|
+
* });
|
|
21
|
+
* if (result.outcome === PollOutcome.Completed) { ... }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example Error-resilient polling with retry
|
|
25
|
+
* ```ts
|
|
26
|
+
* const result = await pollUntil({
|
|
27
|
+
* fn: () => api.getStatus({ id }),
|
|
28
|
+
* until: (r) => r.done,
|
|
29
|
+
* maxConsecutiveErrors: 3,
|
|
30
|
+
* intervalMs: 60_000,
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example Selective error handling (404 transient, 403 fatal)
|
|
35
|
+
* ```ts
|
|
36
|
+
* const result = await pollUntil({
|
|
37
|
+
* fn: () => getTraces(id),
|
|
38
|
+
* until: (spans) => hasTerminalSpan(spans),
|
|
39
|
+
* maxConsecutiveErrors: 0,
|
|
40
|
+
* onError: (error) => {
|
|
41
|
+
* if (error.message.includes("404")) return;
|
|
42
|
+
* return ErrorDecision.Abort;
|
|
43
|
+
* },
|
|
44
|
+
* });
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example Exponential backoff on errors (normal polls use intervalMs)
|
|
48
|
+
* ```ts
|
|
49
|
+
* const result = await pollUntil({
|
|
50
|
+
* fn: () => api.getStatus({ id }),
|
|
51
|
+
* until: (r) => r.done,
|
|
52
|
+
* intervalMs: 5000, // 5s between successful polls
|
|
53
|
+
* backoff: true, // errors: 1s → 2s → 4s → ... → 30s cap
|
|
54
|
+
* maxConsecutiveErrors: 0, // never auto-abort
|
|
55
|
+
* });
|
|
56
|
+
* ```
|
|
57
|
+
*
|
|
58
|
+
* @see PollUntilOptions for full configuration and callback documentation.
|
|
59
|
+
*/
|
|
60
|
+
export declare function pollUntil<T>(options: PollUntilOptions<T>): Promise<PollUntilResult<T>>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared terminal status definitions across all UiPath async operations.
|
|
3
|
+
*
|
|
4
|
+
* These cover the superset of known statuses from Orchestrator, Flow,
|
|
5
|
+
* Test Manager, and Solution deployments. Comparison is case-insensitive.
|
|
6
|
+
*
|
|
7
|
+
* Individual tools can extend with domain-specific statuses if needed,
|
|
8
|
+
* but the common set eliminates each tool defining its own.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Check if a status string represents a terminal state (case-insensitive).
|
|
12
|
+
*
|
|
13
|
+
* Covers the known superset across Orchestrator jobs, Flow executions,
|
|
14
|
+
* Test Manager executions, and Solution deployments.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* isTerminalStatus("Completed") // true
|
|
19
|
+
* isTerminalStatus("Running") // false
|
|
20
|
+
* isTerminalStatus("FAULTED") // true
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function isTerminalStatus(status: string): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a status string represents a failure state (case-insensitive).
|
|
26
|
+
*
|
|
27
|
+
* A subset of terminal statuses — excludes success states like
|
|
28
|
+
* "Completed", "Successful", "Finished".
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* isFailureStatus("Faulted") // true
|
|
33
|
+
* isFailureStatus("Completed") // false
|
|
34
|
+
* isFailureStatus("Cancelled") // true
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function isFailureStatus(status: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Check if a status string represents a successful terminal state (case-insensitive).
|
|
40
|
+
*
|
|
41
|
+
* Equivalent to `isTerminalStatus(s) && !isFailureStatus(s)`.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* isSuccessStatus("Completed") // true
|
|
46
|
+
* isSuccessStatus("Faulted") // false
|
|
47
|
+
* isSuccessStatus("Running") // false
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function isSuccessStatus(status: string): boolean;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared polling utility types.
|
|
3
|
+
*
|
|
4
|
+
* These interfaces define the contract for `pollUntil` — a generic,
|
|
5
|
+
* callback-driven polling utility that any tool can consume. The design
|
|
6
|
+
* is driven by the union of all consumer requirements across the codebase.
|
|
7
|
+
*
|
|
8
|
+
* Callback ordering contract (per successful poll iteration):
|
|
9
|
+
* beforePoll → fn() → onPoll → getStatus/onStatusChange → until → onComplete (if terminal)
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Context passed to dynamic functions (`intervalMs`, `beforePoll`).
|
|
13
|
+
* Gives consumers full visibility into the polling state so they can
|
|
14
|
+
* make informed decisions (e.g., token refresh after N minutes,
|
|
15
|
+
* adaptive interval based on last status).
|
|
16
|
+
*/
|
|
17
|
+
export interface PollContext<T> {
|
|
18
|
+
/** Number of completed successful polls (0 before first poll). */
|
|
19
|
+
pollCount: number;
|
|
20
|
+
/** Time elapsed since polling started, in ms. */
|
|
21
|
+
elapsedMs: number;
|
|
22
|
+
/** Result of the last successful poll. `undefined` before first success. */
|
|
23
|
+
lastResult?: T;
|
|
24
|
+
/** Status string from the last poll. `undefined` if `getStatus` is not provided or before the first poll. */
|
|
25
|
+
lastStatus?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Backoff configuration for exponential backoff.
|
|
29
|
+
* When `backoff` is set on `PollUntilOptions`, it overrides `intervalMs`.
|
|
30
|
+
*/
|
|
31
|
+
export interface BackoffConfig {
|
|
32
|
+
/** Initial interval in ms. (default: 1000) */
|
|
33
|
+
initialMs?: number;
|
|
34
|
+
/** Multiplier applied per poll. (default: 2) */
|
|
35
|
+
multiplier?: number;
|
|
36
|
+
/** Maximum interval cap in ms. (default: 30000) */
|
|
37
|
+
maxMs?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Jitter factor in [0, 1]. Randomizes the interval to avoid thundering herd.
|
|
40
|
+
* 0 = no jitter, 1 = full jitter (uniform in [0, computed]).
|
|
41
|
+
* (default: 0.5 — equal jitter)
|
|
42
|
+
*/
|
|
43
|
+
jitter?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Callback type for `onError`. Return `ErrorDecision.Abort` to stop polling,
|
|
47
|
+
* or return nothing to continue with retry logic. Async-capable.
|
|
48
|
+
*/
|
|
49
|
+
export type OnErrorCallback = (error: Error, consecutiveCount: number) => void | ErrorDecision | Promise<void | ErrorDecision>;
|
|
50
|
+
/** Resolved backoff config with all defaults filled in. */
|
|
51
|
+
export interface ResolvedBackoffConfig {
|
|
52
|
+
initialMs: number;
|
|
53
|
+
multiplier: number;
|
|
54
|
+
maxMs: number;
|
|
55
|
+
jitter: number;
|
|
56
|
+
}
|
|
57
|
+
export interface PollUntilOptions<T> {
|
|
58
|
+
/** Async function that fetches current state. */
|
|
59
|
+
fn: () => Promise<T>;
|
|
60
|
+
/** Predicate — return `true` when polling should stop. */
|
|
61
|
+
until: (result: T) => boolean;
|
|
62
|
+
/** Extract a status string from the poll result for change detection and logging. */
|
|
63
|
+
getStatus?: (result: T) => string;
|
|
64
|
+
/**
|
|
65
|
+
* Polling interval in ms for **successful** polls. Static number or dynamic function.
|
|
66
|
+
*
|
|
67
|
+
* Dynamic function receives `PollContext` and returns the interval for the
|
|
68
|
+
* upcoming sleep. Use for custom scheduling, e.g.:
|
|
69
|
+
* ```ts
|
|
70
|
+
* intervalMs: (ctx) => ctx.lastStatus === "Running" ? 2000 : 5000
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* (default: 5000)
|
|
74
|
+
*/
|
|
75
|
+
intervalMs?: number | ((ctx: PollContext<T>) => number);
|
|
76
|
+
/**
|
|
77
|
+
* Max time to poll in ms. `0` means no limit — poll indefinitely until
|
|
78
|
+
* a terminal state, abort, or interrupt.
|
|
79
|
+
*
|
|
80
|
+
* (default: 1_800_000 — 30 minutes)
|
|
81
|
+
*/
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Exponential backoff for **error retries only**. Does not affect
|
|
85
|
+
* the interval between successful polls (that's `intervalMs`).
|
|
86
|
+
*
|
|
87
|
+
* - `true` — use defaults: `{ initialMs: 1000, multiplier: 2, maxMs: 30000 }`
|
|
88
|
+
* - `BackoffConfig` object — customize any or all fields; unset fields use defaults.
|
|
89
|
+
* - `false` / `undefined` — disabled, errors retry with `intervalMs` instead.
|
|
90
|
+
*
|
|
91
|
+
* The backoff counter resets when a poll succeeds.
|
|
92
|
+
*/
|
|
93
|
+
backoff?: boolean | BackoffConfig;
|
|
94
|
+
/**
|
|
95
|
+
* `AbortSignal` for external cancellation (from parent operation, tests, etc.).
|
|
96
|
+
*
|
|
97
|
+
* When the signal fires, the current sleep is interrupted immediately and
|
|
98
|
+
* `pollUntil` returns with `outcome: "interrupted"`.
|
|
99
|
+
*
|
|
100
|
+
* For SIGINT/SIGTERM support, use `createPollAbortController()` at the CLI
|
|
101
|
+
* entry point and pass its signal here.
|
|
102
|
+
*/
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
/**
|
|
105
|
+
* Max consecutive poll errors before aborting (throwing).
|
|
106
|
+
*
|
|
107
|
+
* - `> 0` — throw after this many consecutive failures.
|
|
108
|
+
* - `0` — never auto-abort on errors. Only timeout, `onError` returning
|
|
109
|
+
* `"abort"`, or signal interruption stops polling. Used by consumers
|
|
110
|
+
* that expect transient errors (e.g., integration-service OAuth,
|
|
111
|
+
* trace streaming with 404s during startup).
|
|
112
|
+
*
|
|
113
|
+
* (default: 3)
|
|
114
|
+
*/
|
|
115
|
+
maxConsecutiveErrors?: number;
|
|
116
|
+
/**
|
|
117
|
+
* Label for log messages (e.g., `"job abc123"`, `"deployment xyz"`).
|
|
118
|
+
*
|
|
119
|
+
* When provided, `pollUntil` emits structured log lines via `logger.info`
|
|
120
|
+
* for start, progress, status changes, errors, and completion.
|
|
121
|
+
*
|
|
122
|
+
* Omit for silent mode — zero log output from the utility. Consumers
|
|
123
|
+
* can still use callbacks (`onPoll`, etc.) for custom logging.
|
|
124
|
+
*/
|
|
125
|
+
label?: string;
|
|
126
|
+
/**
|
|
127
|
+
* Prefix for log messages. Appears as `[prefix]` before each log line.
|
|
128
|
+
* (default: `"wait"`)
|
|
129
|
+
*
|
|
130
|
+
* Override to match your command name, e.g. `"deploy"`, `"activate"`.
|
|
131
|
+
*/
|
|
132
|
+
logPrefix?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Interval between progress log lines in ms.
|
|
135
|
+
*
|
|
136
|
+
* Progress lines are only emitted when `label` is provided.
|
|
137
|
+
*
|
|
138
|
+
* (default: 30_000)
|
|
139
|
+
*/
|
|
140
|
+
logIntervalMs?: number;
|
|
141
|
+
/**
|
|
142
|
+
* Called BEFORE each poll. Async-capable.
|
|
143
|
+
*
|
|
144
|
+
* Use for token refresh, rate-limit checks, or any pre-flight logic.
|
|
145
|
+
* If this throws, the error is treated as a poll error (increments
|
|
146
|
+
* `consecutiveErrors`, fires `onError`, follows retry logic).
|
|
147
|
+
*/
|
|
148
|
+
beforePoll?: (ctx: PollContext<T>) => void | Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Called after each successful `fn()` call.
|
|
151
|
+
*
|
|
152
|
+
* Fires on EVERY successful poll, including the terminal one (before
|
|
153
|
+
* `onComplete`). Consumers that need to emit incremental data (e.g.,
|
|
154
|
+
* trace streaming with span deduplication) use this callback.
|
|
155
|
+
*/
|
|
156
|
+
onPoll?: (result: T, elapsedMs: number) => void;
|
|
157
|
+
/**
|
|
158
|
+
* Called when `getStatus()` detects a status transition.
|
|
159
|
+
*
|
|
160
|
+
* Only fires when the extracted status string differs from the previous
|
|
161
|
+
* poll's status. `getStatus` must be provided for this to work.
|
|
162
|
+
*/
|
|
163
|
+
onStatusChange?: (newStatus: string, oldStatus: string, result: T) => void;
|
|
164
|
+
/**
|
|
165
|
+
* Called on each poll error (including `beforePoll` errors).
|
|
166
|
+
*
|
|
167
|
+
* Return `"abort"` to stop polling immediately — `pollUntil` will return
|
|
168
|
+
* with `outcome: "aborted"`. Return `void` (or nothing) to continue
|
|
169
|
+
* with the retry/timeout logic.
|
|
170
|
+
*
|
|
171
|
+
* Async-capable: the return value is awaited if a Promise is returned.
|
|
172
|
+
*
|
|
173
|
+
* Use for selective error handling, e.g.:
|
|
174
|
+
* ```ts
|
|
175
|
+
* onError: (error) => {
|
|
176
|
+
* if (error.message.includes("404")) return; // transient, continue
|
|
177
|
+
* return "abort"; // fatal, stop
|
|
178
|
+
* }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
onError?: OnErrorCallback;
|
|
182
|
+
/**
|
|
183
|
+
* Called when polling completes (terminal state reached via `until`).
|
|
184
|
+
*/
|
|
185
|
+
onComplete?: (result: T, elapsedMs: number) => void;
|
|
186
|
+
/**
|
|
187
|
+
* Called when the timeout deadline is reached without a terminal state.
|
|
188
|
+
* `lastResult` may be `undefined` if no poll succeeded.
|
|
189
|
+
*/
|
|
190
|
+
onTimeout?: (lastResult: T | undefined, elapsedMs: number) => void;
|
|
191
|
+
/**
|
|
192
|
+
* Called when polling is interrupted via `AbortSignal`.
|
|
193
|
+
* `lastResult` may be `undefined` if no poll succeeded.
|
|
194
|
+
*/
|
|
195
|
+
onInterrupt?: (lastResult: T | undefined, elapsedMs: number) => void;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Result returned by `pollUntil`.
|
|
199
|
+
*
|
|
200
|
+
* - `"completed"` — `until(result)` returned `true`. `data` is guaranteed to be `T`.
|
|
201
|
+
* - `"timeout"` — deadline reached. `data` is the last successful poll result, or `undefined`.
|
|
202
|
+
* - `"interrupted"` — `AbortSignal` fired. `data` is the last successful poll result, or `undefined`.
|
|
203
|
+
* - `"aborted"` — consumer's `onError` returned `"abort"`. `data` is the last successful poll result, or `undefined`.
|
|
204
|
+
* - `"failed"` — `maxConsecutiveErrors` exceeded. `error` contains the last poll error.
|
|
205
|
+
*/
|
|
206
|
+
export interface PollUntilResult<T> {
|
|
207
|
+
/** The final polled value. Guaranteed `T` when `outcome` is `"completed"`. `T | undefined` otherwise. */
|
|
208
|
+
data: T | undefined;
|
|
209
|
+
/** How the poll ended. Compare with `PollOutcome` constants. */
|
|
210
|
+
outcome: PollOutcome;
|
|
211
|
+
/** Total elapsed time in ms. */
|
|
212
|
+
elapsedMs: number;
|
|
213
|
+
/** The error associated with a non-successful outcome. Set when `outcome` is `"aborted"` or `"failed"`; `undefined` otherwise. */
|
|
214
|
+
error?: Error;
|
|
215
|
+
}
|
|
216
|
+
/** Possible outcomes of a `pollUntil` call. Use instead of string literals. */
|
|
217
|
+
export declare const PollOutcome: {
|
|
218
|
+
/** `until(result)` returned `true`. `data` is guaranteed to be `T`. */
|
|
219
|
+
readonly Completed: "completed";
|
|
220
|
+
/** Deadline reached without terminal state. */
|
|
221
|
+
readonly Timeout: "timeout";
|
|
222
|
+
/** `AbortSignal` fired. */
|
|
223
|
+
readonly Interrupted: "interrupted";
|
|
224
|
+
/** Consumer's `onError` returned `ErrorDecision.Abort`. */
|
|
225
|
+
readonly Aborted: "aborted";
|
|
226
|
+
/** `maxConsecutiveErrors` exceeded. `error` field has the last poll error. */
|
|
227
|
+
readonly Failed: "failed";
|
|
228
|
+
};
|
|
229
|
+
export type PollOutcome = (typeof PollOutcome)[keyof typeof PollOutcome];
|
|
230
|
+
/** Return values from `onError` callback. Use instead of string literals. */
|
|
231
|
+
export declare const ErrorDecision: {
|
|
232
|
+
/** Stop polling immediately. */
|
|
233
|
+
readonly Abort: "abort";
|
|
234
|
+
};
|
|
235
|
+
export type ErrorDecision = (typeof ErrorDecision)[keyof typeof ErrorDecision];
|
|
236
|
+
/** Default values for `PollUntilOptions`. */
|
|
237
|
+
export declare const POLL_DEFAULTS: {
|
|
238
|
+
readonly intervalMs: 5000;
|
|
239
|
+
readonly timeoutMs: 1800000;
|
|
240
|
+
readonly maxConsecutiveErrors: 3;
|
|
241
|
+
readonly logIntervalMs: 30000;
|
|
242
|
+
readonly logPrefix: "wait";
|
|
243
|
+
};
|
|
244
|
+
/** Default values for `BackoffConfig`. */
|
|
245
|
+
export declare const BACKOFF_DEFAULTS: ResolvedBackoffConfig;
|
|
246
|
+
/** Minimum allowed polling interval in ms. Prevents CPU spin on bad dynamic values. */
|
|
247
|
+
export declare const MIN_INTERVAL_MS = 100;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone screen-output helper.
|
|
3
|
+
* Methods here write human-visible messages to the screen,
|
|
4
|
+
* bypassing log-level filtering and file-logging redirection.
|
|
5
|
+
*/
|
|
6
|
+
export declare namespace ScreenLogger {
|
|
7
|
+
/** Write a progress message to the screen. */
|
|
8
|
+
function progress(message: string): void;
|
|
9
|
+
}
|