@uipath/common 1.201.0 → 1.202.0-preview.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catch-error.d.ts +14 -0
- package/dist/catch-error.js +259 -10
- package/dist/classified-failure.d.ts +28 -0
- package/dist/entity-name-rules.d.ts +18 -0
- package/dist/entity-name-rules.js +241 -0
- package/dist/error-handler.d.ts +13 -0
- package/dist/exit-code.d.ts +42 -0
- package/dist/formatter.d.ts +34 -5
- package/dist/index.browser.d.ts +3 -0
- package/dist/index.browser.js +11328 -10486
- package/dist/index.d.ts +10 -1
- package/dist/index.js +12320 -11208
- package/dist/logger.d.ts +15 -0
- package/dist/package-metadata-options.js +3 -3
- package/dist/polling/poll-failure-mapping.d.ts +15 -1
- package/dist/sdk-user-agent.js +6 -6
- package/dist/telemetry/command-name.d.ts +60 -0
- package/dist/telemetry/console-telemetry-provider.d.ts +5 -6
- package/dist/telemetry/debug-telemetry-provider.d.ts +5 -6
- package/dist/telemetry/index.d.ts +3 -3
- package/dist/telemetry/index.js +18581 -105
- package/dist/telemetry/invocation-request.d.ts +38 -0
- package/dist/telemetry/logger-telemetry-provider.d.ts +5 -6
- package/dist/telemetry/node-appinsights-telemetry-provider.d.ts +17 -29
- package/dist/telemetry/node.d.ts +2 -2
- package/dist/telemetry/packaged-name.d.ts +22 -0
- package/dist/telemetry/pii-redactor.d.ts +110 -13
- package/dist/telemetry/pseudonymize.d.ts +57 -0
- package/dist/telemetry/span-clock.d.ts +27 -0
- package/dist/telemetry/supplied-values.d.ts +59 -0
- package/dist/telemetry/telemetry-init.d.ts +27 -0
- package/dist/telemetry/telemetry-provider.d.ts +84 -16
- package/dist/telemetry/telemetry-service.d.ts +71 -41
- package/dist/telemetry/telemetry-spool.d.ts +17 -0
- package/dist/timings.d.ts +99 -0
- package/dist/trackedAction.d.ts +25 -2
- package/package.json +6 -2
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { TelemetryContext, TelemetryProperties } from "./telemetry-service.js";
|
|
2
|
+
/**
|
|
3
|
+
* Open this invocation's request scope and run `fn` inside it.
|
|
4
|
+
*
|
|
5
|
+
* Call once, as early in the run as there is a run — inside the timing scope,
|
|
6
|
+
* since the span's start and duration are read from the invocation's baseline.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runWithInvocationRequest<T>(fn: () => Promise<T>): Promise<T>;
|
|
9
|
+
/**
|
|
10
|
+
* Run `fn` inside the invocation's request scope, opening one only if nothing
|
|
11
|
+
* has.
|
|
12
|
+
*
|
|
13
|
+
* For a caller that cannot assume the entry point ran: the standalone tool bins
|
|
14
|
+
* (`packages/*/src/index.ts`) go straight to Commander, so without this their
|
|
15
|
+
* commands would have no scope and their outbound calls would go untracked.
|
|
16
|
+
*/
|
|
17
|
+
export declare function ensureInvocationRequestScope<T>(fn: () => Promise<T>): Promise<T>;
|
|
18
|
+
/**
|
|
19
|
+
* This invocation's request context — the span every dependency and leaf in the
|
|
20
|
+
* run hangs under. `undefined` before the scope is opened.
|
|
21
|
+
*
|
|
22
|
+
* The active context wins over the slot, because it is the per-invocation one:
|
|
23
|
+
* in a host running two commands at once (the MCP bridge) the slot holds
|
|
24
|
+
* whichever opened last, so reading it alone made one command's request
|
|
25
|
+
* envelope ship under the other's span id.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getInvocationRequestContext(): TelemetryContext | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Emit this invocation's request span. One call per run.
|
|
30
|
+
*
|
|
31
|
+
* Duration is read here rather than passed in, so it covers everything from the
|
|
32
|
+
* invocation's start to this moment. The only part of the run left out is the
|
|
33
|
+
* telemetry flush, which is what sends this envelope — a span cannot contain
|
|
34
|
+
* its own delivery.
|
|
35
|
+
*/
|
|
36
|
+
export declare function emitInvocationRequest(name: string, success: boolean, properties?: TelemetryProperties): void;
|
|
37
|
+
/** Drop the scope, so the next invocation in this process opens its own. */
|
|
38
|
+
export declare function resetInvocationRequest(): void;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
-
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
1
|
+
import type { ITelemetryProvider, TrackedDependencySpan, TrackedEvent, TrackedException, TrackedSpan } from "./telemetry-provider.js";
|
|
3
2
|
/**
|
|
4
3
|
* Telemetry provider that enriches all events with analyticsUniqueId
|
|
5
4
|
* from the Windows registry and forwards them to the shared logger.
|
|
@@ -8,8 +7,8 @@ export declare class LoggerTelemetryProvider implements ITelemetryProvider {
|
|
|
8
7
|
private readonly analyticsUniqueId;
|
|
9
8
|
constructor();
|
|
10
9
|
private enrich;
|
|
11
|
-
trackEvent(
|
|
12
|
-
trackException(error
|
|
13
|
-
trackRequest(name
|
|
14
|
-
trackDependency(name
|
|
10
|
+
trackEvent({ name, properties }: TrackedEvent): Promise<void>;
|
|
11
|
+
trackException({ error, properties, }: TrackedException): Promise<void>;
|
|
12
|
+
trackRequest({ name, durationMs, success, properties, }: TrackedSpan): Promise<void>;
|
|
13
|
+
trackDependency({ name, type, durationMs, success, properties, }: TrackedDependencySpan): Promise<void>;
|
|
15
14
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
2
|
-
import { type TelemetryProperties } from "./telemetry-service.js";
|
|
1
|
+
import type { ITelemetryProvider, TrackedDependencySpan, TrackedEvent, TrackedException, TrackedSpan } from "./telemetry-provider.js";
|
|
3
2
|
export { getGlobalTelemetryProperties, setGlobalTelemetryProperties, } from "./global-telemetry-properties.js";
|
|
4
3
|
/**
|
|
5
4
|
* Envelopes still buffered in the SDK channel at exit, plus the ingestion
|
|
@@ -43,40 +42,29 @@ export declare class NodeAppInsightsTelemetryProvider implements ITelemetryProvi
|
|
|
43
42
|
*/
|
|
44
43
|
private mergeProperties;
|
|
45
44
|
/**
|
|
46
|
-
*
|
|
47
|
-
* strip them, so nothing correlation-related ever ships as a custom
|
|
48
|
-
* dimension. `merged` is a fresh per-call object, so mutating it in place is
|
|
49
|
-
* safe; the same reference is what the client call emits as `properties`.
|
|
45
|
+
* Native correlation tags for any tracked item.
|
|
50
46
|
*
|
|
51
|
-
* `
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* dependency's id (the context's `spanId`), present only inside a scope.
|
|
47
|
+
* `operation_Id` is the trace; `operation_ParentId` is whatever the item
|
|
48
|
+
* hangs under — for a span its parent span, for a leaf (event/exception)
|
|
49
|
+
* the span it was emitted inside. Both arrive as fields on the item, so
|
|
50
|
+
* one mapping serves requests, dependencies, events and exceptions alike,
|
|
51
|
+
* and nothing correlation-related has to be read out of — or stripped
|
|
52
|
+
* from — the custom dimensions.
|
|
53
|
+
*
|
|
54
|
+
* `operationId` falls back to the per-invocation id for an item emitted
|
|
55
|
+
* outside any scope, so every item in one run still groups under the same
|
|
56
|
+
* `operation_Id`.
|
|
62
57
|
*
|
|
63
58
|
* Cross-service join: `makeTrackedFetch` stamps a W3C `traceparent`
|
|
64
59
|
* (`00-<operation_Id>-<span>-01`) on every outbound call made inside a
|
|
65
60
|
* request scope, so the API side can line its telemetry up with this trace.
|
|
66
61
|
* These native tags are the CLI-side half of that join.
|
|
67
62
|
*/
|
|
68
|
-
private
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
* context's `parentId` (absent for a top-level request → a trace root).
|
|
74
|
-
*/
|
|
75
|
-
private operationCorrelation;
|
|
76
|
-
trackEvent(eventName: string, properties?: TelemetryProperties): Promise<void>;
|
|
77
|
-
trackException(error: Error, properties?: TelemetryProperties): Promise<void>;
|
|
78
|
-
trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
|
|
79
|
-
trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties, resultCode?: string): Promise<void>;
|
|
63
|
+
private correlationTags;
|
|
64
|
+
trackEvent(event: TrackedEvent): Promise<void>;
|
|
65
|
+
trackException(exception: TrackedException): Promise<void>;
|
|
66
|
+
trackRequest(span: TrackedSpan): Promise<void>;
|
|
67
|
+
trackDependency(span: TrackedDependencySpan): Promise<void>;
|
|
80
68
|
flush(): Promise<void>;
|
|
81
69
|
/**
|
|
82
70
|
* Take the envelopes still buffered in the SDK channel (nothing has sent
|
package/dist/telemetry/node.d.ts
CHANGED
|
@@ -5,8 +5,8 @@ export { buildEnvironmentProperties, type NormalizedEnvironment, normalizeBaseUr
|
|
|
5
5
|
export { type CiProvider, detectExecutionContext, EXECUTION_CONTEXT_VALUES, type ExecutionContext, type ExecutionContextDetection, type ExecutionContextDetectionOptions, getExecutionContextTelemetryProperties, setExecutionContextAuthSignal, } from "./execution-context.js";
|
|
6
6
|
export { NodeContextStorage } from "./node-context-storage.js";
|
|
7
7
|
export { getConfiguredTelemetrySessionId, getTelemetrySessionId, getTelemetrySessionSource, TELEMETRY_SESSION_ID_ENV, TELEMETRY_SESSION_SOURCE_PROPERTY, } from "./session-id.js";
|
|
8
|
-
export type { ITelemetryProvider } from "./telemetry-provider.js";
|
|
8
|
+
export type { ITelemetryProvider, TelemetryCorrelation, TrackedDependencySpan, TrackedEvent, TrackedException, TrackedSpan, } from "./telemetry-provider.js";
|
|
9
9
|
export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
|
|
10
|
-
export {
|
|
10
|
+
export { TelemetryService } from "./telemetry-service.js";
|
|
11
11
|
export { getInboundTraceContext, type InboundTraceContext, parseInboundTraceparent, TELEMETRY_TRACEPARENT_ENV, } from "./trace-context.js";
|
|
12
12
|
export { makeTrackedFetch } from "./tracked-fetch.js";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split a pack service's `<name>@<version>` display string.
|
|
3
|
+
*
|
|
4
|
+
* `flow-pack-service` and `maestro-pack-service` both return the packed
|
|
5
|
+
* artifact as one display string — `invoice-process@2.0.0` — and both hand it
|
|
6
|
+
* straight to telemetry's `package_name`. That breaks the dimension it feeds:
|
|
7
|
+
* the pseudonym is computed over the whole string, so the same package gets a
|
|
8
|
+
* different `package_name` for every version, and a publish event can no longer
|
|
9
|
+
* be joined to the deploy event for the same package. Splitting first is what
|
|
10
|
+
* makes the pseudonym stable across versions.
|
|
11
|
+
*
|
|
12
|
+
* The separator is unambiguous. Both services validate the name against
|
|
13
|
+
* `VALID_PACKAGE_NAME_REGEX` — letters, numbers, dots, underscores, hyphens —
|
|
14
|
+
* so a name can never contain `@`, and the last `@` is always the one the
|
|
15
|
+
* service added. A string with no `@` is returned as a name with no version,
|
|
16
|
+
* which is the right answer for a caller that already passes a bare name.
|
|
17
|
+
*/
|
|
18
|
+
export interface PackagedName {
|
|
19
|
+
name: string;
|
|
20
|
+
version?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function splitPackagedName(packaged: string): PackagedName;
|
|
@@ -9,29 +9,126 @@
|
|
|
9
9
|
* by a sensitive prefix (apiKey, accessKey, signingKey, …) so benign
|
|
10
10
|
* names like sortKey, cacheKey, keyword pass through.
|
|
11
11
|
* 2. Value detectors — JWTs, UUIDs, emails, URLs, user-home paths are
|
|
12
|
-
* rewritten to a
|
|
13
|
-
*
|
|
12
|
+
* rewritten to a pseudonym or structurally redacted. Long strings are
|
|
13
|
+
* truncated.
|
|
14
14
|
*
|
|
15
15
|
* The goal is defense in depth: even if a new sensitive option slips through
|
|
16
16
|
* without being added to the denylist, value detectors catch common shapes.
|
|
17
|
+
*
|
|
18
|
+
* A pseudonym is NOT anonymous — see `pseudonymize.ts`. It keeps plaintext off
|
|
19
|
+
* the wire and out of the store, and it joins across events; it does not stop
|
|
20
|
+
* someone holding a candidate list from confirming a guess. Emitted `email#…` /
|
|
21
|
+
* `uuid#…` values carry the same handling obligations as the values they stand
|
|
22
|
+
* in for.
|
|
17
23
|
*/
|
|
18
24
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
25
|
+
* Cap on an emitted property value.
|
|
26
|
+
*
|
|
27
|
+
* Sized against what redaction ADDS, not just what the caller wrote. Each
|
|
28
|
+
* detector hit swaps its match for a `kind#<32 hex>` pseudonym, which is 24
|
|
29
|
+
* characters wider than the 8-hex digest this replaced — so a message carrying
|
|
30
|
+
* two or three ids or addresses would grow past a 200-character cap and lose its
|
|
31
|
+
* tail to truncation, taking the HTTP status and the failure shape with it.
|
|
32
|
+
* 280 restores the headroom the old cap gave before the digests widened, and is
|
|
33
|
+
* far below the App Insights 8192-character property limit, so nothing
|
|
34
|
+
* downstream reshapes it.
|
|
24
35
|
*/
|
|
25
|
-
export declare
|
|
36
|
+
export declare const MAX_VALUE_LENGTH = 280;
|
|
26
37
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
38
|
+
* Cap on a redacted stack trace.
|
|
39
|
+
*
|
|
40
|
+
* A stack is not a dimension and the value cap makes no sense for it: at 280
|
|
41
|
+
* characters a stack is two or three frames, which is the part every stack has in
|
|
42
|
+
* common and none of the part that says where the bug is. App Insights allows
|
|
43
|
+
* 8192 characters per property, so this leaves headroom under it while keeping
|
|
44
|
+
* enough frames to be worth shipping.
|
|
45
|
+
*/
|
|
46
|
+
export declare const MAX_STACK_LENGTH = 4096;
|
|
47
|
+
/**
|
|
48
|
+
* Redact a free-form message — an error string built from whatever a server or
|
|
49
|
+
* an OS sent back.
|
|
50
|
+
*
|
|
51
|
+
* The value detectors alone are not enough here. `HTTP 409: Queue
|
|
52
|
+
* 'BigBank_AG_Inv_2024' is locked by user Jane D.` matches none of them: those
|
|
53
|
+
* are names, not tokens, URLs or ids. What the message is worth keeping for is
|
|
54
|
+
* its *shape* — which call failed and how — so the three places customer data
|
|
55
|
+
* actually sits are removed and the rest is kept:
|
|
56
|
+
*
|
|
57
|
+
* - an embedded JSON body, which is an API response folded into the message;
|
|
58
|
+
* - quoted literals, where a server names the offending resource or person;
|
|
59
|
+
* - anything this run was *given* as an argument, quoted or not, because the
|
|
60
|
+
* CLI's own messages interpolate a value bare (`Unknown agent: bogusagent`
|
|
61
|
+
* echoes back exactly the string `trackedAction` had just withheld from the
|
|
62
|
+
* `uip.cmd.arg.*` dimensions). See `supplied-values.ts`.
|
|
63
|
+
*
|
|
64
|
+
* `HTTP 409: Queue '<redacted>' is locked by user Jane D.` still tells an
|
|
65
|
+
* operator what happened.
|
|
66
|
+
*
|
|
67
|
+
* Order matters: structure first, then the supplied-value scrub. The scrub
|
|
68
|
+
* emits `[REDACTED]`, and running it before the body pass would let that
|
|
69
|
+
* placeholder be read as an embedded array. Anything inside a body or a quoted
|
|
70
|
+
* span is already gone by the time the scrub runs, so nothing is missed by
|
|
71
|
+
* going in this order.
|
|
72
|
+
*/
|
|
73
|
+
/**
|
|
74
|
+
* Scrub a span or event NAME.
|
|
75
|
+
*
|
|
76
|
+
* A name is not a message, and the difference is the supplied-value scrub. That
|
|
77
|
+
* scrub is a substring replace over the whole string, and a command path is
|
|
78
|
+
* made of the same words a user types as arguments: with the full message
|
|
79
|
+
* treatment, `uip tools install tools` shipped
|
|
80
|
+
* `requests.name = uip.[REDACTED].install` — the column every command count,
|
|
81
|
+
* failure rate and duration percentile groups by, destroyed by the run's own
|
|
82
|
+
* argument. So a name gets the quoted-literal rule, which is what an OData key
|
|
83
|
+
* predicate needs (`GET /odata/QueueDefinitions('BigBank_AG_Inv_2024')`), plus
|
|
84
|
+
* the detectors, and nothing that can rewrite a word the CLI itself chose.
|
|
85
|
+
*
|
|
86
|
+
* The one name that IS untrusted end to end is the fetch wrapper's
|
|
87
|
+
* `METHOD /path` — see {@link redactHttpDependencyName}, which
|
|
88
|
+
* {@link ITelemetryService.trackDependencyResult} calls before this.
|
|
89
|
+
*/
|
|
90
|
+
export declare function redactSpanName(name: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* Scrub the fetch wrapper's `METHOD /path`, the one name that is untrusted end
|
|
93
|
+
* to end: a path segment can be an email or an id (`/odata/Users/a@b.com`), a
|
|
94
|
+
* resource the server quoted, or the exact string the user typed as an argument.
|
|
95
|
+
* So the PATH gets the full message treatment, supplied-value scrub included —
|
|
96
|
+
* a command path can never arrive here, which is why the scrub that would wreck
|
|
97
|
+
* one is safe on this name and on no other.
|
|
98
|
+
*
|
|
99
|
+
* The METHOD does not. It is a word the CLI chose, from a set of eight, and the
|
|
100
|
+
* scrub is a plain substring replace: a run whose own argument was `POST` (or
|
|
101
|
+
* `HEAD`, `PATCH`, `DELETE`) turned every one of its outbound calls into
|
|
102
|
+
* `[REDACTED] /path` and took the verb out of the column that separates a read
|
|
103
|
+
* from a write. Split first, scrub the half that is data.
|
|
104
|
+
*/
|
|
105
|
+
export declare function redactHttpDependencyName(name: string): string;
|
|
106
|
+
export declare function redactMessage(value: string): string;
|
|
107
|
+
/**
|
|
108
|
+
* Return a sanitized copy of an Error whose `message` and `stack` have been
|
|
109
|
+
* scrubbed, so telemetry never ships a raw exception string (they routinely
|
|
110
|
+
* embed the offending token, URL, path, or id). The original frames are
|
|
111
|
+
* preserved — only their sensitive substrings are rewritten — and the `name` is
|
|
112
|
+
* kept so App Insights still groups by exception type.
|
|
113
|
+
*
|
|
114
|
+
* The message gets {@link redactMessage}, not the detectors alone. An exception
|
|
115
|
+
* message IS a message: it is where a server names the thing that went wrong
|
|
116
|
+
* (`Queue 'BigBank_AG_Inv_2024' is locked`), where a response body ends up
|
|
117
|
+
* inlined, and where the CLI interpolates what the user typed. Running only the
|
|
118
|
+
* detectors here shipped all three verbatim in `exceptions.message` while the
|
|
119
|
+
* identical text was scrubbed out of the request row's `errorMessage` — the same
|
|
120
|
+
* string, two answers, and the looser one on the surface that also carries a
|
|
121
|
+
* stack.
|
|
32
122
|
*/
|
|
33
123
|
export declare function redactError(error: Error): Error;
|
|
34
124
|
type TelemetryValue = string | number | boolean;
|
|
125
|
+
/**
|
|
126
|
+
* True when a property name looks like it holds credentials. Exported so
|
|
127
|
+
* `describeThrownValue` can drop the same names when it serializes a thrown
|
|
128
|
+
* object into a user-facing message — a rejected HTTP client payload often
|
|
129
|
+
* carries the request's own `Authorization` header.
|
|
130
|
+
*/
|
|
131
|
+
export declare function isSensitiveName(name: string): boolean;
|
|
35
132
|
/**
|
|
36
133
|
* Redact a single telemetry property.
|
|
37
134
|
* Preserves the original value's type (number/boolean pass through unchanged);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one-way transform every identifying value in telemetry goes through.
|
|
3
|
+
*
|
|
4
|
+
* ## What this is, and what it is not
|
|
5
|
+
*
|
|
6
|
+
* This produces a **pseudonym**, not an anonymous token. Hashing cannot make a
|
|
7
|
+
* low-entropy value unrecoverable: anyone holding the telemetry AND a candidate
|
|
8
|
+
* list (a company's employee directory, a customer's domain list) can hash the
|
|
9
|
+
* candidates and match. That is true of any unkeyed digest, and the salt below
|
|
10
|
+
* ships in this source file, so it does not change the analysis. Treat every
|
|
11
|
+
* `email#…` / `uuid#…` / `origin#…` value as *pseudonymous personal data* under
|
|
12
|
+
* the same retention and access rules as the raw value would be.
|
|
13
|
+
*
|
|
14
|
+
* What the digest DOES buy:
|
|
15
|
+
*
|
|
16
|
+
* - it removes the plaintext from the wire and the store, so nobody reading a
|
|
17
|
+
* dashboard, an export, or a spool file sees a customer's address;
|
|
18
|
+
* - it is stable, so the same value joins across events and runs;
|
|
19
|
+
* - at 128 bits it does not collide, which the previous 32-bit FNV-1a did:
|
|
20
|
+
* that space hit a 50% collision chance at ~77k distinct values, so at real
|
|
21
|
+
* telemetry volume distinct tenants, projects and people silently merged
|
|
22
|
+
* into one bucket — breaking the joins the hash exists for.
|
|
23
|
+
*
|
|
24
|
+
* This is the ONLY digest in the telemetry pipeline. `pii-redactor.ts` calls it
|
|
25
|
+
* directly for every `email#…`, `uuid#…` and `url#…` it writes, rather than
|
|
26
|
+
* through the FNV-1a wrapper it used to keep. Two strengths for one job would have
|
|
27
|
+
* left an email on the very payload whose `package_name` is pseudonymized here
|
|
28
|
+
* carrying the collision risk this file exists to remove. Anything new that
|
|
29
|
+
* needs to hash an identifying value calls this, and nothing rolls its own.
|
|
30
|
+
*
|
|
31
|
+
* ## Two implementations, one digest
|
|
32
|
+
*
|
|
33
|
+
* The redactor runs inside `String.prototype.replace` callbacks, so the digest
|
|
34
|
+
* has to be synchronous — which rules out `crypto.subtle.digest`, the async
|
|
35
|
+
* one. It does NOT rule out `node:crypto`: `createHash().digest()` is fully
|
|
36
|
+
* synchronous, and about 36x faster than the pure implementation below (0.28us
|
|
37
|
+
* against 10.2us on a short string). So Node takes `node:crypto` and the pure
|
|
38
|
+
* version is the browser fallback, where `node:crypto` does not resolve. Both
|
|
39
|
+
* produce the same bytes, so a pseudonym computed on either path joins with the
|
|
40
|
+
* other — and `resolveSha256Hex` checks that rather than assuming it.
|
|
41
|
+
*
|
|
42
|
+
* @see hashContent in `../content-hash.ts` for the async SHA-256 used for
|
|
43
|
+
* content addressing — a different job with no sync constraint.
|
|
44
|
+
*/
|
|
45
|
+
/**
|
|
46
|
+
* FIPS 180-4 SHA-256 over the UTF-8 bytes of `input`, as 64 lowercase hex.
|
|
47
|
+
*
|
|
48
|
+
* The portable reference implementation: the browser fallback, and the value
|
|
49
|
+
* `resolveSha256Hex` checks `node:crypto` against before adopting it.
|
|
50
|
+
*/
|
|
51
|
+
export declare function sha256Hex(input: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* The stable pseudonym for an identifying value: 32 lowercase hex characters.
|
|
54
|
+
*
|
|
55
|
+
* Read the module comment before treating the output as anonymous — it is not.
|
|
56
|
+
*/
|
|
57
|
+
export declare function pseudonymize(input: string): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One clock reading, serving both halves of a span.
|
|
3
|
+
*
|
|
4
|
+
* A span carries two numbers that have to agree: the wall-clock moment it
|
|
5
|
+
* began, which is where App Insights draws the bar, and its duration, which is
|
|
6
|
+
* how far the bar extends. Reading `new Date()` for the first and a separate
|
|
7
|
+
* `performance.now()` baseline for the second samples two clocks at two
|
|
8
|
+
* moments, and those clocks drift independently — the wall clock can be stepped
|
|
9
|
+
* by NTP or a suspend/resume mid-span, the monotonic one cannot.
|
|
10
|
+
*
|
|
11
|
+
* {@link startSpanClock} reads `performance.now()` once. The start is that
|
|
12
|
+
* reading projected onto the wall clock through `performance.timeOrigin`, and
|
|
13
|
+
* the duration is measured back against the same reading, so the bar's position
|
|
14
|
+
* and its length are two views of a single instant.
|
|
15
|
+
*
|
|
16
|
+
* `timings.ts` applies the same projection to the whole invocation
|
|
17
|
+
* (`invocationStartedAt` / `invocationElapsedMs`); this is that pattern for a
|
|
18
|
+
* span that opens and closes inside one.
|
|
19
|
+
*/
|
|
20
|
+
export interface SpanClock {
|
|
21
|
+
/** Wall-clock moment the span opened. */
|
|
22
|
+
readonly startedAt: Date;
|
|
23
|
+
/** Milliseconds since it opened, off the monotonic clock. */
|
|
24
|
+
elapsedMs(): number;
|
|
25
|
+
}
|
|
26
|
+
/** Open a clock for a span that is starting now. */
|
|
27
|
+
export declare function startSpanClock(): SpanClock;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The literal strings this run's user typed as argument and option values.
|
|
3
|
+
*
|
|
4
|
+
* Held in memory and **never emitted** — the point is the opposite.
|
|
5
|
+
* `trackedAction` withholds an argument's value from the `uip.cmd.arg.*`
|
|
6
|
+
* dimensions unless the value cannot carry a payload, but that only covers those
|
|
7
|
+
* dimensions. Nothing stopped the same string coming back out through a
|
|
8
|
+
* *message*: a command that says `Unknown agent: bogusagent`, or a server that
|
|
9
|
+
* says `Queue 'BigBank_AG_Inv_2024' not found`, hands it to
|
|
10
|
+
* `OutputFormatter.error`, which ships `Message` to telemetry.
|
|
11
|
+
*
|
|
12
|
+
* Quoting rules cannot close that, because the CLI's own messages interpolate
|
|
13
|
+
* the value bare. What closes it is knowing what the user typed and refusing to
|
|
14
|
+
* echo it — see `redactMessage`.
|
|
15
|
+
*
|
|
16
|
+
* Process-wide, like every other telemetry slot on this path, and held as one
|
|
17
|
+
* ENTRY PER RUN rather than a single list. A long-lived host runs commands
|
|
18
|
+
* concurrently (the MCP bridge), and a single list made both directions wrong:
|
|
19
|
+
* the second command to start replaced the first one's values, so the first
|
|
20
|
+
* stopped scrubbing its own arguments, and the first to finish emptied the list
|
|
21
|
+
* and stopped scrubbing the second's. With an entry per run, an overlap scrubs
|
|
22
|
+
* the union — over-scrub, the safe direction — and a run that ends takes only
|
|
23
|
+
* its own values with it.
|
|
24
|
+
*/
|
|
25
|
+
export interface SuppliedValueEntry {
|
|
26
|
+
readonly values: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Record the values this run was given, and return the handle that releases
|
|
30
|
+
* them again.
|
|
31
|
+
*
|
|
32
|
+
* The handle is the entry object itself, so it works across bundles: a number
|
|
33
|
+
* or a name would have to be unique in a process where several copies of this
|
|
34
|
+
* module are live, and object identity already is.
|
|
35
|
+
*
|
|
36
|
+
* Hand the handle back to {@link releaseSuppliedArgumentValues} when the run
|
|
37
|
+
* ends — never to {@link clearSuppliedArgumentValues}, which drops every
|
|
38
|
+
* concurrent run's entries too. The pair is exported together from the package
|
|
39
|
+
* barrel for that reason: a caller that can record and cannot release leaks its
|
|
40
|
+
* values into every later run in the process.
|
|
41
|
+
*/
|
|
42
|
+
export declare function recordSuppliedArgumentValues(values: unknown): SuppliedValueEntry;
|
|
43
|
+
/** Drop one run's values, leaving any other run's in place. */
|
|
44
|
+
export declare function releaseSuppliedArgumentValues(entry: SuppliedValueEntry): void;
|
|
45
|
+
/**
|
|
46
|
+
* Every value a run in flight was given, longest first.
|
|
47
|
+
*
|
|
48
|
+
* Longest first so a value that contains another is replaced whole rather than
|
|
49
|
+
* leaving the tail of it behind.
|
|
50
|
+
*/
|
|
51
|
+
export declare function getSuppliedArgumentValues(): readonly string[];
|
|
52
|
+
/**
|
|
53
|
+
* Drop every run's values.
|
|
54
|
+
*
|
|
55
|
+
* For tests, and for a host that knows nothing is in flight.
|
|
56
|
+
* `trackedAction` releases its own entry instead — see
|
|
57
|
+
* {@link releaseSuppliedArgumentValues}.
|
|
58
|
+
*/
|
|
59
|
+
export declare function clearSuppliedArgumentValues(): void;
|
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import type { ITelemetryProvider, ITelemetryService } from "./node.js";
|
|
2
2
|
import { type NodeAppInsightsTelemetryProvider } from "./node-appinsights-telemetry-provider.js";
|
|
3
|
+
/**
|
|
4
|
+
* The one origin this process is allowed to send telemetry to.
|
|
5
|
+
*
|
|
6
|
+
* The spool sender needs this because the URL it POSTs to arrives from a **file
|
|
7
|
+
* on disk**, and a spool file is not a trusted input — anything running as the
|
|
8
|
+
* user can drop one in, which on a shared CI agent is any other job on the same
|
|
9
|
+
* uid. Checking only the scheme (all the sender used to do) let such a file
|
|
10
|
+
* point the CLI's own sidecar at an arbitrary host and hand it whole envelopes.
|
|
11
|
+
* Comparing against this closes it: the file supplies the path, never the
|
|
12
|
+
* destination.
|
|
13
|
+
*
|
|
14
|
+
* Read from the connection string rather than hardcoded, so an operator's
|
|
15
|
+
* `UIPATH_AI_CONNECTION_STRING` (and the e2e suite's local ingestion server)
|
|
16
|
+
* keeps working — the destination is theirs to choose through configuration,
|
|
17
|
+
* which is exactly the channel a file on disk is not.
|
|
18
|
+
*
|
|
19
|
+
* This has to answer with whatever the SDK would have used, because the URL in
|
|
20
|
+
* the spool file is the SDK's `config.endpointUrl` and a mismatch means the
|
|
21
|
+
* file is dropped. `InstrumentationKey=…` with no `IngestionEndpoint` is legal
|
|
22
|
+
* and common, and the SDK then sends to {@link DEFAULT_INGESTION_ORIGIN} — so
|
|
23
|
+
* returning "no endpoint" there and failing closed silently discarded every
|
|
24
|
+
* spooled envelope for anyone using the short form. There is no case left where
|
|
25
|
+
* a spool file exists and no origin resolves: without a usable instrumentation
|
|
26
|
+
* key the SDK throws instead of constructing a client, so nothing is ever
|
|
27
|
+
* spooled.
|
|
28
|
+
*/
|
|
29
|
+
export declare function getTelemetryIngestionOrigin(): string;
|
|
3
30
|
/**
|
|
4
31
|
* Create or retrieve the shared Node.js Application Insights telemetry provider.
|
|
5
32
|
* Uses globalThis to ensure all bundled copies share a single TelemetryClient.
|
|
@@ -1,31 +1,99 @@
|
|
|
1
1
|
import type { TelemetryProperties } from "./telemetry-service.js";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Where an item sits in the trace.
|
|
4
|
+
*
|
|
5
|
+
* Every tracked item carries this, because every backend needs it and none of
|
|
6
|
+
* it belongs in custom dimensions. It used to travel as reserved `uip.trace.*`
|
|
7
|
+
* keys inside `properties`, which meant each provider had to know the contract,
|
|
8
|
+
* read the keys, and delete them before emitting — and a provider that forgot
|
|
9
|
+
* (the logger one, the browser one) shipped raw correlation ids as dimensions.
|
|
10
|
+
* An item that describes itself needs no such contract.
|
|
5
11
|
*/
|
|
12
|
+
export interface TelemetryCorrelation {
|
|
13
|
+
/** The trace this item belongs to (`operation_Id`). */
|
|
14
|
+
operationId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The span this item hangs under (`operation_ParentId`). For a span, the
|
|
17
|
+
* span containing it — absent on a trace root. For a leaf, the span it was
|
|
18
|
+
* emitted inside — absent outside any span scope.
|
|
19
|
+
*/
|
|
20
|
+
parentId?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* One finished span, as a provider receives it.
|
|
24
|
+
*
|
|
25
|
+
* Everything the backend needs about a request or dependency arrives as this
|
|
26
|
+
* one object: what it was, how long it took, whether it worked, when it began,
|
|
27
|
+
* and where it sits in the trace.
|
|
28
|
+
*/
|
|
29
|
+
export interface TrackedSpan extends TelemetryCorrelation {
|
|
30
|
+
/** Operation name — the command path, or `METHOD /path` for a call. */
|
|
31
|
+
name: string;
|
|
32
|
+
/** Measured wall-clock length, in milliseconds. */
|
|
33
|
+
durationMs: number;
|
|
34
|
+
success: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* When the span began.
|
|
37
|
+
*
|
|
38
|
+
* App Insights reads this as the span START and draws the bar forward by
|
|
39
|
+
* `durationMs`. A provider whose backend timestamps on arrival must use it;
|
|
40
|
+
* without it, the only start available is the moment of emit, which charges
|
|
41
|
+
* the bar for everything that happened after the clock stopped.
|
|
42
|
+
*/
|
|
43
|
+
startedAt?: Date;
|
|
44
|
+
/** This span's own id, which its children point their parent id at. */
|
|
45
|
+
id?: string;
|
|
46
|
+
/** Custom dimensions. Correlation is not among them — see above. */
|
|
47
|
+
properties?: TelemetryProperties;
|
|
48
|
+
}
|
|
49
|
+
/** A {@link TrackedSpan} for an outbound call. */
|
|
50
|
+
export interface TrackedDependencySpan extends TrackedSpan {
|
|
51
|
+
/** Dependency kind, e.g. `HTTP`. */
|
|
52
|
+
type: string;
|
|
53
|
+
/**
|
|
54
|
+
* Backend-native status of the call (e.g. the HTTP status code). Omitted,
|
|
55
|
+
* a provider derives a coarse code from `success`; supplying the real one
|
|
56
|
+
* keeps `dependencies.resultCode` truthful instead of collapsing every
|
|
57
|
+
* outcome to 200/500.
|
|
58
|
+
*/
|
|
59
|
+
resultCode?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* One event, as a provider receives it.
|
|
63
|
+
*
|
|
64
|
+
* A leaf: it marks an instant rather than an interval, so it has no duration
|
|
65
|
+
* and no id of its own. It nests under whichever span was open when it was
|
|
66
|
+
* emitted, via {@link TelemetryCorrelation.parentId}.
|
|
67
|
+
*/
|
|
68
|
+
export interface TrackedEvent extends TelemetryCorrelation {
|
|
69
|
+
name: string;
|
|
70
|
+
/** Custom dimensions. Correlation is not among them. */
|
|
71
|
+
properties?: TelemetryProperties;
|
|
72
|
+
}
|
|
73
|
+
/** A {@link TrackedEvent}-shaped leaf carrying an error instead of a name. */
|
|
74
|
+
export interface TrackedException extends TelemetryCorrelation {
|
|
75
|
+
/** Already redacted by the service — providers emit it as-is. */
|
|
76
|
+
error: Error;
|
|
77
|
+
/** Custom dimensions. Correlation is not among them. */
|
|
78
|
+
properties?: TelemetryProperties;
|
|
79
|
+
}
|
|
6
80
|
export interface ITelemetryProvider {
|
|
7
81
|
/**
|
|
8
|
-
* Track a custom event
|
|
82
|
+
* Track a custom event.
|
|
9
83
|
*/
|
|
10
|
-
trackEvent(
|
|
84
|
+
trackEvent(event: TrackedEvent): Promise<void>;
|
|
11
85
|
/**
|
|
12
|
-
* Track an exception
|
|
86
|
+
* Track an exception.
|
|
13
87
|
*/
|
|
14
|
-
trackException(
|
|
88
|
+
trackException(exception: TrackedException): Promise<void>;
|
|
15
89
|
/**
|
|
16
|
-
* Track a completed request operation
|
|
90
|
+
* Track a completed request operation.
|
|
17
91
|
*/
|
|
18
|
-
trackRequest(
|
|
92
|
+
trackRequest(span: TrackedSpan): Promise<void>;
|
|
19
93
|
/**
|
|
20
|
-
* Track a completed dependency operation
|
|
21
|
-
*
|
|
22
|
-
* `resultCode` is the backend-native status of the call (e.g. the HTTP
|
|
23
|
-
* status code for an outbound request). When omitted the provider derives a
|
|
24
|
-
* coarse code from `success`. Passing the real code keeps the App Insights
|
|
25
|
-
* `dependencies.resultCode` column accurate instead of collapsing every
|
|
26
|
-
* outcome to 200/500.
|
|
94
|
+
* Track a completed dependency operation.
|
|
27
95
|
*/
|
|
28
|
-
trackDependency(
|
|
96
|
+
trackDependency(span: TrackedDependencySpan): Promise<void>;
|
|
29
97
|
/**
|
|
30
98
|
* Get the current session ID, if available.
|
|
31
99
|
*/
|