@uipath/apms-tool 1.199.0-preview.91 → 1.199.0-preview.97

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.
Files changed (3) hide show
  1. package/dist/index.js +257 -150
  2. package/dist/tool.js +257 -150
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -21247,7 +21247,7 @@ var {
21247
21247
  var package_default = {
21248
21248
  name: "@uipath/apms-tool",
21249
21249
  license: "MIT",
21250
- version: "1.199.0-preview.91",
21250
+ version: "1.199.0-preview.97",
21251
21251
  description: "CLI plugin for the UiPath Access Policy Management Service.",
21252
21252
  private: false,
21253
21253
  repository: {
@@ -30009,11 +30009,36 @@ class NodeContextStorage {
30009
30009
  return this.storage.getStore();
30010
30010
  }
30011
30011
  }
30012
+ // ../../common/src/telemetry/trace-context.ts
30013
+ var TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
30014
+ var TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
30015
+ function getProcessEnv() {
30016
+ return globalThis.process?.env;
30017
+ }
30018
+ function parseInboundTraceparent(value) {
30019
+ if (!value) {
30020
+ return;
30021
+ }
30022
+ const match = TRACEPARENT_PATTERN.exec(value.trim().toLowerCase());
30023
+ if (!match) {
30024
+ return;
30025
+ }
30026
+ const [, traceId, parentSpanId] = match;
30027
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId)) {
30028
+ return;
30029
+ }
30030
+ return { traceId, parentSpanId };
30031
+ }
30032
+ function getInboundTraceContext() {
30033
+ return parseInboundTraceparent(getProcessEnv()?.[TELEMETRY_TRACEPARENT_ENV]);
30034
+ }
30035
+
30012
30036
  // ../../common/src/telemetry/session-id.ts
30013
30037
  var TELEMETRY_SESSION_ID_ENV = "UIPATH_SESSION_ID";
30014
30038
  var TELEMETRY_SESSION_ID_PROPERTY = "session_id";
30015
30039
  var telemetrySessionIdSlot = singleton("TelemetrySessionId");
30016
- function getProcessEnv() {
30040
+ var telemetryOperationIdSlot = singleton("TelemetryOperationId");
30041
+ function getProcessEnv2() {
30017
30042
  return globalThis.process?.env;
30018
30043
  }
30019
30044
  function normalizeSessionId(value) {
@@ -30024,12 +30049,159 @@ function normalizeSessionId(value) {
30024
30049
  return trimmed || undefined;
30025
30050
  }
30026
30051
  function getConfiguredTelemetrySessionId() {
30027
- return normalizeSessionId(getProcessEnv()?.[TELEMETRY_SESSION_ID_ENV]);
30052
+ return normalizeSessionId(getProcessEnv2()?.[TELEMETRY_SESSION_ID_ENV]);
30028
30053
  }
30029
30054
  function resolveTelemetrySessionId(existingSessionId) {
30030
30055
  return getConfiguredTelemetrySessionId() ?? normalizeSessionId(existingSessionId);
30031
30056
  }
30057
+ function getTelemetryOperationId() {
30058
+ const existing = telemetryOperationIdSlot.get();
30059
+ if (existing) {
30060
+ return existing;
30061
+ }
30062
+ const inboundTraceId = getInboundTraceContext()?.traceId;
30063
+ const generated = inboundTraceId ?? crypto.randomUUID().replaceAll("-", "");
30064
+ telemetryOperationIdSlot.set(generated);
30065
+ return generated;
30066
+ }
30067
+ // ../../common/src/telemetry/pii-redactor.ts
30068
+ var REDACTED = "[REDACTED]";
30069
+ var MAX_VALUE_LENGTH = 200;
30070
+ var SENSITIVE_NAME_TOKENS = new Set([
30071
+ "token",
30072
+ "tokens",
30073
+ "secret",
30074
+ "secrets",
30075
+ "password",
30076
+ "passwords",
30077
+ "pwd",
30078
+ "credential",
30079
+ "credentials",
30080
+ "auth",
30081
+ "authentication",
30082
+ "authorization",
30083
+ "authority",
30084
+ "cert",
30085
+ "certificate",
30086
+ "certificates"
30087
+ ]);
30088
+ var SENSITIVE_KEY_PREFIXES = new Set([
30089
+ "api",
30090
+ "access",
30091
+ "client",
30092
+ "private",
30093
+ "public",
30094
+ "signing",
30095
+ "encryption",
30096
+ "session",
30097
+ "master",
30098
+ "shared",
30099
+ "root",
30100
+ "ssh",
30101
+ "rsa",
30102
+ "aes",
30103
+ "hmac",
30104
+ "oauth"
30105
+ ]);
30106
+ 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;
30107
+ var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
30108
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
30109
+ var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
30110
+ var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
30111
+ var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
30112
+ var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
30113
+ function shortHash(input) {
30114
+ let hash = 2166136261;
30115
+ for (let i = 0;i < input.length; i++) {
30116
+ hash ^= input.charCodeAt(i);
30117
+ hash = Math.imul(hash, 16777619);
30118
+ }
30119
+ return (hash >>> 0).toString(16).padStart(8, "0");
30120
+ }
30121
+ function redactUrl(raw) {
30122
+ try {
30123
+ const url = new URL(raw);
30124
+ return `${url.protocol}//${url.host}`;
30125
+ } catch {
30126
+ return `url#${shortHash(raw)}`;
30127
+ }
30128
+ }
30129
+ function redactValueDetectors(value) {
30130
+ let out = value;
30131
+ out = out.replace(JWT_PATTERN, () => REDACTED);
30132
+ out = out.replace(URL_PATTERN, (match) => {
30133
+ const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
30134
+ const core2 = trailing ? match.slice(0, -trailing.length) : match;
30135
+ return `${redactUrl(core2)}${trailing}`;
30136
+ });
30137
+ out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
30138
+ out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
30139
+ out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
30140
+ out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
30141
+ if (out.length > MAX_VALUE_LENGTH) {
30142
+ out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
30143
+ }
30144
+ return out;
30145
+ }
30146
+ function redactValue(value) {
30147
+ return redactValueDetectors(value);
30148
+ }
30149
+ function redactError(error) {
30150
+ const safe = new Error(redactValueDetectors(error.message ?? ""));
30151
+ safe.name = error.name;
30152
+ safe.stack = typeof error.stack === "string" ? redactValueDetectors(error.stack) : undefined;
30153
+ return safe;
30154
+ }
30155
+ function nameTokens(name) {
30156
+ 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);
30157
+ }
30158
+ function isSensitiveName(name) {
30159
+ const tokens = nameTokens(name);
30160
+ for (let i = 0;i < tokens.length; i++) {
30161
+ const token = tokens[i];
30162
+ if (SENSITIVE_NAME_TOKENS.has(token)) {
30163
+ return true;
30164
+ }
30165
+ if (token === "key" || token === "keys") {
30166
+ const prev = tokens[i - 1];
30167
+ if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
30168
+ return true;
30169
+ }
30170
+ }
30171
+ }
30172
+ return false;
30173
+ }
30174
+ function redactProperty(name, value) {
30175
+ if (value === undefined || value === null) {
30176
+ return;
30177
+ }
30178
+ if (isSensitiveName(name)) {
30179
+ return REDACTED;
30180
+ }
30181
+ if (typeof value === "boolean" || typeof value === "number") {
30182
+ return value;
30183
+ }
30184
+ if (typeof value !== "string") {
30185
+ return "[OBJECT]";
30186
+ }
30187
+ return redactValueDetectors(value);
30188
+ }
30189
+ function redactProperties(properties) {
30190
+ const out = {};
30191
+ for (const [name, value] of Object.entries(properties)) {
30192
+ const redacted = redactProperty(name, value);
30193
+ if (redacted !== undefined) {
30194
+ out[name] = redacted;
30195
+ }
30196
+ }
30197
+ return out;
30198
+ }
30199
+
30032
30200
  // ../../common/src/telemetry/telemetry-service.ts
30201
+ var TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
30202
+ var TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
30203
+ var TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
30204
+
30033
30205
  class TelemetryService {
30034
30206
  telemetryProvider;
30035
30207
  contextStorage;
@@ -30056,11 +30228,15 @@ class TelemetryService {
30056
30228
  trackException(error, properties) {
30057
30229
  const context = this.getCurrentContext();
30058
30230
  const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
30059
- this.telemetryProvider.trackException(error, enrichedProperties);
30231
+ this.telemetryProvider.trackException(redactError(error), enrichedProperties);
30060
30232
  }
30061
30233
  async trackRequest(name, fn, properties) {
30234
+ const parentContext = this.getCurrentContext();
30235
+ const operationId = parentContext?.operationId ?? this.operationId ?? getTelemetryOperationId();
30236
+ const parentId = parentContext ? parentContext.id : this.inboundParentIdFor(operationId);
30062
30237
  const context = {
30063
- operationId: this.operationId ?? this.generateId(),
30238
+ operationId,
30239
+ ...parentId !== undefined ? { parentId } : {},
30064
30240
  id: this.generateId()
30065
30241
  };
30066
30242
  const startTime = performance.now();
@@ -30078,6 +30254,45 @@ class TelemetryService {
30078
30254
  throw error;
30079
30255
  }
30080
30256
  }
30257
+ trackRequestResult(name, durationMs, success, properties, context) {
30258
+ const requestContext = context ?? {
30259
+ operationId: this.operationId ?? getTelemetryOperationId(),
30260
+ id: this.generateId()
30261
+ };
30262
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, requestContext);
30263
+ this.telemetryProvider.trackRequest(name, durationMs, success, enrichedProperties);
30264
+ }
30265
+ createRequestContext() {
30266
+ const operationId = this.operationId ?? getTelemetryOperationId();
30267
+ const parentId = this.inboundParentIdFor(operationId);
30268
+ return {
30269
+ operationId,
30270
+ ...parentId !== undefined ? { parentId } : {},
30271
+ id: this.generateId()
30272
+ };
30273
+ }
30274
+ inboundParentIdFor(operationId) {
30275
+ const inbound = getInboundTraceContext();
30276
+ return inbound && inbound.traceId === operationId ? inbound.parentSpanId : undefined;
30277
+ }
30278
+ runWithContext(context, fn) {
30279
+ return this.contextStorage.run(context, fn);
30280
+ }
30281
+ createDependencyContext() {
30282
+ const parentContext = this.getCurrentContext();
30283
+ if (!parentContext) {
30284
+ return;
30285
+ }
30286
+ return {
30287
+ operationId: parentContext.operationId,
30288
+ parentId: parentContext.id,
30289
+ id: this.generateId()
30290
+ };
30291
+ }
30292
+ trackDependencyResult(name, type2, durationMs, success, properties, context, resultCode) {
30293
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
30294
+ this.telemetryProvider.trackDependency(redactValue(name), type2, durationMs, success, enrichedProperties, resultCode);
30295
+ }
30081
30296
  async trackDependencyOperation(name, type2, fn, properties) {
30082
30297
  const parentContext = this.getCurrentContext();
30083
30298
  if (!parentContext) {
@@ -30114,8 +30329,12 @@ class TelemetryService {
30114
30329
  ...getExecutionContextTelemetryProperties(),
30115
30330
  ...globalProperties,
30116
30331
  ...this.defaultProperties,
30117
- ...properties,
30118
- ...context
30332
+ ...redactProperties(properties ?? {}),
30333
+ ...context ? {
30334
+ [TELEMETRY_OPERATION_ID_PROPERTY]: context.operationId,
30335
+ ...context.parentId !== undefined ? { [TELEMETRY_PARENT_ID_PROPERTY]: context.parentId } : {},
30336
+ [TELEMETRY_SPAN_ID_PROPERTY]: context.id
30337
+ } : {}
30119
30338
  };
30120
30339
  if (sessionId === undefined) {
30121
30340
  delete enriched[TELEMETRY_SESSION_ID_PROPERTY];
@@ -30125,7 +30344,16 @@ class TelemetryService {
30125
30344
  return enriched;
30126
30345
  }
30127
30346
  generateId() {
30128
- return crypto.randomUUID().replaceAll("-", "");
30347
+ const bytes = new Uint8Array(8);
30348
+ let hex = "";
30349
+ do {
30350
+ crypto.getRandomValues(bytes);
30351
+ hex = "";
30352
+ for (const byte of bytes) {
30353
+ hex += byte.toString(16).padStart(2, "0");
30354
+ }
30355
+ } while (/^0+$/.test(hex));
30356
+ return hex;
30129
30357
  }
30130
30358
  }
30131
30359
  // ../../common/src/telemetry/node-appinsights-telemetry-provider.ts
@@ -30828,134 +31056,11 @@ function buildCommandTelemetryAttribution(commandPath, skillSource) {
30828
31056
  };
30829
31057
  }
30830
31058
 
30831
- // ../../common/src/telemetry/pii-redactor.ts
30832
- var REDACTED = "[REDACTED]";
30833
- var MAX_VALUE_LENGTH = 200;
30834
- var SENSITIVE_NAME_TOKENS = new Set([
30835
- "token",
30836
- "tokens",
30837
- "secret",
30838
- "secrets",
30839
- "password",
30840
- "passwords",
30841
- "pwd",
30842
- "credential",
30843
- "credentials",
30844
- "auth",
30845
- "authentication",
30846
- "authorization",
30847
- "authority",
30848
- "cert",
30849
- "certificate",
30850
- "certificates"
30851
- ]);
30852
- var SENSITIVE_KEY_PREFIXES = new Set([
30853
- "api",
30854
- "access",
30855
- "client",
30856
- "private",
30857
- "public",
30858
- "signing",
30859
- "encryption",
30860
- "session",
30861
- "master",
30862
- "shared",
30863
- "root",
30864
- "ssh",
30865
- "rsa",
30866
- "aes",
30867
- "hmac",
30868
- "oauth"
30869
- ]);
30870
- 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;
30871
- var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
30872
- var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
30873
- var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
30874
- var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
30875
- var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
30876
- var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
30877
- function shortHash(input) {
30878
- let hash = 2166136261;
30879
- for (let i = 0;i < input.length; i++) {
30880
- hash ^= input.charCodeAt(i);
30881
- hash = Math.imul(hash, 16777619);
30882
- }
30883
- return (hash >>> 0).toString(16).padStart(8, "0");
30884
- }
30885
- function redactUrl(raw) {
30886
- try {
30887
- const url = new URL(raw);
30888
- return `${url.protocol}//${url.host}`;
30889
- } catch {
30890
- return `url#${shortHash(raw)}`;
30891
- }
30892
- }
30893
- function redactValueDetectors(value) {
30894
- let out = value;
30895
- out = out.replace(JWT_PATTERN, () => REDACTED);
30896
- out = out.replace(URL_PATTERN, (match) => {
30897
- const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
30898
- const core2 = trailing ? match.slice(0, -trailing.length) : match;
30899
- return `${redactUrl(core2)}${trailing}`;
30900
- });
30901
- out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
30902
- out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
30903
- out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
30904
- out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
30905
- if (out.length > MAX_VALUE_LENGTH) {
30906
- out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
30907
- }
30908
- return out;
30909
- }
30910
- function nameTokens(name) {
30911
- 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);
30912
- }
30913
- function isSensitiveName(name) {
30914
- const tokens = nameTokens(name);
30915
- for (let i = 0;i < tokens.length; i++) {
30916
- const token = tokens[i];
30917
- if (SENSITIVE_NAME_TOKENS.has(token)) {
30918
- return true;
30919
- }
30920
- if (token === "key" || token === "keys") {
30921
- const prev = tokens[i - 1];
30922
- if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
30923
- return true;
30924
- }
30925
- }
30926
- }
30927
- return false;
30928
- }
30929
- function redactProperty(name, value) {
30930
- if (value === undefined || value === null) {
30931
- return;
30932
- }
30933
- if (isSensitiveName(name)) {
30934
- return REDACTED;
30935
- }
30936
- if (typeof value === "boolean" || typeof value === "number") {
30937
- return value;
30938
- }
30939
- if (typeof value !== "string") {
30940
- return "[OBJECT]";
30941
- }
30942
- return redactValueDetectors(value);
30943
- }
30944
- function redactProperties(properties) {
30945
- const out = {};
30946
- for (const [name, value] of Object.entries(properties)) {
30947
- const redacted = redactProperty(name, value);
30948
- if (redacted !== undefined) {
30949
- out[name] = redacted;
30950
- }
30951
- }
30952
- return out;
30953
- }
30954
-
30955
31059
  // ../../common/src/trackedAction.ts
30956
31060
  var pollSignalSlot = singleton("PollSignal");
30957
31061
  var cliErrorCodeValues = new Set(CLI_ERROR_CODES);
30958
31062
  var retryHintValues = new Set(RETRY_HINTS);
31063
+ var TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
30959
31064
  var processContext = {
30960
31065
  exit: (code) => {
30961
31066
  process.exitCode = code;
@@ -30966,22 +31071,18 @@ var processContext = {
30966
31071
  };
30967
31072
  function extractCommandParams(cmd) {
30968
31073
  const params = {};
31074
+ const add2 = (name, value) => {
31075
+ if (name && value !== undefined) {
31076
+ params[`${TELEMETRY_COMMAND_ARG_PREFIX}${name}`] = value;
31077
+ }
31078
+ };
30969
31079
  const registered = cmd.registeredArguments ?? [];
30970
31080
  const processed = cmd.processedArgs ?? [];
30971
31081
  for (let i = 0;i < registered.length; i++) {
30972
- const value = processed[i];
30973
- if (value === undefined) {
30974
- continue;
30975
- }
30976
- const name = registered[i].name();
30977
- if (name) {
30978
- params[name] = value;
30979
- }
31082
+ add2(registered[i].name(), processed[i]);
30980
31083
  }
30981
31084
  for (const [key, value] of Object.entries(cmd.opts())) {
30982
- if (value !== undefined) {
30983
- params[key] = value;
30984
- }
31085
+ add2(key, value);
30985
31086
  }
30986
31087
  return params;
30987
31088
  }
@@ -31024,11 +31125,12 @@ Command.prototype.trackedAction = function(context, fn, properties) {
31024
31125
  return this.action(async (...args) => {
31025
31126
  const telemetryName = deriveCommandPath(command);
31026
31127
  const props = typeof properties === "function" ? properties(...args) : properties;
31128
+ const requestContext = telemetry.createRequestContext();
31027
31129
  const startTime = performance.now();
31028
31130
  let errorMessage2;
31029
31131
  let fallbackExitCode = EXIT_CODES.Success;
31030
31132
  clearRecordedCommandFailureTelemetry();
31031
- const [error] = await catchError2(fn(...args));
31133
+ const [error] = await catchError2(telemetry.runWithContext(requestContext, () => fn(...args)));
31032
31134
  if (error) {
31033
31135
  errorMessage2 = error instanceof Error ? error.message : String(error);
31034
31136
  logger.debug(`[trackedAction] ${telemetryName} failed: ${errorMessage2}`);
@@ -31064,16 +31166,21 @@ Command.prototype.trackedAction = function(context, fn, properties) {
31064
31166
  recordedFailure,
31065
31167
  pollSignal: context.pollSignal
31066
31168
  });
31067
- telemetry.trackEvent(telemetryName, redactProperties({
31068
- ...extractCommandParams(command),
31169
+ const commandParams = extractCommandParams(command);
31170
+ if (props) {
31171
+ for (const key of Object.keys(props)) {
31172
+ delete commandParams[`${TELEMETRY_COMMAND_ARG_PREFIX}${key}`];
31173
+ }
31174
+ }
31175
+ const baseProperties = redactProperties({
31176
+ ...commandParams,
31069
31177
  ...props,
31070
31178
  ...buildCommandTelemetryAttribution(telemetryName, process.env.UIPATH_SKILL),
31071
31179
  command: "true",
31072
- duration: String(durationMs),
31073
- success: String(success),
31074
31180
  ...terminalTelemetry,
31075
31181
  ...errorMessage2 ? { errorMessage: errorMessage2 } : {}
31076
- }));
31182
+ });
31183
+ telemetry.trackRequestResult(telemetryName, durationMs, success, baseProperties, requestContext);
31077
31184
  });
31078
31185
  };
31079
31186
  // ../../common/src/console-guard.ts
@@ -32288,4 +32395,4 @@ program2.name(metadata.commandPrefix).description(metadata.description).version(
32288
32395
  await registerCommands(program2);
32289
32396
  program2.parse(process.argv);
32290
32397
 
32291
- //# debugId=EFC2EA77C44EDEC564756E2164756E21
32398
+ //# debugId=17BD382D326723E264756E2164756E21
package/dist/tool.js CHANGED
@@ -19137,7 +19137,7 @@ var init_server = __esm(() => {
19137
19137
  var package_default = {
19138
19138
  name: "@uipath/apms-tool",
19139
19139
  license: "MIT",
19140
- version: "1.199.0-preview.91",
19140
+ version: "1.199.0-preview.97",
19141
19141
  description: "CLI plugin for the UiPath Access Policy Management Service.",
19142
19142
  private: false,
19143
19143
  repository: {
@@ -27900,11 +27900,36 @@ class NodeContextStorage {
27900
27900
  return this.storage.getStore();
27901
27901
  }
27902
27902
  }
27903
+ // ../../common/src/telemetry/trace-context.ts
27904
+ var TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
27905
+ var TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
27906
+ function getProcessEnv() {
27907
+ return globalThis.process?.env;
27908
+ }
27909
+ function parseInboundTraceparent(value) {
27910
+ if (!value) {
27911
+ return;
27912
+ }
27913
+ const match = TRACEPARENT_PATTERN.exec(value.trim().toLowerCase());
27914
+ if (!match) {
27915
+ return;
27916
+ }
27917
+ const [, traceId, parentSpanId] = match;
27918
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId)) {
27919
+ return;
27920
+ }
27921
+ return { traceId, parentSpanId };
27922
+ }
27923
+ function getInboundTraceContext() {
27924
+ return parseInboundTraceparent(getProcessEnv()?.[TELEMETRY_TRACEPARENT_ENV]);
27925
+ }
27926
+
27903
27927
  // ../../common/src/telemetry/session-id.ts
27904
27928
  var TELEMETRY_SESSION_ID_ENV = "UIPATH_SESSION_ID";
27905
27929
  var TELEMETRY_SESSION_ID_PROPERTY = "session_id";
27906
27930
  var telemetrySessionIdSlot = singleton("TelemetrySessionId");
27907
- function getProcessEnv() {
27931
+ var telemetryOperationIdSlot = singleton("TelemetryOperationId");
27932
+ function getProcessEnv2() {
27908
27933
  return globalThis.process?.env;
27909
27934
  }
27910
27935
  function normalizeSessionId(value) {
@@ -27915,12 +27940,159 @@ function normalizeSessionId(value) {
27915
27940
  return trimmed || undefined;
27916
27941
  }
27917
27942
  function getConfiguredTelemetrySessionId() {
27918
- return normalizeSessionId(getProcessEnv()?.[TELEMETRY_SESSION_ID_ENV]);
27943
+ return normalizeSessionId(getProcessEnv2()?.[TELEMETRY_SESSION_ID_ENV]);
27919
27944
  }
27920
27945
  function resolveTelemetrySessionId(existingSessionId) {
27921
27946
  return getConfiguredTelemetrySessionId() ?? normalizeSessionId(existingSessionId);
27922
27947
  }
27948
+ function getTelemetryOperationId() {
27949
+ const existing = telemetryOperationIdSlot.get();
27950
+ if (existing) {
27951
+ return existing;
27952
+ }
27953
+ const inboundTraceId = getInboundTraceContext()?.traceId;
27954
+ const generated = inboundTraceId ?? crypto.randomUUID().replaceAll("-", "");
27955
+ telemetryOperationIdSlot.set(generated);
27956
+ return generated;
27957
+ }
27958
+ // ../../common/src/telemetry/pii-redactor.ts
27959
+ var REDACTED = "[REDACTED]";
27960
+ var MAX_VALUE_LENGTH = 200;
27961
+ var SENSITIVE_NAME_TOKENS = new Set([
27962
+ "token",
27963
+ "tokens",
27964
+ "secret",
27965
+ "secrets",
27966
+ "password",
27967
+ "passwords",
27968
+ "pwd",
27969
+ "credential",
27970
+ "credentials",
27971
+ "auth",
27972
+ "authentication",
27973
+ "authorization",
27974
+ "authority",
27975
+ "cert",
27976
+ "certificate",
27977
+ "certificates"
27978
+ ]);
27979
+ var SENSITIVE_KEY_PREFIXES = new Set([
27980
+ "api",
27981
+ "access",
27982
+ "client",
27983
+ "private",
27984
+ "public",
27985
+ "signing",
27986
+ "encryption",
27987
+ "session",
27988
+ "master",
27989
+ "shared",
27990
+ "root",
27991
+ "ssh",
27992
+ "rsa",
27993
+ "aes",
27994
+ "hmac",
27995
+ "oauth"
27996
+ ]);
27997
+ 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;
27998
+ var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
27999
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
28000
+ var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
28001
+ var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
28002
+ var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
28003
+ var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
28004
+ function shortHash(input) {
28005
+ let hash = 2166136261;
28006
+ for (let i = 0;i < input.length; i++) {
28007
+ hash ^= input.charCodeAt(i);
28008
+ hash = Math.imul(hash, 16777619);
28009
+ }
28010
+ return (hash >>> 0).toString(16).padStart(8, "0");
28011
+ }
28012
+ function redactUrl(raw) {
28013
+ try {
28014
+ const url = new URL(raw);
28015
+ return `${url.protocol}//${url.host}`;
28016
+ } catch {
28017
+ return `url#${shortHash(raw)}`;
28018
+ }
28019
+ }
28020
+ function redactValueDetectors(value) {
28021
+ let out = value;
28022
+ out = out.replace(JWT_PATTERN, () => REDACTED);
28023
+ out = out.replace(URL_PATTERN, (match) => {
28024
+ const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
28025
+ const core2 = trailing ? match.slice(0, -trailing.length) : match;
28026
+ return `${redactUrl(core2)}${trailing}`;
28027
+ });
28028
+ out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
28029
+ out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
28030
+ out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
28031
+ out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
28032
+ if (out.length > MAX_VALUE_LENGTH) {
28033
+ out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
28034
+ }
28035
+ return out;
28036
+ }
28037
+ function redactValue(value) {
28038
+ return redactValueDetectors(value);
28039
+ }
28040
+ function redactError(error) {
28041
+ const safe = new Error(redactValueDetectors(error.message ?? ""));
28042
+ safe.name = error.name;
28043
+ safe.stack = typeof error.stack === "string" ? redactValueDetectors(error.stack) : undefined;
28044
+ return safe;
28045
+ }
28046
+ function nameTokens(name) {
28047
+ 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);
28048
+ }
28049
+ function isSensitiveName(name) {
28050
+ const tokens = nameTokens(name);
28051
+ for (let i = 0;i < tokens.length; i++) {
28052
+ const token = tokens[i];
28053
+ if (SENSITIVE_NAME_TOKENS.has(token)) {
28054
+ return true;
28055
+ }
28056
+ if (token === "key" || token === "keys") {
28057
+ const prev = tokens[i - 1];
28058
+ if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
28059
+ return true;
28060
+ }
28061
+ }
28062
+ }
28063
+ return false;
28064
+ }
28065
+ function redactProperty(name, value) {
28066
+ if (value === undefined || value === null) {
28067
+ return;
28068
+ }
28069
+ if (isSensitiveName(name)) {
28070
+ return REDACTED;
28071
+ }
28072
+ if (typeof value === "boolean" || typeof value === "number") {
28073
+ return value;
28074
+ }
28075
+ if (typeof value !== "string") {
28076
+ return "[OBJECT]";
28077
+ }
28078
+ return redactValueDetectors(value);
28079
+ }
28080
+ function redactProperties(properties) {
28081
+ const out = {};
28082
+ for (const [name, value] of Object.entries(properties)) {
28083
+ const redacted = redactProperty(name, value);
28084
+ if (redacted !== undefined) {
28085
+ out[name] = redacted;
28086
+ }
28087
+ }
28088
+ return out;
28089
+ }
28090
+
27923
28091
  // ../../common/src/telemetry/telemetry-service.ts
28092
+ var TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
28093
+ var TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
28094
+ var TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
28095
+
27924
28096
  class TelemetryService {
27925
28097
  telemetryProvider;
27926
28098
  contextStorage;
@@ -27947,11 +28119,15 @@ class TelemetryService {
27947
28119
  trackException(error, properties) {
27948
28120
  const context = this.getCurrentContext();
27949
28121
  const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
27950
- this.telemetryProvider.trackException(error, enrichedProperties);
28122
+ this.telemetryProvider.trackException(redactError(error), enrichedProperties);
27951
28123
  }
27952
28124
  async trackRequest(name, fn, properties) {
28125
+ const parentContext = this.getCurrentContext();
28126
+ const operationId = parentContext?.operationId ?? this.operationId ?? getTelemetryOperationId();
28127
+ const parentId = parentContext ? parentContext.id : this.inboundParentIdFor(operationId);
27953
28128
  const context = {
27954
- operationId: this.operationId ?? this.generateId(),
28129
+ operationId,
28130
+ ...parentId !== undefined ? { parentId } : {},
27955
28131
  id: this.generateId()
27956
28132
  };
27957
28133
  const startTime = performance.now();
@@ -27969,6 +28145,45 @@ class TelemetryService {
27969
28145
  throw error;
27970
28146
  }
27971
28147
  }
28148
+ trackRequestResult(name, durationMs, success, properties, context) {
28149
+ const requestContext = context ?? {
28150
+ operationId: this.operationId ?? getTelemetryOperationId(),
28151
+ id: this.generateId()
28152
+ };
28153
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, requestContext);
28154
+ this.telemetryProvider.trackRequest(name, durationMs, success, enrichedProperties);
28155
+ }
28156
+ createRequestContext() {
28157
+ const operationId = this.operationId ?? getTelemetryOperationId();
28158
+ const parentId = this.inboundParentIdFor(operationId);
28159
+ return {
28160
+ operationId,
28161
+ ...parentId !== undefined ? { parentId } : {},
28162
+ id: this.generateId()
28163
+ };
28164
+ }
28165
+ inboundParentIdFor(operationId) {
28166
+ const inbound = getInboundTraceContext();
28167
+ return inbound && inbound.traceId === operationId ? inbound.parentSpanId : undefined;
28168
+ }
28169
+ runWithContext(context, fn) {
28170
+ return this.contextStorage.run(context, fn);
28171
+ }
28172
+ createDependencyContext() {
28173
+ const parentContext = this.getCurrentContext();
28174
+ if (!parentContext) {
28175
+ return;
28176
+ }
28177
+ return {
28178
+ operationId: parentContext.operationId,
28179
+ parentId: parentContext.id,
28180
+ id: this.generateId()
28181
+ };
28182
+ }
28183
+ trackDependencyResult(name, type2, durationMs, success, properties, context, resultCode) {
28184
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
28185
+ this.telemetryProvider.trackDependency(redactValue(name), type2, durationMs, success, enrichedProperties, resultCode);
28186
+ }
27972
28187
  async trackDependencyOperation(name, type2, fn, properties) {
27973
28188
  const parentContext = this.getCurrentContext();
27974
28189
  if (!parentContext) {
@@ -28005,8 +28220,12 @@ class TelemetryService {
28005
28220
  ...getExecutionContextTelemetryProperties(),
28006
28221
  ...globalProperties,
28007
28222
  ...this.defaultProperties,
28008
- ...properties,
28009
- ...context
28223
+ ...redactProperties(properties ?? {}),
28224
+ ...context ? {
28225
+ [TELEMETRY_OPERATION_ID_PROPERTY]: context.operationId,
28226
+ ...context.parentId !== undefined ? { [TELEMETRY_PARENT_ID_PROPERTY]: context.parentId } : {},
28227
+ [TELEMETRY_SPAN_ID_PROPERTY]: context.id
28228
+ } : {}
28010
28229
  };
28011
28230
  if (sessionId === undefined) {
28012
28231
  delete enriched[TELEMETRY_SESSION_ID_PROPERTY];
@@ -28016,7 +28235,16 @@ class TelemetryService {
28016
28235
  return enriched;
28017
28236
  }
28018
28237
  generateId() {
28019
- return crypto.randomUUID().replaceAll("-", "");
28238
+ const bytes = new Uint8Array(8);
28239
+ let hex = "";
28240
+ do {
28241
+ crypto.getRandomValues(bytes);
28242
+ hex = "";
28243
+ for (const byte of bytes) {
28244
+ hex += byte.toString(16).padStart(2, "0");
28245
+ }
28246
+ } while (/^0+$/.test(hex));
28247
+ return hex;
28020
28248
  }
28021
28249
  }
28022
28250
  // ../../common/src/telemetry/node-appinsights-telemetry-provider.ts
@@ -28722,134 +28950,11 @@ function buildCommandTelemetryAttribution(commandPath, skillSource) {
28722
28950
  };
28723
28951
  }
28724
28952
 
28725
- // ../../common/src/telemetry/pii-redactor.ts
28726
- var REDACTED = "[REDACTED]";
28727
- var MAX_VALUE_LENGTH = 200;
28728
- var SENSITIVE_NAME_TOKENS = new Set([
28729
- "token",
28730
- "tokens",
28731
- "secret",
28732
- "secrets",
28733
- "password",
28734
- "passwords",
28735
- "pwd",
28736
- "credential",
28737
- "credentials",
28738
- "auth",
28739
- "authentication",
28740
- "authorization",
28741
- "authority",
28742
- "cert",
28743
- "certificate",
28744
- "certificates"
28745
- ]);
28746
- var SENSITIVE_KEY_PREFIXES = new Set([
28747
- "api",
28748
- "access",
28749
- "client",
28750
- "private",
28751
- "public",
28752
- "signing",
28753
- "encryption",
28754
- "session",
28755
- "master",
28756
- "shared",
28757
- "root",
28758
- "ssh",
28759
- "rsa",
28760
- "aes",
28761
- "hmac",
28762
- "oauth"
28763
- ]);
28764
- 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;
28765
- var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
28766
- var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
28767
- var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
28768
- var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
28769
- var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
28770
- var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
28771
- function shortHash(input) {
28772
- let hash = 2166136261;
28773
- for (let i = 0;i < input.length; i++) {
28774
- hash ^= input.charCodeAt(i);
28775
- hash = Math.imul(hash, 16777619);
28776
- }
28777
- return (hash >>> 0).toString(16).padStart(8, "0");
28778
- }
28779
- function redactUrl(raw) {
28780
- try {
28781
- const url = new URL(raw);
28782
- return `${url.protocol}//${url.host}`;
28783
- } catch {
28784
- return `url#${shortHash(raw)}`;
28785
- }
28786
- }
28787
- function redactValueDetectors(value) {
28788
- let out = value;
28789
- out = out.replace(JWT_PATTERN, () => REDACTED);
28790
- out = out.replace(URL_PATTERN, (match) => {
28791
- const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
28792
- const core2 = trailing ? match.slice(0, -trailing.length) : match;
28793
- return `${redactUrl(core2)}${trailing}`;
28794
- });
28795
- out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
28796
- out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
28797
- out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
28798
- out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
28799
- if (out.length > MAX_VALUE_LENGTH) {
28800
- out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
28801
- }
28802
- return out;
28803
- }
28804
- function nameTokens(name) {
28805
- 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);
28806
- }
28807
- function isSensitiveName(name) {
28808
- const tokens = nameTokens(name);
28809
- for (let i = 0;i < tokens.length; i++) {
28810
- const token = tokens[i];
28811
- if (SENSITIVE_NAME_TOKENS.has(token)) {
28812
- return true;
28813
- }
28814
- if (token === "key" || token === "keys") {
28815
- const prev = tokens[i - 1];
28816
- if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
28817
- return true;
28818
- }
28819
- }
28820
- }
28821
- return false;
28822
- }
28823
- function redactProperty(name, value) {
28824
- if (value === undefined || value === null) {
28825
- return;
28826
- }
28827
- if (isSensitiveName(name)) {
28828
- return REDACTED;
28829
- }
28830
- if (typeof value === "boolean" || typeof value === "number") {
28831
- return value;
28832
- }
28833
- if (typeof value !== "string") {
28834
- return "[OBJECT]";
28835
- }
28836
- return redactValueDetectors(value);
28837
- }
28838
- function redactProperties(properties) {
28839
- const out = {};
28840
- for (const [name, value] of Object.entries(properties)) {
28841
- const redacted = redactProperty(name, value);
28842
- if (redacted !== undefined) {
28843
- out[name] = redacted;
28844
- }
28845
- }
28846
- return out;
28847
- }
28848
-
28849
28953
  // ../../common/src/trackedAction.ts
28850
28954
  var pollSignalSlot = singleton("PollSignal");
28851
28955
  var cliErrorCodeValues = new Set(CLI_ERROR_CODES);
28852
28956
  var retryHintValues = new Set(RETRY_HINTS);
28957
+ var TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
28853
28958
  var processContext = {
28854
28959
  exit: (code) => {
28855
28960
  process.exitCode = code;
@@ -28860,22 +28965,18 @@ var processContext = {
28860
28965
  };
28861
28966
  function extractCommandParams(cmd) {
28862
28967
  const params = {};
28968
+ const add2 = (name, value) => {
28969
+ if (name && value !== undefined) {
28970
+ params[`${TELEMETRY_COMMAND_ARG_PREFIX}${name}`] = value;
28971
+ }
28972
+ };
28863
28973
  const registered = cmd.registeredArguments ?? [];
28864
28974
  const processed = cmd.processedArgs ?? [];
28865
28975
  for (let i = 0;i < registered.length; i++) {
28866
- const value = processed[i];
28867
- if (value === undefined) {
28868
- continue;
28869
- }
28870
- const name = registered[i].name();
28871
- if (name) {
28872
- params[name] = value;
28873
- }
28976
+ add2(registered[i].name(), processed[i]);
28874
28977
  }
28875
28978
  for (const [key, value] of Object.entries(cmd.opts())) {
28876
- if (value !== undefined) {
28877
- params[key] = value;
28878
- }
28979
+ add2(key, value);
28879
28980
  }
28880
28981
  return params;
28881
28982
  }
@@ -28918,11 +29019,12 @@ Command2.prototype.trackedAction = function(context, fn, properties) {
28918
29019
  return this.action(async (...args) => {
28919
29020
  const telemetryName = deriveCommandPath(command);
28920
29021
  const props = typeof properties === "function" ? properties(...args) : properties;
29022
+ const requestContext = telemetry.createRequestContext();
28921
29023
  const startTime = performance.now();
28922
29024
  let errorMessage2;
28923
29025
  let fallbackExitCode = EXIT_CODES.Success;
28924
29026
  clearRecordedCommandFailureTelemetry();
28925
- const [error] = await catchError2(fn(...args));
29027
+ const [error] = await catchError2(telemetry.runWithContext(requestContext, () => fn(...args)));
28926
29028
  if (error) {
28927
29029
  errorMessage2 = error instanceof Error ? error.message : String(error);
28928
29030
  logger.debug(`[trackedAction] ${telemetryName} failed: ${errorMessage2}`);
@@ -28958,16 +29060,21 @@ Command2.prototype.trackedAction = function(context, fn, properties) {
28958
29060
  recordedFailure,
28959
29061
  pollSignal: context.pollSignal
28960
29062
  });
28961
- telemetry.trackEvent(telemetryName, redactProperties({
28962
- ...extractCommandParams(command),
29063
+ const commandParams = extractCommandParams(command);
29064
+ if (props) {
29065
+ for (const key of Object.keys(props)) {
29066
+ delete commandParams[`${TELEMETRY_COMMAND_ARG_PREFIX}${key}`];
29067
+ }
29068
+ }
29069
+ const baseProperties = redactProperties({
29070
+ ...commandParams,
28963
29071
  ...props,
28964
29072
  ...buildCommandTelemetryAttribution(telemetryName, process.env.UIPATH_SKILL),
28965
29073
  command: "true",
28966
- duration: String(durationMs),
28967
- success: String(success),
28968
29074
  ...terminalTelemetry,
28969
29075
  ...errorMessage2 ? { errorMessage: errorMessage2 } : {}
28970
- }));
29076
+ });
29077
+ telemetry.trackRequestResult(telemetryName, durationMs, success, baseProperties, requestContext);
28971
29078
  });
28972
29079
  };
28973
29080
  // ../../common/src/console-guard.ts
@@ -30185,4 +30292,4 @@ export {
30185
30292
  metadata
30186
30293
  };
30187
30294
 
30188
- //# debugId=F40F8DAD89C81AF364756E2164756E21
30295
+ //# debugId=A6EBF7BECA3718DE64756E2164756E21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/apms-tool",
3
3
  "license": "MIT",
4
- "version": "1.199.0-preview.91",
4
+ "version": "1.199.0-preview.97",
5
5
  "description": "CLI plugin for the UiPath Access Policy Management Service.",
6
6
  "private": false,
7
7
  "repository": {
@@ -26,5 +26,5 @@
26
26
  "files": [
27
27
  "dist"
28
28
  ],
29
- "gitHead": "f428cb1e61ba89ad18394b0c6106784055699f02"
29
+ "gitHead": "087ae21e842f27bde5eb0013892c9487bfe60568"
30
30
  }