@uipath/common 1.197.0 → 1.198.0-preview.101

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.
@@ -24,6 +24,13 @@ export type InteractivityMode = "never" | "auto" | "always";
24
24
  export declare function setInteractivityMode(mode: InteractivityMode): void;
25
25
  /** Get the current interactivity mode, defaulting to "auto". */
26
26
  export declare function getInteractivityMode(): InteractivityMode;
27
+ /**
28
+ * Record whether the global `--interactive` flag was explicitly passed on the
29
+ * command line. Called once at CLI startup, alongside {@link setInteractivityMode}.
30
+ */
31
+ export declare function setInteractiveFlag(passed: boolean): void;
32
+ /** True when the user explicitly passed `--interactive` (see {@link setInteractiveFlag}). */
33
+ export declare function wasInteractiveFlagPassed(): boolean;
27
34
  /**
28
35
  * True when the CLI may show an interactive prompt right now.
29
36
  *
@@ -27,6 +27,18 @@ export declare function setOutputFormatExplicit(explicit: boolean): void;
27
27
  * Defaults to false (i.e. resolved value is the default).
28
28
  */
29
29
  export declare function getOutputFormatExplicit(): boolean;
30
+ /**
31
+ * Record whether the user asked for help explicitly (`-h`/`--help`).
32
+ * Kept separate from the output format so that the help renderer can force
33
+ * the table layout without hijacking the format used for error output —
34
+ * errors always follow the real format (json by default). Set once at CLI
35
+ * startup.
36
+ */
37
+ export declare function setHelpRequested(requested: boolean): void;
38
+ /**
39
+ * True when `-h`/`--help` was passed on the command line. Defaults to false.
40
+ */
41
+ export declare function getHelpRequested(): boolean;
30
42
  /**
31
43
  * Set the process-wide output filter expression.
32
44
  * Called once at CLI startup after parsing the global --output-filter option.
@@ -38,5 +38,5 @@ export interface Singleton<T> {
38
38
  *
39
39
  * The key is auto-prefixed with `@uipath/common/`.
40
40
  */
41
- export declare function singleton<T>(ctor: abstract new (...args: any[]) => T): Singleton<T>;
41
+ export declare function singleton<T>(ctor: abstract new (...args: never[]) => T): Singleton<T>;
42
42
  export declare function singleton<T>(name: string): Singleton<T>;
package/dist/stdin.d.ts CHANGED
@@ -1 +1,8 @@
1
1
  export declare function readStdin(): Promise<string | null>;
2
+ /**
3
+ * `readStdin()` with a deadline. A non-TTY pipe that stays open but never sends
4
+ * data (or EOF) would otherwise block forever; on expiry this unrefs stdin so
5
+ * it can't keep the process alive and resolves `null`. Returns `null` on
6
+ * timeout, TTY, or empty input.
7
+ */
8
+ export declare function readStdinWithTimeout(timeoutMs: number): Promise<string | null>;
@@ -4,8 +4,8 @@ export { ConsoleTelemetryProvider } from "./console-telemetry-provider.js";
4
4
  export type { IContextStorage } from "./context-storage.js";
5
5
  export { buildEnvironmentProperties, type NormalizedEnvironment, normalizeBaseUrl, normalizeEnvironment, } from "./environment-info.js";
6
6
  export { type CiProvider, detectExecutionContext, EXECUTION_CONTEXT_VALUES, type ExecutionContext, type ExecutionContextDetection, type ExecutionContextDetectionOptions, getExecutionContextTelemetryProperties, setExecutionContextAuthSignal, } from "./execution-context.js";
7
- export { redactProperties, redactProperty } from "./pii-redactor.js";
7
+ export { redactError, redactProperties, redactProperty, redactValue, } from "./pii-redactor.js";
8
8
  export { getConfiguredTelemetrySessionId, getTelemetrySessionId, resolveTelemetrySessionId, TELEMETRY_SESSION_ID_ENV, TELEMETRY_SESSION_ID_PROPERTY, } from "./session-id.js";
9
9
  export type { ITelemetryProvider } from "./telemetry-provider.js";
10
10
  export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
11
- export { TelemetryService } from "./telemetry-service.js";
11
+ export { TELEMETRY_OPERATION_ID_PROPERTY, TELEMETRY_PARENT_ID_PROPERTY, TELEMETRY_SPAN_ID_PROPERTY, TelemetryService, } from "./telemetry-service.js";
@@ -508,8 +508,17 @@ function redactValueDetectors(value) {
508
508
  }
509
509
  return out;
510
510
  }
511
+ function redactValue(value) {
512
+ return redactValueDetectors(value);
513
+ }
514
+ function redactError(error) {
515
+ const safe = new Error(redactValueDetectors(error.message ?? ""));
516
+ safe.name = error.name;
517
+ safe.stack = typeof error.stack === "string" ? redactValueDetectors(error.stack) : undefined;
518
+ return safe;
519
+ }
511
520
  function nameTokens(name) {
512
- 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);
521
+ 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);
513
522
  }
514
523
  function isSensitiveName(name) {
515
524
  const tokens = nameTokens(name);
@@ -552,11 +561,36 @@ function redactProperties(properties) {
552
561
  }
553
562
  return out;
554
563
  }
564
+ // src/telemetry/trace-context.ts
565
+ var TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
566
+ var TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
567
+ function getProcessEnv() {
568
+ return globalThis.process?.env;
569
+ }
570
+ function parseInboundTraceparent(value) {
571
+ if (!value) {
572
+ return;
573
+ }
574
+ const match = TRACEPARENT_PATTERN.exec(value.trim().toLowerCase());
575
+ if (!match) {
576
+ return;
577
+ }
578
+ const [, traceId, parentSpanId] = match;
579
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId)) {
580
+ return;
581
+ }
582
+ return { traceId, parentSpanId };
583
+ }
584
+ function getInboundTraceContext() {
585
+ return parseInboundTraceparent(getProcessEnv()?.[TELEMETRY_TRACEPARENT_ENV]);
586
+ }
587
+
555
588
  // src/telemetry/session-id.ts
556
589
  var TELEMETRY_SESSION_ID_ENV = "UIPATH_SESSION_ID";
557
590
  var TELEMETRY_SESSION_ID_PROPERTY = "session_id";
558
591
  var telemetrySessionIdSlot = singleton("TelemetrySessionId");
559
- function getProcessEnv() {
592
+ var telemetryOperationIdSlot = singleton("TelemetryOperationId");
593
+ function getProcessEnv2() {
560
594
  return globalThis.process?.env;
561
595
  }
562
596
  function normalizeSessionId(value) {
@@ -567,7 +601,7 @@ function normalizeSessionId(value) {
567
601
  return trimmed || undefined;
568
602
  }
569
603
  function getConfiguredTelemetrySessionId() {
570
- return normalizeSessionId(getProcessEnv()?.[TELEMETRY_SESSION_ID_ENV]);
604
+ return normalizeSessionId(getProcessEnv2()?.[TELEMETRY_SESSION_ID_ENV]);
571
605
  }
572
606
  function getTelemetrySessionId() {
573
607
  const envSessionId = getConfiguredTelemetrySessionId();
@@ -585,6 +619,16 @@ function getTelemetrySessionId() {
585
619
  function resolveTelemetrySessionId(existingSessionId) {
586
620
  return getConfiguredTelemetrySessionId() ?? normalizeSessionId(existingSessionId);
587
621
  }
622
+ function getTelemetryOperationId() {
623
+ const existing = telemetryOperationIdSlot.get();
624
+ if (existing) {
625
+ return existing;
626
+ }
627
+ const inboundTraceId = getInboundTraceContext()?.traceId;
628
+ const generated = inboundTraceId ?? crypto.randomUUID().replaceAll("-", "");
629
+ telemetryOperationIdSlot.set(generated);
630
+ return generated;
631
+ }
588
632
  // src/telemetry/global-telemetry-properties.ts
589
633
  var telemetryPropsSlot = singleton("TelemetryDefaultProps");
590
634
  function getGlobalTelemetryProperties() {
@@ -592,6 +636,10 @@ function getGlobalTelemetryProperties() {
592
636
  }
593
637
 
594
638
  // src/telemetry/telemetry-service.ts
639
+ var TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
640
+ var TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
641
+ var TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
642
+
595
643
  class TelemetryService {
596
644
  telemetryProvider;
597
645
  contextStorage;
@@ -618,11 +666,15 @@ class TelemetryService {
618
666
  trackException(error, properties) {
619
667
  const context = this.getCurrentContext();
620
668
  const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
621
- this.telemetryProvider.trackException(error, enrichedProperties);
669
+ this.telemetryProvider.trackException(redactError(error), enrichedProperties);
622
670
  }
623
671
  async trackRequest(name, fn, properties) {
672
+ const parentContext = this.getCurrentContext();
673
+ const operationId = parentContext?.operationId ?? this.operationId ?? getTelemetryOperationId();
674
+ const parentId = parentContext ? parentContext.id : this.inboundParentIdFor(operationId);
624
675
  const context = {
625
- operationId: this.operationId ?? this.generateId(),
676
+ operationId,
677
+ ...parentId !== undefined ? { parentId } : {},
626
678
  id: this.generateId()
627
679
  };
628
680
  const startTime = performance.now();
@@ -640,6 +692,45 @@ class TelemetryService {
640
692
  throw error;
641
693
  }
642
694
  }
695
+ trackRequestResult(name, durationMs, success, properties, context) {
696
+ const requestContext = context ?? {
697
+ operationId: this.operationId ?? getTelemetryOperationId(),
698
+ id: this.generateId()
699
+ };
700
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, requestContext);
701
+ this.telemetryProvider.trackRequest(name, durationMs, success, enrichedProperties);
702
+ }
703
+ createRequestContext() {
704
+ const operationId = this.operationId ?? getTelemetryOperationId();
705
+ const parentId = this.inboundParentIdFor(operationId);
706
+ return {
707
+ operationId,
708
+ ...parentId !== undefined ? { parentId } : {},
709
+ id: this.generateId()
710
+ };
711
+ }
712
+ inboundParentIdFor(operationId) {
713
+ const inbound = getInboundTraceContext();
714
+ return inbound && inbound.traceId === operationId ? inbound.parentSpanId : undefined;
715
+ }
716
+ runWithContext(context, fn) {
717
+ return this.contextStorage.run(context, fn);
718
+ }
719
+ createDependencyContext() {
720
+ const parentContext = this.getCurrentContext();
721
+ if (!parentContext) {
722
+ return;
723
+ }
724
+ return {
725
+ operationId: parentContext.operationId,
726
+ parentId: parentContext.id,
727
+ id: this.generateId()
728
+ };
729
+ }
730
+ trackDependencyResult(name, type, durationMs, success, properties, context, resultCode) {
731
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
732
+ this.telemetryProvider.trackDependency(redactValue(name), type, durationMs, success, enrichedProperties, resultCode);
733
+ }
643
734
  async trackDependencyOperation(name, type, fn, properties) {
644
735
  const parentContext = this.getCurrentContext();
645
736
  if (!parentContext) {
@@ -676,8 +767,12 @@ class TelemetryService {
676
767
  ...getExecutionContextTelemetryProperties(),
677
768
  ...globalProperties,
678
769
  ...this.defaultProperties,
679
- ...properties,
680
- ...context
770
+ ...redactProperties(properties ?? {}),
771
+ ...context ? {
772
+ [TELEMETRY_OPERATION_ID_PROPERTY]: context.operationId,
773
+ ...context.parentId !== undefined ? { [TELEMETRY_PARENT_ID_PROPERTY]: context.parentId } : {},
774
+ [TELEMETRY_SPAN_ID_PROPERTY]: context.id
775
+ } : {}
681
776
  };
682
777
  if (sessionId === undefined) {
683
778
  delete enriched[TELEMETRY_SESSION_ID_PROPERTY];
@@ -687,14 +782,25 @@ class TelemetryService {
687
782
  return enriched;
688
783
  }
689
784
  generateId() {
690
- return crypto.randomUUID().replaceAll("-", "");
785
+ const bytes = new Uint8Array(8);
786
+ let hex = "";
787
+ do {
788
+ crypto.getRandomValues(bytes);
789
+ hex = "";
790
+ for (const byte of bytes) {
791
+ hex += byte.toString(16).padStart(2, "0");
792
+ }
793
+ } while (/^0+$/.test(hex));
794
+ return hex;
691
795
  }
692
796
  }
693
797
  export {
694
798
  setExecutionContextAuthSignal,
695
799
  resolveTelemetrySessionId,
800
+ redactValue,
696
801
  redactProperty,
697
802
  redactProperties,
803
+ redactError,
698
804
  normalizeSkillName,
699
805
  normalizeEnvironment,
700
806
  normalizeBaseUrl,
@@ -706,11 +812,14 @@ export {
706
812
  buildEnvironmentProperties,
707
813
  buildCommandTelemetryAttribution,
708
814
  TelemetryService,
815
+ TELEMETRY_SPAN_ID_PROPERTY,
709
816
  TELEMETRY_SESSION_ID_PROPERTY,
710
817
  TELEMETRY_SESSION_ID_ENV,
818
+ TELEMETRY_PARENT_ID_PROPERTY,
819
+ TELEMETRY_OPERATION_ID_PROPERTY,
711
820
  EXECUTION_CONTEXT_VALUES,
712
821
  ConsoleTelemetryProvider,
713
822
  BrowserContextStorage
714
823
  };
715
824
 
716
- //# debugId=E6ABC1B31BAE25B864756E2164756E21
825
+ //# debugId=B104F80E6DBFBC9064756E2164756E21
@@ -1,5 +1,5 @@
1
1
  import type { ITelemetryProvider } from "./telemetry-provider.js";
2
- import type { TelemetryProperties } from "./telemetry-service.js";
2
+ import { type TelemetryProperties } from "./telemetry-service.js";
3
3
  export { getGlobalTelemetryProperties, setGlobalTelemetryProperties, } from "./global-telemetry-properties.js";
4
4
  /**
5
5
  * Node.js Application Insights telemetry provider.
@@ -31,10 +31,53 @@ export declare class NodeAppInsightsTelemetryProvider implements ITelemetryProvi
31
31
  * Per-call properties take precedence over global defaults.
32
32
  */
33
33
  private mergeProperties;
34
+ /**
35
+ * Read the trace context off the internal `uip.trace.*` routing keys and
36
+ * strip them, so nothing correlation-related ever ships as a custom
37
+ * dimension. `merged` is a fresh per-call object, so mutating it in place is
38
+ * safe; the same reference is what the client call emits as `properties`.
39
+ *
40
+ * `operationId` falls back to the per-invocation id when no context is set
41
+ * (events outside a `trackRequest` scope), so every item in one run still
42
+ * groups under the same `operation_Id`. `parentId`/`spanId` are only present
43
+ * inside a scope.
44
+ */
45
+ private consumeCorrelation;
46
+ /**
47
+ * Promote a `session_id` custom dimension onto the native `ai.session.id`
48
+ * context tag and strip it from the dimension bag. Session belongs in the
49
+ * native session tag — the App Insights Sessions blade reads it there — so
50
+ * shipping it as a custom dimension too is redundant and drifts (the raw
51
+ * tag vs. a redactor-hashed dimension). Only the AppInsights provider does
52
+ * this; fallback providers (logger/console) keep `session_id` as a
53
+ * dimension, since they have no native session field.
54
+ *
55
+ * `merged` is a fresh per-call object, so deleting in place is safe.
56
+ */
57
+ private promoteSessionTag;
58
+ /**
59
+ * Native correlation tags for a LEAF item (event/exception). It has no item
60
+ * id of its own, so it nests under the current operation: `operation_Id` is
61
+ * the trace id, and `operation_ParentId` is the enclosing request/
62
+ * dependency's id (the context's `spanId`), present only inside a scope.
63
+ *
64
+ * Cross-service join: `makeTrackedFetch` stamps a W3C `traceparent`
65
+ * (`00-<operation_Id>-<span>-01`) on every outbound call made inside a
66
+ * request scope, so the API side can line its telemetry up with this trace.
67
+ * These native tags are the CLI-side half of that join.
68
+ */
69
+ private leafTagOverrides;
70
+ /**
71
+ * Native correlation for an OPERATION item (request/dependency). It carries
72
+ * its own item `id` (the context's `spanId`) so child items can point their
73
+ * `operation_ParentId` at it, and its own `operation_ParentId` is the
74
+ * context's `parentId` (absent for a top-level request → a trace root).
75
+ */
76
+ private operationCorrelation;
34
77
  trackEvent(eventName: string, properties?: TelemetryProperties): Promise<void>;
35
78
  trackException(error: Error, properties?: TelemetryProperties): Promise<void>;
36
79
  trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
37
- trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
80
+ trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties, resultCode?: string): Promise<void>;
38
81
  flush(): Promise<void>;
39
82
  /**
40
83
  * Dispose the Application Insights SDK so its internal channels,
@@ -7,4 +7,6 @@ export { NodeContextStorage } from "./node-context-storage.js";
7
7
  export { getConfiguredTelemetrySessionId, getTelemetrySessionId, resolveTelemetrySessionId, TELEMETRY_SESSION_ID_ENV, TELEMETRY_SESSION_ID_PROPERTY, } from "./session-id.js";
8
8
  export type { ITelemetryProvider } from "./telemetry-provider.js";
9
9
  export type { ITelemetryService, TelemetryContext, TelemetryProperties, } from "./telemetry-service.js";
10
- export { TelemetryService } from "./telemetry-service.js";
10
+ export { TELEMETRY_OPERATION_ID_PROPERTY, TELEMETRY_PARENT_ID_PROPERTY, TELEMETRY_SPAN_ID_PROPERTY, TelemetryService, } from "./telemetry-service.js";
11
+ export { getInboundTraceContext, type InboundTraceContext, parseInboundTraceparent, TELEMETRY_TRACEPARENT_ENV, } from "./trace-context.js";
12
+ export { makeTrackedFetch } from "./tracked-fetch.js";
@@ -15,6 +15,22 @@
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
17
  */
18
+ /**
19
+ * Run the value detectors over a free-form string (no name-based check). Use for
20
+ * strings that aren't property values but can still carry PII — a telemetry
21
+ * event/dependency name (`GET /odata/Users/alice@corp.com`) or an exception
22
+ * message. Emails/UUIDs are hashed, URLs reduced to origin, tokens/JWTs and
23
+ * user-home paths redacted, over-long strings truncated.
24
+ */
25
+ export declare function redactValue(value: string): string;
26
+ /**
27
+ * Return a sanitized copy of an Error whose `message` and `stack` have been run
28
+ * through the value detectors, so telemetry never ships a raw exception string
29
+ * (they routinely embed the offending token, URL, path, or id). The original
30
+ * frames are preserved — only their sensitive substrings are rewritten — and
31
+ * the `name` is kept so App Insights still groups by exception type.
32
+ */
33
+ export declare function redactError(error: Error): Error;
18
34
  type TelemetryValue = string | number | boolean;
19
35
  /**
20
36
  * Redact a single telemetry property.
@@ -10,3 +10,22 @@ export declare function getConfiguredTelemetrySessionId(): string | undefined;
10
10
  */
11
11
  export declare function getTelemetrySessionId(): string;
12
12
  export declare function resolveTelemetrySessionId(existingSessionId: unknown): string | undefined;
13
+ /**
14
+ * Resolve the per-invocation operation id used for App Insights' native
15
+ * `operation_Id` tag.
16
+ *
17
+ * One CLI process is one invocation, so this is generated once per process and
18
+ * shared across bundled copies of @uipath/common (the singleton slot lives on
19
+ * globalThis). It does not take a grouping override the way the session id does:
20
+ * a coding-agent host sets UIPATH_SESSION_ID to group several CLI runs, but each
21
+ * run still needs its own operation id so consumers can tell the runs apart. The
22
+ * one env input it honors is an inbound TRACEPARENT — when the caller passes
23
+ * trace context, this run adopts that trace id so it lines up with the caller's
24
+ * transaction and with the API telemetry it triggers.
25
+ *
26
+ * The value is a 32-hex string (a UUID with dashes stripped). That is the shape
27
+ * App Insights expects for `operation_Id`, and — unlike the UUID-shaped session
28
+ * id — it is left untouched by the PII redactor, so the emitted value matches
29
+ * raw on every path.
30
+ */
31
+ export declare function getTelemetryOperationId(): string;
@@ -18,8 +18,14 @@ export interface ITelemetryProvider {
18
18
  trackRequest(name: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
19
19
  /**
20
20
  * Track a completed dependency operation with measured duration.
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.
21
27
  */
22
- trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties): Promise<void>;
28
+ trackDependency(name: string, type: string, duration: number, success: boolean, properties?: TelemetryProperties, resultCode?: string): Promise<void>;
23
29
  /**
24
30
  * Get the current session ID, if available.
25
31
  */
@@ -6,6 +6,39 @@ import type { ITelemetryProvider } from "./telemetry-provider.js";
6
6
  export interface TelemetryProperties {
7
7
  [key: string]: string | number | boolean | undefined;
8
8
  }
9
+ /**
10
+ * Internal property key that carries an active trace context's operation id
11
+ * (mirrors {@link TelemetryContext.operationId}). The AppInsights provider reads
12
+ * it to set the native `operation_Id` tag, falling back to the per-invocation id
13
+ * when no context is present — i.e. for events emitted outside a `trackRequest`
14
+ * scope. The provider consumes and strips it, so it never ships as a dimension.
15
+ *
16
+ * The key lives in the `uip.trace.*` namespace (not the plain `operationId`)
17
+ * so it can never be shadowed by a command argument of the same name.
18
+ * `extractCommandParams` in `trackedAction.ts` now namespaces args under
19
+ * `uip.cmd.arg.*`, but the dedicated trace namespace keeps this control key
20
+ * unambiguous and consistent with the rest of the owner-namespaced schema. The
21
+ * provider consumes and strips it, so the dotted key never ships as a dimension.
22
+ */
23
+ export declare const TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
24
+ /**
25
+ * Internal routing key carrying an active trace context's parent id (mirrors
26
+ * {@link TelemetryContext.parentId}). The AppInsights provider reads it to set
27
+ * the native `ai.operation.parentId` tag on request/dependency items, so the
28
+ * parent/child tree links in the App Insights UI. Present only inside a nested
29
+ * scope (a top-level `trackRequest` has no parent). Consumed and stripped by
30
+ * the provider — never ships as a dimension.
31
+ */
32
+ export declare const TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
33
+ /**
34
+ * Internal routing key carrying an active trace context's own id (mirrors
35
+ * {@link TelemetryContext.id}). The AppInsights provider uses it as the request/
36
+ * dependency envelope's native item `id`, so child items whose parent id equals
37
+ * it link up; for leaf items (events/exceptions) the provider maps it onto
38
+ * `ai.operation.parentId` so the leaf nests under the current operation.
39
+ * Consumed and stripped by the provider — never ships as a dimension.
40
+ */
41
+ export declare const TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
9
42
  /**
10
43
  * Telemetry correlation context for tracking parent-child relationships
11
44
  */
@@ -97,6 +130,55 @@ export interface ITelemetryService {
97
130
  * All nested trackDependencyOperation calls will be automatically correlated to this request.
98
131
  */
99
132
  trackRequest<T>(name: string, fn: () => Promise<T>, properties?: TelemetryProperties): Promise<T>;
133
+ /**
134
+ * Track a request from already-measured data — no wrapping function.
135
+ *
136
+ * Use when the caller measured duration and success itself and just needs
137
+ * the request emitted (e.g. `trackedAction`, which times the whole command
138
+ * imperatively). The request becomes a top-level operation: it groups under
139
+ * the per-invocation `operation_Id` and carries its own span id, so it lands
140
+ * in the native App Insights `requests` table with `duration`/`success` as
141
+ * first-class columns instead of stringified custom dimensions.
142
+ *
143
+ * @param name The request name (e.g. the command path `uip.solution.pack`)
144
+ * @param durationMs Measured wall-clock duration in milliseconds
145
+ * @param success Whether the operation succeeded
146
+ * @param properties Base properties to include in telemetry
147
+ */
148
+ trackRequestResult(name: string, durationMs: number, success: boolean, properties?: TelemetryProperties, context?: TelemetryContext): void;
149
+ /**
150
+ * Build a root request context (a trace root: a per-invocation operation
151
+ * id, its own span id, no parent) without storing or emitting anything.
152
+ *
153
+ * For imperative callers that time the work themselves (e.g. `trackedAction`)
154
+ * but still need child dependencies to nest: create the context once, run the
155
+ * work inside {@link runWithContext} so dependencies find it, then pass the
156
+ * same context to {@link trackRequestResult} so the request envelope reuses
157
+ * this span id and the children's parent id points at it.
158
+ */
159
+ createRequestContext(): TelemetryContext;
160
+ /**
161
+ * Run `fn` with `context` active in the async context storage, so any
162
+ * telemetry emitted inside (dependencies, events, exceptions) correlates to
163
+ * it. Returns the function's result.
164
+ */
165
+ runWithContext<T>(context: TelemetryContext, fn: () => Promise<T>): Promise<T>;
166
+ /**
167
+ * Build a dependency context (child of the currently active context) without
168
+ * emitting anything, or `undefined` when there is no active request scope.
169
+ *
170
+ * For imperative callers (e.g. the outbound-fetch wrapper) that need the
171
+ * span id up front — to stamp a `traceparent` header before the call — and
172
+ * report success/duration afterwards via {@link trackDependencyResult}.
173
+ */
174
+ createDependencyContext(): TelemetryContext | undefined;
175
+ /**
176
+ * Track a dependency from already-measured data using an explicit context —
177
+ * no wrapping function. Use when success can't be inferred from "the callback
178
+ * didn't throw": an outbound HTTP call returning 4xx/5xx resolves normally,
179
+ * so the caller passes `success = response.ok`.
180
+ */
181
+ trackDependencyResult(name: string, type: string, durationMs: number, success: boolean, properties: TelemetryProperties | undefined, context: TelemetryContext, resultCode?: string): void;
100
182
  /**
101
183
  * Track a dependency operation (child operation in the dependency tree).
102
184
  * Use this for operations that are part of a larger request.
@@ -140,6 +222,21 @@ export declare class TelemetryService implements ITelemetryService {
140
222
  trackEvent(name: string, properties?: TelemetryProperties): void;
141
223
  trackException(error: Error, properties?: TelemetryProperties): void;
142
224
  trackRequest<T>(name: string, fn: () => Promise<T>, properties?: TelemetryProperties): Promise<T>;
225
+ trackRequestResult(name: string, durationMs: number, success: boolean, properties?: TelemetryProperties, context?: TelemetryContext): void;
226
+ createRequestContext(): TelemetryContext;
227
+ /**
228
+ * The caller's span id to parent a root request under, or `undefined`.
229
+ *
230
+ * Only returns a parent when this run actually adopted the inbound trace id
231
+ * as its `operationId` (the run's `getTelemetryOperationId()` picked up the
232
+ * `TRACEPARENT` trace id). If a caller pinned a different `operationId` via
233
+ * `setOperationId`, the inbound parent would reference a span in a different
234
+ * trace, so it's dropped — correlation must stay internally consistent.
235
+ */
236
+ private inboundParentIdFor;
237
+ runWithContext<T>(context: TelemetryContext, fn: () => Promise<T>): Promise<T>;
238
+ createDependencyContext(): TelemetryContext | undefined;
239
+ trackDependencyResult(name: string, type: string, durationMs: number, success: boolean, properties: TelemetryProperties | undefined, context: TelemetryContext, resultCode?: string): void;
143
240
  trackDependencyOperation<T>(name: string, type: string, fn: () => Promise<T>, properties?: TelemetryProperties): Promise<T>;
144
241
  /**
145
242
  * Gets the current telemetry context from the context storage.
@@ -160,7 +257,14 @@ export declare class TelemetryService implements ITelemetryService {
160
257
  */
161
258
  private enrichPropertiesWithContext;
162
259
  /**
163
- * Generate a unique ID for telemetry correlation
260
+ * Generate a span id for telemetry correlation.
261
+ *
262
+ * 16 hex chars (8 random bytes) — the W3C trace-context `span-id` width.
263
+ * The trace id (`operationId`) stays 32 hex (a UUID with dashes stripped,
264
+ * the W3C `trace-id` width). Keeping the two at their standard widths means
265
+ * the ids can be emitted verbatim as a `traceparent`
266
+ * (`00-<32hex traceId>-<16hex spanId>-01`) once the CLI propagates trace
267
+ * context to the APIs, without a downstream parser rejecting a mis-sized id.
164
268
  */
165
269
  private generateId;
166
270
  }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Inbound W3C Trace Context ingestion.
3
+ *
4
+ * The CLI normally starts its own trace: one process = one `operation_Id`, and
5
+ * the command's request is a trace root with no parent. But when the CLI is run
6
+ * as one step of a larger distributed operation — a robot, agent, or
7
+ * orchestrator shelling out to `uip ...` — that caller wants the CLI's whole
8
+ * telemetry subtree nested under its own span in the App Insights end-to-end
9
+ * transaction view.
10
+ *
11
+ * A process has no inbound HTTP headers, so the caller passes the standard W3C
12
+ * `traceparent` value in the `TRACEPARENT` environment variable (the same
13
+ * convention OpenTelemetry CLI tools use). When present and valid, this run
14
+ * adopts the caller's trace id as its `operation_Id` and points the command
15
+ * request's `operation_ParentId` at the caller's span id. The outbound-fetch
16
+ * wrapper then inherits the adopted trace id, so the full chain
17
+ * (caller → CLI → API) reads as one transaction.
18
+ */
19
+ /**
20
+ * Environment variable carrying the inbound W3C `traceparent`
21
+ * (`00-<trace-id>-<parent-id>-<flags>`). Set by a caller that wants this CLI
22
+ * run to join its distributed trace.
23
+ */
24
+ export declare const TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
25
+ /**
26
+ * The parts of an inbound `traceparent` the CLI adopts: the trace id (becomes
27
+ * this run's `operation_Id`) and the caller's span id (becomes the command
28
+ * request's parent).
29
+ */
30
+ export interface InboundTraceContext {
31
+ /** 32-hex W3C trace-id. */
32
+ traceId: string;
33
+ /** 16-hex W3C parent span-id — the caller's span this run nests under. */
34
+ parentSpanId: string;
35
+ }
36
+ /**
37
+ * Parse a `traceparent` string into the trace/parent ids the CLI adopts, or
38
+ * `undefined` when the value is absent or malformed.
39
+ *
40
+ * Rejects: the wrong version, wrong id widths, and the W3C-forbidden all-zero
41
+ * trace-id / parent-id (which signal "no valid id"). A malformed value falls
42
+ * back to the default root-trace behaviour rather than corrupting correlation.
43
+ */
44
+ export declare function parseInboundTraceparent(value: string | undefined): InboundTraceContext | undefined;
45
+ /**
46
+ * Read and parse the inbound trace context from the `TRACEPARENT` environment
47
+ * variable, or `undefined` when unset/invalid.
48
+ */
49
+ export declare function getInboundTraceContext(): InboundTraceContext | undefined;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A `fetch`-shaped function. Generic so the wrapper types cleanly against both
3
+ * the global `fetch` (CLI host) and `node-fetch` (codedapp-tool's uploads),
4
+ * each keeping its own input/init/response types.
5
+ */
6
+ type FetchLike = (input: any, init?: any) => Promise<{
7
+ ok: boolean;
8
+ status: number;
9
+ }>;
10
+ /**
11
+ * Wraps a `fetch` implementation so every outbound call is reported as an App
12
+ * Insights dependency, nested under the command's request.
13
+ *
14
+ * This is the single enforcement point for "every outbound network call is a
15
+ * dependency": installed over `globalThis.fetch` at CLI startup, it covers all
16
+ * SDKs and auth without touching their call sites, because they all funnel
17
+ * through the global `fetch`. codedapp-tool wraps its own `node-fetch` the same
18
+ * way (see its lint allowlist entry).
19
+ *
20
+ * Behaviour:
21
+ * - Outside a request scope (no active telemetry context) the call passes
22
+ * through untracked and unmodified — nothing to correlate to.
23
+ * - Inside a scope it stamps a W3C `traceparent` header so the server side can
24
+ * join the same trace, times the call, and emits a dependency whose success
25
+ * reflects `response.ok` (an HTTP 4xx/5xx resolves normally but is not a
26
+ * successful dependency).
27
+ *
28
+ * Security: the dependency name is `METHOD /path` only — never the query string
29
+ * (which can carry tokens/PII) and never request headers. The host is recorded
30
+ * as a plain, non-sensitive dimension.
31
+ */
32
+ export declare function makeTrackedFetch<F extends FetchLike>(realFetch: F): F;
33
+ export {};
@@ -5,6 +5,21 @@ export interface CommandContext {
5
5
  /** AbortSignal wired to SIGINT/SIGTERM. Pass to `pollUntil({ signal })` for graceful cancellation. */
6
6
  pollSignal?: AbortSignal;
7
7
  }
8
+ /**
9
+ * Namespace prefix for a command's own invocation arguments in telemetry.
10
+ *
11
+ * Command args and options are user-supplied and carry arbitrary names, so they
12
+ * are the one part of the property bag whose keys we don't control. Emitting
13
+ * them bare at the root of the event lets an arg named like a reserved
14
+ * dimension (`operationId`, `duration`, `success`, …) shadow that dimension —
15
+ * e.g. `uip oms organizations operation get <operationId>` overwriting the
16
+ * correlation tag. Prefixing every extracted arg with a dedicated namespace
17
+ * (mirrors OpenTelemetry attribute-namespacing) walls them off: a user arg can
18
+ * only ever land under `uip.cmd.arg.*`, never at the root where system and
19
+ * control keys live. System dimensions stay bare — they're a closed, controlled
20
+ * set, like OTel's semantic-convention keys.
21
+ */
22
+ export declare const TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
8
23
  /**
9
24
  * Default CommandContext for tool packages that sets process.exitCode
10
25
  * instead of calling process.exit().