@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,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-bundle singleton primitive.
|
|
3
|
+
*
|
|
4
|
+
* Each tool bundles its own copy of @uipath/common, so module-level
|
|
5
|
+
* variables are isolated per bundle. This utility uses Symbol.for()
|
|
6
|
+
* keyed slots on globalThis to share state across all bundles.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
*
|
|
10
|
+
* // Class — name derived from constructor:
|
|
11
|
+
* const logger = singleton(SimpleLogger);
|
|
12
|
+
* logger.getOrInit(() => new SimpleLogger());
|
|
13
|
+
*
|
|
14
|
+
* // Type alias or union — explicit name:
|
|
15
|
+
* const format = singleton<OutputFormat>("OutputFormat");
|
|
16
|
+
* format.set("json");
|
|
17
|
+
* format.get("table"); // "json" (value takes precedence)
|
|
18
|
+
*/
|
|
19
|
+
export interface Singleton<T> {
|
|
20
|
+
/** Read the current value, or `fallback` when unset. */
|
|
21
|
+
get(fallback?: T): T | undefined;
|
|
22
|
+
/** Write a new value. */
|
|
23
|
+
set(value: T): void;
|
|
24
|
+
/** Reset to undefined. */
|
|
25
|
+
clear(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Get the existing value, or initialise it with `factory()`.
|
|
28
|
+
* An optional `guard` validates existing values via duck-typing
|
|
29
|
+
* (needed because `instanceof` fails across bundles).
|
|
30
|
+
*/
|
|
31
|
+
getOrInit(factory: () => T, guard?: (value: object) => boolean): T;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a typed singleton backed by `globalThis[Symbol.for(key)]`.
|
|
35
|
+
*
|
|
36
|
+
* @overload Pass a class constructor to derive the key from its name.
|
|
37
|
+
* @overload Pass a string key for non-class types (type aliases, unions).
|
|
38
|
+
*
|
|
39
|
+
* The key is auto-prefixed with `@uipath/common/`.
|
|
40
|
+
*/
|
|
41
|
+
export declare function singleton<T>(ctor: abstract new (...args: any[]) => T): Singleton<T>;
|
|
42
|
+
export declare function singleton<T>(name: string): Singleton<T>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IContextStorage } from "./context-storage.js";
|
|
2
|
+
/**
|
|
3
|
+
* Browser implementation of context storage using a stack-based approach.
|
|
4
|
+
*
|
|
5
|
+
* Unlike Node.js's AsyncLocalStorage which provides automatic context propagation,
|
|
6
|
+
* this implementation uses a simple stack to maintain context. The context remains
|
|
7
|
+
* available for the duration of the async operation because JavaScript is single-threaded
|
|
8
|
+
* and async operations are queued.
|
|
9
|
+
*
|
|
10
|
+
* @template TContext - The type of context to store
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* This implementation works in browser environments without requiring zone.js.
|
|
14
|
+
* Context is maintained on a stack and is available until the async operation completes.
|
|
15
|
+
*/
|
|
16
|
+
export declare class BrowserContextStorage<TContext = unknown> implements IContextStorage<TContext> {
|
|
17
|
+
private contextStack;
|
|
18
|
+
/**
|
|
19
|
+
* Runs a function with the given context.
|
|
20
|
+
* Uses a stack-based approach to maintain context across async operations.
|
|
21
|
+
* The context remains available for the duration of the async operation.
|
|
22
|
+
*/
|
|
23
|
+
run<T>(context: TContext, fn: () => T): T;
|
|
24
|
+
/**
|
|
25
|
+
* Gets the current context from the context stack.
|
|
26
|
+
* Returns undefined if no context is available (not within a run() block).
|
|
27
|
+
*/
|
|
28
|
+
getContext(): TContext | undefined;
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
+
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
3
|
+
/**
|
|
4
|
+
* A simple telemetry provider that logs events to the console.
|
|
5
|
+
* Useful for development and testing. Browser-safe (no Node API dependencies).
|
|
6
|
+
*/
|
|
7
|
+
export declare class ConsoleTelemetryProvider implements ITelemetryProvider {
|
|
8
|
+
trackEvent(eventName: string, _properties?: TelemetryProperties): Promise<void>;
|
|
9
|
+
trackException(error: Error, _properties?: TelemetryProperties): Promise<void>;
|
|
10
|
+
trackRequest(name: string, duration: number, success: boolean, _properties?: TelemetryProperties): Promise<void>;
|
|
11
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, _properties?: TelemetryProperties): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface for storing and retrieving context in async operations.
|
|
3
|
+
* @template TContext - The type of context to store
|
|
4
|
+
*/
|
|
5
|
+
export interface IContextStorage<TContext = unknown> {
|
|
6
|
+
/**
|
|
7
|
+
* Runs a function with a given context, making it available to all
|
|
8
|
+
* async operations within the execution tree.
|
|
9
|
+
* @param context - The context to store
|
|
10
|
+
* @param fn - The function to execute with this context
|
|
11
|
+
* @returns The result of the function
|
|
12
|
+
*/
|
|
13
|
+
run<T>(context: TContext, fn: () => T): T;
|
|
14
|
+
/**
|
|
15
|
+
* Gets the current context for the executing async operation.
|
|
16
|
+
* @returns The current context, or undefined if not within a run() call
|
|
17
|
+
*/
|
|
18
|
+
getContext(): TContext | undefined;
|
|
19
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
+
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
3
|
+
/**
|
|
4
|
+
* A simple telemetry provider that logs events via the shared logger.
|
|
5
|
+
* Useful for development and testing.
|
|
6
|
+
*/
|
|
7
|
+
export declare class DebugTelemetryProvider implements ITelemetryProvider {
|
|
8
|
+
trackEvent(eventName: string, _properties?: TelemetryProperties): Promise<void>;
|
|
9
|
+
trackException(error: Error, _properties?: TelemetryProperties): Promise<void>;
|
|
10
|
+
trackRequest(name: string, duration: number, success: boolean, _properties?: TelemetryProperties): Promise<void>;
|
|
11
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, _properties?: TelemetryProperties): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect which AI coding agent (if any) is invoking the CLI
|
|
3
|
+
* by checking known environment variables.
|
|
4
|
+
*
|
|
5
|
+
* Tool-specific variables are checked first (most reliable),
|
|
6
|
+
* then the generic `AGENT` variable (emerging standard from
|
|
7
|
+
* https://github.com/agentsmd/agents.md/issues/136).
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Detect the AI coding agent invoking the CLI.
|
|
11
|
+
* Returns the agent identifier string, or `undefined` if no agent is detected.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectAgent(): string | undefined;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { BrowserContextStorage } from "./browser-context-storage.js";
|
|
2
|
+
export { ConsoleTelemetryProvider } from "./console-telemetry-provider.js";
|
|
3
|
+
export type { IContextStorage } from "./context-storage.js";
|
|
4
|
+
export { redactProperties, redactProperty } from "./pii-redactor.js";
|
|
5
|
+
export type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
6
|
+
export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
|
|
7
|
+
export { TelemetryService } from "./telemetry-service.js";
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
// src/telemetry/browser-context-storage.ts
|
|
2
|
+
class BrowserContextStorage {
|
|
3
|
+
contextStack = [];
|
|
4
|
+
run(context, fn) {
|
|
5
|
+
this.contextStack.push(context);
|
|
6
|
+
try {
|
|
7
|
+
const result = fn();
|
|
8
|
+
if (result !== null && typeof result === "object" && typeof result.then === "function") {
|
|
9
|
+
return result.finally(() => {
|
|
10
|
+
this.contextStack.pop();
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
this.contextStack.pop();
|
|
14
|
+
return result;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
this.contextStack.pop();
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
getContext() {
|
|
21
|
+
return this.contextStack.length > 0 ? this.contextStack[this.contextStack.length - 1] : undefined;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// src/telemetry/console-telemetry-provider.ts
|
|
25
|
+
class ConsoleTelemetryProvider {
|
|
26
|
+
async trackEvent(eventName, _properties) {
|
|
27
|
+
console.debug(`[Telemetry] Event: ${eventName}`);
|
|
28
|
+
}
|
|
29
|
+
async trackException(error, _properties) {
|
|
30
|
+
console.error(`[Telemetry] Exception: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
async trackRequest(name, duration, success, _properties) {
|
|
33
|
+
console.debug(`[Telemetry] Request: ${name} (${duration}ms, ${success ? "ok" : "fail"})`);
|
|
34
|
+
}
|
|
35
|
+
async trackDependency(name, type, duration, success, _properties) {
|
|
36
|
+
console.debug(`[Telemetry] Dependency: ${name} [${type}] (${duration}ms, ${success ? "ok" : "fail"})`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// src/telemetry/pii-redactor.ts
|
|
40
|
+
var REDACTED = "[REDACTED]";
|
|
41
|
+
var MAX_VALUE_LENGTH = 200;
|
|
42
|
+
var SENSITIVE_NAME_TOKENS = new Set([
|
|
43
|
+
"token",
|
|
44
|
+
"tokens",
|
|
45
|
+
"secret",
|
|
46
|
+
"secrets",
|
|
47
|
+
"password",
|
|
48
|
+
"passwords",
|
|
49
|
+
"pwd",
|
|
50
|
+
"credential",
|
|
51
|
+
"credentials",
|
|
52
|
+
"auth",
|
|
53
|
+
"authentication",
|
|
54
|
+
"authorization",
|
|
55
|
+
"authority",
|
|
56
|
+
"cert",
|
|
57
|
+
"certificate",
|
|
58
|
+
"certificates"
|
|
59
|
+
]);
|
|
60
|
+
var SENSITIVE_KEY_PREFIXES = new Set([
|
|
61
|
+
"api",
|
|
62
|
+
"access",
|
|
63
|
+
"client",
|
|
64
|
+
"private",
|
|
65
|
+
"public",
|
|
66
|
+
"signing",
|
|
67
|
+
"encryption",
|
|
68
|
+
"session",
|
|
69
|
+
"master",
|
|
70
|
+
"shared",
|
|
71
|
+
"root",
|
|
72
|
+
"ssh",
|
|
73
|
+
"rsa",
|
|
74
|
+
"aes",
|
|
75
|
+
"hmac",
|
|
76
|
+
"oauth"
|
|
77
|
+
]);
|
|
78
|
+
var UUID_PATTERN = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
|
|
79
|
+
var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
|
|
80
|
+
var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
|
|
81
|
+
var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
|
|
82
|
+
var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
|
|
83
|
+
var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
|
|
84
|
+
var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
|
|
85
|
+
function shortHash(input) {
|
|
86
|
+
let hash = 2166136261;
|
|
87
|
+
for (let i = 0;i < input.length; i++) {
|
|
88
|
+
hash ^= input.charCodeAt(i);
|
|
89
|
+
hash = Math.imul(hash, 16777619);
|
|
90
|
+
}
|
|
91
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
92
|
+
}
|
|
93
|
+
function redactUrl(raw) {
|
|
94
|
+
try {
|
|
95
|
+
const url = new URL(raw);
|
|
96
|
+
return `${url.protocol}//${url.host}`;
|
|
97
|
+
} catch {
|
|
98
|
+
return `url#${shortHash(raw)}`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function redactValueDetectors(value) {
|
|
102
|
+
let out = value;
|
|
103
|
+
out = out.replace(JWT_PATTERN, () => REDACTED);
|
|
104
|
+
out = out.replace(URL_PATTERN, (match) => {
|
|
105
|
+
const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
|
|
106
|
+
const core = trailing ? match.slice(0, -trailing.length) : match;
|
|
107
|
+
return `${redactUrl(core)}${trailing}`;
|
|
108
|
+
});
|
|
109
|
+
out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
|
|
110
|
+
out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
|
|
111
|
+
out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
|
|
112
|
+
out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
|
|
113
|
+
if (out.length > MAX_VALUE_LENGTH) {
|
|
114
|
+
out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
function nameTokens(name) {
|
|
119
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").split(/[\s_-]+/).map((t) => t.toLowerCase()).filter(Boolean);
|
|
120
|
+
}
|
|
121
|
+
function isSensitiveName(name) {
|
|
122
|
+
const tokens = nameTokens(name);
|
|
123
|
+
for (let i = 0;i < tokens.length; i++) {
|
|
124
|
+
const token = tokens[i];
|
|
125
|
+
if (SENSITIVE_NAME_TOKENS.has(token)) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
if (token === "key" || token === "keys") {
|
|
129
|
+
const prev = tokens[i - 1];
|
|
130
|
+
if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
function redactProperty(name, value) {
|
|
138
|
+
if (value === undefined || value === null) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (isSensitiveName(name)) {
|
|
142
|
+
return REDACTED;
|
|
143
|
+
}
|
|
144
|
+
if (typeof value === "boolean" || typeof value === "number") {
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
if (typeof value !== "string") {
|
|
148
|
+
return "[OBJECT]";
|
|
149
|
+
}
|
|
150
|
+
return redactValueDetectors(value);
|
|
151
|
+
}
|
|
152
|
+
function redactProperties(properties) {
|
|
153
|
+
const out = {};
|
|
154
|
+
for (const [name, value] of Object.entries(properties)) {
|
|
155
|
+
const redacted = redactProperty(name, value);
|
|
156
|
+
if (redacted !== undefined) {
|
|
157
|
+
out[name] = redacted;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
// src/telemetry/telemetry-service.ts
|
|
163
|
+
class TelemetryService {
|
|
164
|
+
telemetryProvider;
|
|
165
|
+
contextStorage;
|
|
166
|
+
operationId;
|
|
167
|
+
defaultProperties;
|
|
168
|
+
constructor(telemetryProvider, contextStorage) {
|
|
169
|
+
this.telemetryProvider = telemetryProvider;
|
|
170
|
+
this.contextStorage = contextStorage;
|
|
171
|
+
}
|
|
172
|
+
setOperationId(operationId) {
|
|
173
|
+
this.operationId = operationId;
|
|
174
|
+
}
|
|
175
|
+
setProvider(provider) {
|
|
176
|
+
this.telemetryProvider = provider;
|
|
177
|
+
}
|
|
178
|
+
setDefaultProperties(properties) {
|
|
179
|
+
this.defaultProperties = properties;
|
|
180
|
+
}
|
|
181
|
+
trackEvent(name, properties) {
|
|
182
|
+
const context = this.getCurrentContext();
|
|
183
|
+
const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
|
|
184
|
+
this.telemetryProvider.trackEvent(name, enrichedProperties);
|
|
185
|
+
}
|
|
186
|
+
trackException(error, properties) {
|
|
187
|
+
const context = this.getCurrentContext();
|
|
188
|
+
const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
|
|
189
|
+
this.telemetryProvider.trackException(error, enrichedProperties);
|
|
190
|
+
}
|
|
191
|
+
async trackRequest(name, fn, properties) {
|
|
192
|
+
const context = {
|
|
193
|
+
operationId: this.operationId ?? this.generateId(),
|
|
194
|
+
id: this.generateId()
|
|
195
|
+
};
|
|
196
|
+
const startTime = performance.now();
|
|
197
|
+
try {
|
|
198
|
+
const result = await this.contextStorage.run(context, fn);
|
|
199
|
+
const durationMs = performance.now() - startTime;
|
|
200
|
+
const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
|
|
201
|
+
await this.telemetryProvider.trackRequest(name, durationMs, true, enrichedProperties);
|
|
202
|
+
return result;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
const durationMs = performance.now() - startTime;
|
|
205
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
206
|
+
const enrichedProperties = this.enrichPropertiesWithContext({ ...properties, errorMessage: err.message }, context);
|
|
207
|
+
await this.telemetryProvider.trackRequest(name, durationMs, false, enrichedProperties);
|
|
208
|
+
throw error;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async trackDependencyOperation(name, type, fn, properties) {
|
|
212
|
+
const parentContext = this.getCurrentContext();
|
|
213
|
+
if (!parentContext) {
|
|
214
|
+
throw new Error("trackDependencyOperation must be called within a trackRequest block.");
|
|
215
|
+
}
|
|
216
|
+
const childContext = {
|
|
217
|
+
operationId: parentContext.operationId,
|
|
218
|
+
parentId: parentContext.id,
|
|
219
|
+
id: this.generateId()
|
|
220
|
+
};
|
|
221
|
+
const startTime = performance.now();
|
|
222
|
+
try {
|
|
223
|
+
const result = await this.contextStorage.run(childContext, fn);
|
|
224
|
+
const durationMs = performance.now() - startTime;
|
|
225
|
+
const enrichedProperties = this.enrichPropertiesWithContext(properties, childContext);
|
|
226
|
+
await this.telemetryProvider.trackDependency(name, type, durationMs, true, enrichedProperties);
|
|
227
|
+
return result;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
const durationMs = performance.now() - startTime;
|
|
230
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
231
|
+
const enrichedProperties = this.enrichPropertiesWithContext({ ...properties, errorMessage: err.message }, childContext);
|
|
232
|
+
await this.telemetryProvider.trackDependency(name, type, durationMs, false, enrichedProperties);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
getCurrentContext() {
|
|
237
|
+
return this.contextStorage.getContext();
|
|
238
|
+
}
|
|
239
|
+
enrichPropertiesWithContext(properties, context) {
|
|
240
|
+
return {
|
|
241
|
+
...this.defaultProperties,
|
|
242
|
+
...properties,
|
|
243
|
+
...context
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
generateId() {
|
|
247
|
+
return crypto.randomUUID().replaceAll("-", "");
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
export {
|
|
251
|
+
redactProperty,
|
|
252
|
+
redactProperties,
|
|
253
|
+
TelemetryService,
|
|
254
|
+
ConsoleTelemetryProvider,
|
|
255
|
+
BrowserContextStorage
|
|
256
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
+
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
3
|
+
/**
|
|
4
|
+
* Telemetry provider that enriches all events with analyticsUniqueId
|
|
5
|
+
* from the Windows registry and forwards them to the shared logger.
|
|
6
|
+
*/
|
|
7
|
+
export declare class LoggerTelemetryProvider implements ITelemetryProvider {
|
|
8
|
+
private readonly analyticsUniqueId;
|
|
9
|
+
constructor();
|
|
10
|
+
private enrich;
|
|
11
|
+
trackEvent(eventName: string, properties?: TelemetryProperties): Promise<void>;
|
|
12
|
+
trackException(error: Error, properties?: TelemetryProperties): Promise<void>;
|
|
13
|
+
trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
14
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
+
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
3
|
+
export declare function setGlobalTelemetryProperties(properties: TelemetryProperties): void;
|
|
4
|
+
export declare function getGlobalTelemetryProperties(): TelemetryProperties | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Node.js Application Insights telemetry provider.
|
|
7
|
+
* Uses the `applicationinsights` Node SDK (not the browser SDK).
|
|
8
|
+
*
|
|
9
|
+
* The provider is created asynchronously because `applicationinsights` is
|
|
10
|
+
* loaded via dynamic import — it may not be installed in all packages.
|
|
11
|
+
*/
|
|
12
|
+
export declare class NodeAppInsightsTelemetryProvider implements ITelemetryProvider {
|
|
13
|
+
private readonly connectionString;
|
|
14
|
+
private client;
|
|
15
|
+
private appInsightsModule;
|
|
16
|
+
private readonly _sessionId;
|
|
17
|
+
private initialized;
|
|
18
|
+
constructor(connectionString: string);
|
|
19
|
+
/**
|
|
20
|
+
* Initialize the provider by dynamically importing applicationinsights.
|
|
21
|
+
* Returns false if the package is not available.
|
|
22
|
+
*/
|
|
23
|
+
initialize(): Promise<boolean>;
|
|
24
|
+
getSessionId(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Set the Application Version context tag (`ai.application.ver`).
|
|
27
|
+
* Must be called after {@link initialize}.
|
|
28
|
+
*/
|
|
29
|
+
setApplicationVersion(version: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Merge global default properties with per-call properties.
|
|
32
|
+
* Per-call properties take precedence over global defaults.
|
|
33
|
+
*/
|
|
34
|
+
private mergeProperties;
|
|
35
|
+
trackEvent(eventName: string, properties?: TelemetryProperties): Promise<void>;
|
|
36
|
+
trackException(error: Error, properties?: TelemetryProperties): Promise<void>;
|
|
37
|
+
trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
38
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
39
|
+
flush(): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Dispose the Application Insights SDK so its internal channels,
|
|
42
|
+
* keep-alive sockets, and timers are closed — allowing the Node.js
|
|
43
|
+
* event loop to drain and the process to exit naturally.
|
|
44
|
+
*
|
|
45
|
+
* IMPORTANT: The caller must NOT call `process.exit()` after this.
|
|
46
|
+
* On Windows, forcing exit while libuv handles from the preceding
|
|
47
|
+
* `flush()` are still closing triggers
|
|
48
|
+
* `!(handle->flags & UV_HANDLE_CLOSING)` in `uv_async_send`.
|
|
49
|
+
* Instead, set `process.exitCode` and let the loop drain.
|
|
50
|
+
*/
|
|
51
|
+
shutdown(): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get or create the single shared provider instance.
|
|
55
|
+
* The first call creates the provider and stores it on globalThis;
|
|
56
|
+
* subsequent calls (from other bundled copies) return the same instance.
|
|
57
|
+
*
|
|
58
|
+
* Now async — must be awaited. Returns undefined if applicationinsights
|
|
59
|
+
* is not installed. Stores the init promise on globalThis to prevent
|
|
60
|
+
* concurrent callers from creating duplicate providers.
|
|
61
|
+
*/
|
|
62
|
+
export declare function getOrCreateProvider(connectionString: string): Promise<NodeAppInsightsTelemetryProvider | undefined>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IContextStorage } from "./context-storage.js";
|
|
2
|
+
/**
|
|
3
|
+
* Node.js implementation of context storage using AsyncLocalStorage.
|
|
4
|
+
* This provides proper async context propagation in Node.js environments.
|
|
5
|
+
* @template TContext - The type of context to store
|
|
6
|
+
*/
|
|
7
|
+
export declare class NodeContextStorage<TContext = unknown> implements IContextStorage<TContext> {
|
|
8
|
+
private readonly storage;
|
|
9
|
+
run<T>(context: TContext, fn: () => T): T;
|
|
10
|
+
getContext(): TContext | undefined;
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { IContextStorage } from "./context-storage.js";
|
|
2
|
+
export { DebugTelemetryProvider } from "./debug-telemetry-provider.js";
|
|
3
|
+
export { detectAgent } from "./detect-agent.js";
|
|
4
|
+
export { NodeContextStorage } from "./node-context-storage.js";
|
|
5
|
+
export type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
6
|
+
export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
|
|
7
|
+
export { TelemetryService } from "./telemetry-service.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PII redactor for telemetry property values.
|
|
3
|
+
*
|
|
4
|
+
* Two layers, applied in order:
|
|
5
|
+
* 1. Name-based hard redact — property names are split on camelCase,
|
|
6
|
+
* snake_case, and kebab-case boundaries, then any token matches a
|
|
7
|
+
* sensitive-word set (token/secret/password/pwd/credential/auth/
|
|
8
|
+
* certificate) triggers [REDACTED]. `key` is only flagged when preceded
|
|
9
|
+
* by a sensitive prefix (apiKey, accessKey, signingKey, …) so benign
|
|
10
|
+
* names like sortKey, cacheKey, keyword pass through.
|
|
11
|
+
* 2. Value detectors — JWTs, UUIDs, emails, URLs, user-home paths are
|
|
12
|
+
* rewritten to a non-reversible form (hash or structural redaction).
|
|
13
|
+
* Long strings are truncated.
|
|
14
|
+
*
|
|
15
|
+
* The goal is defense in depth: even if a new sensitive option slips through
|
|
16
|
+
* without being added to the denylist, value detectors catch common shapes.
|
|
17
|
+
*/
|
|
18
|
+
type TelemetryValue = string | number | boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Redact a single telemetry property.
|
|
21
|
+
* Preserves the original value's type (number/boolean pass through unchanged);
|
|
22
|
+
* strings are scanned for sensitive shapes. Returns undefined for null/undefined
|
|
23
|
+
* so callers can drop the key.
|
|
24
|
+
*/
|
|
25
|
+
export declare function redactProperty(name: string, value: unknown): TelemetryValue | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Redact an entire property bag. Preserves each value's native type
|
|
28
|
+
* (numbers stay numbers, booleans stay booleans) so downstream sinks like
|
|
29
|
+
* App Insights can still aggregate them as metrics. Undefined values are dropped.
|
|
30
|
+
*/
|
|
31
|
+
export declare function redactProperties(properties: Record<string, unknown>): Record<string, TelemetryValue>;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ITelemetryProvider, ITelemetryService } from "./node.js";
|
|
2
|
+
import { type NodeAppInsightsTelemetryProvider } from "./node-appinsights-telemetry-provider.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create or retrieve the shared Node.js Application Insights telemetry provider.
|
|
5
|
+
* Uses globalThis to ensure all bundled copies share a single TelemetryClient.
|
|
6
|
+
* Returns undefined if the applicationinsights package is not installed.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createAppInsightsProvider(): Promise<NodeAppInsightsTelemetryProvider | undefined>;
|
|
9
|
+
/**
|
|
10
|
+
* Check whether telemetry is disabled via environment variable.
|
|
11
|
+
* Set UIPATH_TELEMETRY_DISABLED=1 or UIPATH_TELEMETRY_DISABLED=true to opt out.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isTelemetryDisabled(): boolean;
|
|
14
|
+
interface TelemetryProviderResult {
|
|
15
|
+
provider: ITelemetryProvider;
|
|
16
|
+
name: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create the default telemetry provider (async).
|
|
20
|
+
* Uses Application Insights (Node SDK) by default, falls back to
|
|
21
|
+
* LoggerTelemetryProvider if telemetry is disabled, initialization
|
|
22
|
+
* fails, or the applicationinsights package is not installed.
|
|
23
|
+
*
|
|
24
|
+
* Returns both the provider and its name so callers can log which
|
|
25
|
+
* provider was selected without relying on module-level mutable state.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createTelemetryProvider(): Promise<TelemetryProviderResult>;
|
|
28
|
+
export declare const telemetry: ITelemetryService;
|
|
29
|
+
export interface TelemetryInitOptions {
|
|
30
|
+
/** Application version — sets the standard `ai.application.ver` context tag. */
|
|
31
|
+
version?: string;
|
|
32
|
+
/** Custom dimensions added to every telemetry event. */
|
|
33
|
+
defaultProperties?: Record<string, string>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Initialize telemetry with default properties.
|
|
37
|
+
* Call after logger is configured (e.g. after --log-file is processed).
|
|
38
|
+
*
|
|
39
|
+
* This is async — it awaits the dynamic import of applicationinsights.
|
|
40
|
+
* Must be awaited to ensure the correct provider is selected before
|
|
41
|
+
* telemetry events are tracked.
|
|
42
|
+
*
|
|
43
|
+
* The resulting TelemetryService instance is stored on globalThis so that
|
|
44
|
+
* tool bundles (which don't ship applicationinsights) can reuse it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function telemetryInit(options?: TelemetryInitOptions): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Flush all buffered telemetry to the cloud.
|
|
49
|
+
* Must be awaited before the process exits to ensure delivery.
|
|
50
|
+
* Capped at FLUSH_SHUTDOWN_TIMEOUT_MS to avoid hanging on slow/unreachable endpoints.
|
|
51
|
+
*/
|
|
52
|
+
export declare function telemetryFlushAndShutdown(): Promise<void>;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
2
|
+
/**
|
|
3
|
+
* Interface for telemetry providers that can be injected into the solution packager.
|
|
4
|
+
* Providers are simple adapters that send pre-measured telemetry data to their backends.
|
|
5
|
+
*/
|
|
6
|
+
export interface ITelemetryProvider {
|
|
7
|
+
/**
|
|
8
|
+
* Track a custom event with optional properties.
|
|
9
|
+
*/
|
|
10
|
+
trackEvent(eventName: string, properties?: TelemetryProperties): Promise<void>;
|
|
11
|
+
/**
|
|
12
|
+
* Track an exception with optional properties.
|
|
13
|
+
*/
|
|
14
|
+
trackException(error: Error, properties?: TelemetryProperties): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Track a completed request operation with measured duration.
|
|
17
|
+
*/
|
|
18
|
+
trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Track a completed dependency operation with measured duration.
|
|
21
|
+
*/
|
|
22
|
+
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Get the current session ID, if available.
|
|
25
|
+
*/
|
|
26
|
+
getSessionId?(): string | undefined;
|
|
27
|
+
}
|