@uipath/apms-tool 1.198.0-preview.95 → 1.198.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.198.0-preview.95",
21250
+ version: "1.198.0",
21251
21251
  description: "CLI plugin for the UiPath Access Policy Management Service.",
21252
21252
  private: false,
21253
21253
  repository: {
@@ -30003,11 +30003,36 @@ class NodeContextStorage {
30003
30003
  return this.storage.getStore();
30004
30004
  }
30005
30005
  }
30006
+ // ../../common/src/telemetry/trace-context.ts
30007
+ var TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
30008
+ var TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
30009
+ function getProcessEnv() {
30010
+ return globalThis.process?.env;
30011
+ }
30012
+ function parseInboundTraceparent(value) {
30013
+ if (!value) {
30014
+ return;
30015
+ }
30016
+ const match = TRACEPARENT_PATTERN.exec(value.trim().toLowerCase());
30017
+ if (!match) {
30018
+ return;
30019
+ }
30020
+ const [, traceId, parentSpanId] = match;
30021
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId)) {
30022
+ return;
30023
+ }
30024
+ return { traceId, parentSpanId };
30025
+ }
30026
+ function getInboundTraceContext() {
30027
+ return parseInboundTraceparent(getProcessEnv()?.[TELEMETRY_TRACEPARENT_ENV]);
30028
+ }
30029
+
30006
30030
  // ../../common/src/telemetry/session-id.ts
30007
30031
  var TELEMETRY_SESSION_ID_ENV = "UIPATH_SESSION_ID";
30008
30032
  var TELEMETRY_SESSION_ID_PROPERTY = "session_id";
30009
30033
  var telemetrySessionIdSlot = singleton("TelemetrySessionId");
30010
- function getProcessEnv() {
30034
+ var telemetryOperationIdSlot = singleton("TelemetryOperationId");
30035
+ function getProcessEnv2() {
30011
30036
  return globalThis.process?.env;
30012
30037
  }
30013
30038
  function normalizeSessionId(value) {
@@ -30018,12 +30043,159 @@ function normalizeSessionId(value) {
30018
30043
  return trimmed || undefined;
30019
30044
  }
30020
30045
  function getConfiguredTelemetrySessionId() {
30021
- return normalizeSessionId(getProcessEnv()?.[TELEMETRY_SESSION_ID_ENV]);
30046
+ return normalizeSessionId(getProcessEnv2()?.[TELEMETRY_SESSION_ID_ENV]);
30022
30047
  }
30023
30048
  function resolveTelemetrySessionId(existingSessionId) {
30024
30049
  return getConfiguredTelemetrySessionId() ?? normalizeSessionId(existingSessionId);
30025
30050
  }
30051
+ function getTelemetryOperationId() {
30052
+ const existing = telemetryOperationIdSlot.get();
30053
+ if (existing) {
30054
+ return existing;
30055
+ }
30056
+ const inboundTraceId = getInboundTraceContext()?.traceId;
30057
+ const generated = inboundTraceId ?? crypto.randomUUID().replaceAll("-", "");
30058
+ telemetryOperationIdSlot.set(generated);
30059
+ return generated;
30060
+ }
30061
+ // ../../common/src/telemetry/pii-redactor.ts
30062
+ var REDACTED = "[REDACTED]";
30063
+ var MAX_VALUE_LENGTH = 200;
30064
+ var SENSITIVE_NAME_TOKENS = new Set([
30065
+ "token",
30066
+ "tokens",
30067
+ "secret",
30068
+ "secrets",
30069
+ "password",
30070
+ "passwords",
30071
+ "pwd",
30072
+ "credential",
30073
+ "credentials",
30074
+ "auth",
30075
+ "authentication",
30076
+ "authorization",
30077
+ "authority",
30078
+ "cert",
30079
+ "certificate",
30080
+ "certificates"
30081
+ ]);
30082
+ var SENSITIVE_KEY_PREFIXES = new Set([
30083
+ "api",
30084
+ "access",
30085
+ "client",
30086
+ "private",
30087
+ "public",
30088
+ "signing",
30089
+ "encryption",
30090
+ "session",
30091
+ "master",
30092
+ "shared",
30093
+ "root",
30094
+ "ssh",
30095
+ "rsa",
30096
+ "aes",
30097
+ "hmac",
30098
+ "oauth"
30099
+ ]);
30100
+ 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;
30101
+ var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
30102
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
30103
+ var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
30104
+ var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
30105
+ var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
30106
+ var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
30107
+ function shortHash(input) {
30108
+ let hash = 2166136261;
30109
+ for (let i = 0;i < input.length; i++) {
30110
+ hash ^= input.charCodeAt(i);
30111
+ hash = Math.imul(hash, 16777619);
30112
+ }
30113
+ return (hash >>> 0).toString(16).padStart(8, "0");
30114
+ }
30115
+ function redactUrl(raw) {
30116
+ try {
30117
+ const url = new URL(raw);
30118
+ return `${url.protocol}//${url.host}`;
30119
+ } catch {
30120
+ return `url#${shortHash(raw)}`;
30121
+ }
30122
+ }
30123
+ function redactValueDetectors(value) {
30124
+ let out = value;
30125
+ out = out.replace(JWT_PATTERN, () => REDACTED);
30126
+ out = out.replace(URL_PATTERN, (match) => {
30127
+ const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
30128
+ const core2 = trailing ? match.slice(0, -trailing.length) : match;
30129
+ return `${redactUrl(core2)}${trailing}`;
30130
+ });
30131
+ out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
30132
+ out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
30133
+ out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
30134
+ out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
30135
+ if (out.length > MAX_VALUE_LENGTH) {
30136
+ out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
30137
+ }
30138
+ return out;
30139
+ }
30140
+ function redactValue(value) {
30141
+ return redactValueDetectors(value);
30142
+ }
30143
+ function redactError(error) {
30144
+ const safe = new Error(redactValueDetectors(error.message ?? ""));
30145
+ safe.name = error.name;
30146
+ safe.stack = typeof error.stack === "string" ? redactValueDetectors(error.stack) : undefined;
30147
+ return safe;
30148
+ }
30149
+ function nameTokens(name) {
30150
+ 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);
30151
+ }
30152
+ function isSensitiveName(name) {
30153
+ const tokens = nameTokens(name);
30154
+ for (let i = 0;i < tokens.length; i++) {
30155
+ const token = tokens[i];
30156
+ if (SENSITIVE_NAME_TOKENS.has(token)) {
30157
+ return true;
30158
+ }
30159
+ if (token === "key" || token === "keys") {
30160
+ const prev = tokens[i - 1];
30161
+ if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
30162
+ return true;
30163
+ }
30164
+ }
30165
+ }
30166
+ return false;
30167
+ }
30168
+ function redactProperty(name, value) {
30169
+ if (value === undefined || value === null) {
30170
+ return;
30171
+ }
30172
+ if (isSensitiveName(name)) {
30173
+ return REDACTED;
30174
+ }
30175
+ if (typeof value === "boolean" || typeof value === "number") {
30176
+ return value;
30177
+ }
30178
+ if (typeof value !== "string") {
30179
+ return "[OBJECT]";
30180
+ }
30181
+ return redactValueDetectors(value);
30182
+ }
30183
+ function redactProperties(properties) {
30184
+ const out = {};
30185
+ for (const [name, value] of Object.entries(properties)) {
30186
+ const redacted = redactProperty(name, value);
30187
+ if (redacted !== undefined) {
30188
+ out[name] = redacted;
30189
+ }
30190
+ }
30191
+ return out;
30192
+ }
30193
+
30026
30194
  // ../../common/src/telemetry/telemetry-service.ts
30195
+ var TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
30196
+ var TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
30197
+ var TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
30198
+
30027
30199
  class TelemetryService {
30028
30200
  telemetryProvider;
30029
30201
  contextStorage;
@@ -30050,11 +30222,15 @@ class TelemetryService {
30050
30222
  trackException(error, properties) {
30051
30223
  const context = this.getCurrentContext();
30052
30224
  const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
30053
- this.telemetryProvider.trackException(error, enrichedProperties);
30225
+ this.telemetryProvider.trackException(redactError(error), enrichedProperties);
30054
30226
  }
30055
30227
  async trackRequest(name, fn, properties) {
30228
+ const parentContext = this.getCurrentContext();
30229
+ const operationId = parentContext?.operationId ?? this.operationId ?? getTelemetryOperationId();
30230
+ const parentId = parentContext ? parentContext.id : this.inboundParentIdFor(operationId);
30056
30231
  const context = {
30057
- operationId: this.operationId ?? this.generateId(),
30232
+ operationId,
30233
+ ...parentId !== undefined ? { parentId } : {},
30058
30234
  id: this.generateId()
30059
30235
  };
30060
30236
  const startTime = performance.now();
@@ -30072,6 +30248,45 @@ class TelemetryService {
30072
30248
  throw error;
30073
30249
  }
30074
30250
  }
30251
+ trackRequestResult(name, durationMs, success, properties, context) {
30252
+ const requestContext = context ?? {
30253
+ operationId: this.operationId ?? getTelemetryOperationId(),
30254
+ id: this.generateId()
30255
+ };
30256
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, requestContext);
30257
+ this.telemetryProvider.trackRequest(name, durationMs, success, enrichedProperties);
30258
+ }
30259
+ createRequestContext() {
30260
+ const operationId = this.operationId ?? getTelemetryOperationId();
30261
+ const parentId = this.inboundParentIdFor(operationId);
30262
+ return {
30263
+ operationId,
30264
+ ...parentId !== undefined ? { parentId } : {},
30265
+ id: this.generateId()
30266
+ };
30267
+ }
30268
+ inboundParentIdFor(operationId) {
30269
+ const inbound = getInboundTraceContext();
30270
+ return inbound && inbound.traceId === operationId ? inbound.parentSpanId : undefined;
30271
+ }
30272
+ runWithContext(context, fn) {
30273
+ return this.contextStorage.run(context, fn);
30274
+ }
30275
+ createDependencyContext() {
30276
+ const parentContext = this.getCurrentContext();
30277
+ if (!parentContext) {
30278
+ return;
30279
+ }
30280
+ return {
30281
+ operationId: parentContext.operationId,
30282
+ parentId: parentContext.id,
30283
+ id: this.generateId()
30284
+ };
30285
+ }
30286
+ trackDependencyResult(name, type2, durationMs, success, properties, context, resultCode) {
30287
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
30288
+ this.telemetryProvider.trackDependency(redactValue(name), type2, durationMs, success, enrichedProperties, resultCode);
30289
+ }
30075
30290
  async trackDependencyOperation(name, type2, fn, properties) {
30076
30291
  const parentContext = this.getCurrentContext();
30077
30292
  if (!parentContext) {
@@ -30108,8 +30323,12 @@ class TelemetryService {
30108
30323
  ...getExecutionContextTelemetryProperties(),
30109
30324
  ...globalProperties,
30110
30325
  ...this.defaultProperties,
30111
- ...properties,
30112
- ...context
30326
+ ...redactProperties(properties ?? {}),
30327
+ ...context ? {
30328
+ [TELEMETRY_OPERATION_ID_PROPERTY]: context.operationId,
30329
+ ...context.parentId !== undefined ? { [TELEMETRY_PARENT_ID_PROPERTY]: context.parentId } : {},
30330
+ [TELEMETRY_SPAN_ID_PROPERTY]: context.id
30331
+ } : {}
30113
30332
  };
30114
30333
  if (sessionId === undefined) {
30115
30334
  delete enriched[TELEMETRY_SESSION_ID_PROPERTY];
@@ -30119,7 +30338,16 @@ class TelemetryService {
30119
30338
  return enriched;
30120
30339
  }
30121
30340
  generateId() {
30122
- return crypto.randomUUID().replaceAll("-", "");
30341
+ const bytes = new Uint8Array(8);
30342
+ let hex = "";
30343
+ do {
30344
+ crypto.getRandomValues(bytes);
30345
+ hex = "";
30346
+ for (const byte of bytes) {
30347
+ hex += byte.toString(16).padStart(2, "0");
30348
+ }
30349
+ } while (/^0+$/.test(hex));
30350
+ return hex;
30123
30351
  }
30124
30352
  }
30125
30353
  // ../../common/src/telemetry/node-appinsights-telemetry-provider.ts
@@ -30821,134 +31049,11 @@ function buildCommandTelemetryAttribution(commandPath, skillSource) {
30821
31049
  };
30822
31050
  }
30823
31051
 
30824
- // ../../common/src/telemetry/pii-redactor.ts
30825
- var REDACTED = "[REDACTED]";
30826
- var MAX_VALUE_LENGTH = 200;
30827
- var SENSITIVE_NAME_TOKENS = new Set([
30828
- "token",
30829
- "tokens",
30830
- "secret",
30831
- "secrets",
30832
- "password",
30833
- "passwords",
30834
- "pwd",
30835
- "credential",
30836
- "credentials",
30837
- "auth",
30838
- "authentication",
30839
- "authorization",
30840
- "authority",
30841
- "cert",
30842
- "certificate",
30843
- "certificates"
30844
- ]);
30845
- var SENSITIVE_KEY_PREFIXES = new Set([
30846
- "api",
30847
- "access",
30848
- "client",
30849
- "private",
30850
- "public",
30851
- "signing",
30852
- "encryption",
30853
- "session",
30854
- "master",
30855
- "shared",
30856
- "root",
30857
- "ssh",
30858
- "rsa",
30859
- "aes",
30860
- "hmac",
30861
- "oauth"
30862
- ]);
30863
- 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;
30864
- var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
30865
- var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
30866
- var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
30867
- var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
30868
- var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
30869
- var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
30870
- function shortHash(input) {
30871
- let hash = 2166136261;
30872
- for (let i = 0;i < input.length; i++) {
30873
- hash ^= input.charCodeAt(i);
30874
- hash = Math.imul(hash, 16777619);
30875
- }
30876
- return (hash >>> 0).toString(16).padStart(8, "0");
30877
- }
30878
- function redactUrl(raw) {
30879
- try {
30880
- const url = new URL(raw);
30881
- return `${url.protocol}//${url.host}`;
30882
- } catch {
30883
- return `url#${shortHash(raw)}`;
30884
- }
30885
- }
30886
- function redactValueDetectors(value) {
30887
- let out = value;
30888
- out = out.replace(JWT_PATTERN, () => REDACTED);
30889
- out = out.replace(URL_PATTERN, (match) => {
30890
- const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
30891
- const core2 = trailing ? match.slice(0, -trailing.length) : match;
30892
- return `${redactUrl(core2)}${trailing}`;
30893
- });
30894
- out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
30895
- out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
30896
- out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
30897
- out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
30898
- if (out.length > MAX_VALUE_LENGTH) {
30899
- out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
30900
- }
30901
- return out;
30902
- }
30903
- function nameTokens(name) {
30904
- 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);
30905
- }
30906
- function isSensitiveName(name) {
30907
- const tokens = nameTokens(name);
30908
- for (let i = 0;i < tokens.length; i++) {
30909
- const token = tokens[i];
30910
- if (SENSITIVE_NAME_TOKENS.has(token)) {
30911
- return true;
30912
- }
30913
- if (token === "key" || token === "keys") {
30914
- const prev = tokens[i - 1];
30915
- if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
30916
- return true;
30917
- }
30918
- }
30919
- }
30920
- return false;
30921
- }
30922
- function redactProperty(name, value) {
30923
- if (value === undefined || value === null) {
30924
- return;
30925
- }
30926
- if (isSensitiveName(name)) {
30927
- return REDACTED;
30928
- }
30929
- if (typeof value === "boolean" || typeof value === "number") {
30930
- return value;
30931
- }
30932
- if (typeof value !== "string") {
30933
- return "[OBJECT]";
30934
- }
30935
- return redactValueDetectors(value);
30936
- }
30937
- function redactProperties(properties) {
30938
- const out = {};
30939
- for (const [name, value] of Object.entries(properties)) {
30940
- const redacted = redactProperty(name, value);
30941
- if (redacted !== undefined) {
30942
- out[name] = redacted;
30943
- }
30944
- }
30945
- return out;
30946
- }
30947
-
30948
31052
  // ../../common/src/trackedAction.ts
30949
31053
  var pollSignalSlot = singleton("PollSignal");
30950
31054
  var cliErrorCodeValues = new Set(CLI_ERROR_CODES);
30951
31055
  var retryHintValues = new Set(RETRY_HINTS);
31056
+ var TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
30952
31057
  var processContext = {
30953
31058
  exit: (code) => {
30954
31059
  process.exitCode = code;
@@ -30959,22 +31064,18 @@ var processContext = {
30959
31064
  };
30960
31065
  function extractCommandParams(cmd) {
30961
31066
  const params = {};
31067
+ const add2 = (name, value) => {
31068
+ if (name && value !== undefined) {
31069
+ params[`${TELEMETRY_COMMAND_ARG_PREFIX}${name}`] = value;
31070
+ }
31071
+ };
30962
31072
  const registered = cmd.registeredArguments ?? [];
30963
31073
  const processed = cmd.processedArgs ?? [];
30964
31074
  for (let i = 0;i < registered.length; i++) {
30965
- const value = processed[i];
30966
- if (value === undefined) {
30967
- continue;
30968
- }
30969
- const name = registered[i].name();
30970
- if (name) {
30971
- params[name] = value;
30972
- }
31075
+ add2(registered[i].name(), processed[i]);
30973
31076
  }
30974
31077
  for (const [key, value] of Object.entries(cmd.opts())) {
30975
- if (value !== undefined) {
30976
- params[key] = value;
30977
- }
31078
+ add2(key, value);
30978
31079
  }
30979
31080
  return params;
30980
31081
  }
@@ -31017,11 +31118,12 @@ Command.prototype.trackedAction = function(context, fn, properties) {
31017
31118
  return this.action(async (...args) => {
31018
31119
  const telemetryName = deriveCommandPath(command);
31019
31120
  const props = typeof properties === "function" ? properties(...args) : properties;
31121
+ const requestContext = telemetry.createRequestContext();
31020
31122
  const startTime = performance.now();
31021
31123
  let errorMessage2;
31022
31124
  let fallbackExitCode = EXIT_CODES.Success;
31023
31125
  clearRecordedCommandFailureTelemetry();
31024
- const [error] = await catchError2(fn(...args));
31126
+ const [error] = await catchError2(telemetry.runWithContext(requestContext, () => fn(...args)));
31025
31127
  if (error) {
31026
31128
  errorMessage2 = error instanceof Error ? error.message : String(error);
31027
31129
  logger.debug(`[trackedAction] ${telemetryName} failed: ${errorMessage2}`);
@@ -31057,16 +31159,21 @@ Command.prototype.trackedAction = function(context, fn, properties) {
31057
31159
  recordedFailure,
31058
31160
  pollSignal: context.pollSignal
31059
31161
  });
31060
- telemetry.trackEvent(telemetryName, redactProperties({
31061
- ...extractCommandParams(command),
31162
+ const commandParams = extractCommandParams(command);
31163
+ if (props) {
31164
+ for (const key of Object.keys(props)) {
31165
+ delete commandParams[`${TELEMETRY_COMMAND_ARG_PREFIX}${key}`];
31166
+ }
31167
+ }
31168
+ const baseProperties = redactProperties({
31169
+ ...commandParams,
31062
31170
  ...props,
31063
31171
  ...buildCommandTelemetryAttribution(telemetryName, process.env.UIPATH_SKILL),
31064
31172
  command: "true",
31065
- duration: String(durationMs),
31066
- success: String(success),
31067
31173
  ...terminalTelemetry,
31068
31174
  ...errorMessage2 ? { errorMessage: errorMessage2 } : {}
31069
- }));
31175
+ });
31176
+ telemetry.trackRequestResult(telemetryName, durationMs, success, baseProperties, requestContext);
31070
31177
  });
31071
31178
  };
31072
31179
  // ../../common/src/console-guard.ts
@@ -32281,4 +32388,4 @@ program2.name(metadata.commandPrefix).description(metadata.description).version(
32281
32388
  await registerCommands(program2);
32282
32389
  program2.parse(process.argv);
32283
32390
 
32284
- //# debugId=C2846D3C639B0E1664756E2164756E21
32391
+ //# debugId=74E589E18B5F8B9964756E2164756E21
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.198.0-preview.95",
19140
+ version: "1.198.0",
19141
19141
  description: "CLI plugin for the UiPath Access Policy Management Service.",
19142
19142
  private: false,
19143
19143
  repository: {
@@ -27894,11 +27894,36 @@ class NodeContextStorage {
27894
27894
  return this.storage.getStore();
27895
27895
  }
27896
27896
  }
27897
+ // ../../common/src/telemetry/trace-context.ts
27898
+ var TELEMETRY_TRACEPARENT_ENV = "TRACEPARENT";
27899
+ var TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-[0-9a-f]{2}$/;
27900
+ function getProcessEnv() {
27901
+ return globalThis.process?.env;
27902
+ }
27903
+ function parseInboundTraceparent(value) {
27904
+ if (!value) {
27905
+ return;
27906
+ }
27907
+ const match = TRACEPARENT_PATTERN.exec(value.trim().toLowerCase());
27908
+ if (!match) {
27909
+ return;
27910
+ }
27911
+ const [, traceId, parentSpanId] = match;
27912
+ if (/^0+$/.test(traceId) || /^0+$/.test(parentSpanId)) {
27913
+ return;
27914
+ }
27915
+ return { traceId, parentSpanId };
27916
+ }
27917
+ function getInboundTraceContext() {
27918
+ return parseInboundTraceparent(getProcessEnv()?.[TELEMETRY_TRACEPARENT_ENV]);
27919
+ }
27920
+
27897
27921
  // ../../common/src/telemetry/session-id.ts
27898
27922
  var TELEMETRY_SESSION_ID_ENV = "UIPATH_SESSION_ID";
27899
27923
  var TELEMETRY_SESSION_ID_PROPERTY = "session_id";
27900
27924
  var telemetrySessionIdSlot = singleton("TelemetrySessionId");
27901
- function getProcessEnv() {
27925
+ var telemetryOperationIdSlot = singleton("TelemetryOperationId");
27926
+ function getProcessEnv2() {
27902
27927
  return globalThis.process?.env;
27903
27928
  }
27904
27929
  function normalizeSessionId(value) {
@@ -27909,12 +27934,159 @@ function normalizeSessionId(value) {
27909
27934
  return trimmed || undefined;
27910
27935
  }
27911
27936
  function getConfiguredTelemetrySessionId() {
27912
- return normalizeSessionId(getProcessEnv()?.[TELEMETRY_SESSION_ID_ENV]);
27937
+ return normalizeSessionId(getProcessEnv2()?.[TELEMETRY_SESSION_ID_ENV]);
27913
27938
  }
27914
27939
  function resolveTelemetrySessionId(existingSessionId) {
27915
27940
  return getConfiguredTelemetrySessionId() ?? normalizeSessionId(existingSessionId);
27916
27941
  }
27942
+ function getTelemetryOperationId() {
27943
+ const existing = telemetryOperationIdSlot.get();
27944
+ if (existing) {
27945
+ return existing;
27946
+ }
27947
+ const inboundTraceId = getInboundTraceContext()?.traceId;
27948
+ const generated = inboundTraceId ?? crypto.randomUUID().replaceAll("-", "");
27949
+ telemetryOperationIdSlot.set(generated);
27950
+ return generated;
27951
+ }
27952
+ // ../../common/src/telemetry/pii-redactor.ts
27953
+ var REDACTED = "[REDACTED]";
27954
+ var MAX_VALUE_LENGTH = 200;
27955
+ var SENSITIVE_NAME_TOKENS = new Set([
27956
+ "token",
27957
+ "tokens",
27958
+ "secret",
27959
+ "secrets",
27960
+ "password",
27961
+ "passwords",
27962
+ "pwd",
27963
+ "credential",
27964
+ "credentials",
27965
+ "auth",
27966
+ "authentication",
27967
+ "authorization",
27968
+ "authority",
27969
+ "cert",
27970
+ "certificate",
27971
+ "certificates"
27972
+ ]);
27973
+ var SENSITIVE_KEY_PREFIXES = new Set([
27974
+ "api",
27975
+ "access",
27976
+ "client",
27977
+ "private",
27978
+ "public",
27979
+ "signing",
27980
+ "encryption",
27981
+ "session",
27982
+ "master",
27983
+ "shared",
27984
+ "root",
27985
+ "ssh",
27986
+ "rsa",
27987
+ "aes",
27988
+ "hmac",
27989
+ "oauth"
27990
+ ]);
27991
+ 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;
27992
+ var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
27993
+ var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
27994
+ var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
27995
+ var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
27996
+ var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
27997
+ var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
27998
+ function shortHash(input) {
27999
+ let hash = 2166136261;
28000
+ for (let i = 0;i < input.length; i++) {
28001
+ hash ^= input.charCodeAt(i);
28002
+ hash = Math.imul(hash, 16777619);
28003
+ }
28004
+ return (hash >>> 0).toString(16).padStart(8, "0");
28005
+ }
28006
+ function redactUrl(raw) {
28007
+ try {
28008
+ const url = new URL(raw);
28009
+ return `${url.protocol}//${url.host}`;
28010
+ } catch {
28011
+ return `url#${shortHash(raw)}`;
28012
+ }
28013
+ }
28014
+ function redactValueDetectors(value) {
28015
+ let out = value;
28016
+ out = out.replace(JWT_PATTERN, () => REDACTED);
28017
+ out = out.replace(URL_PATTERN, (match) => {
28018
+ const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
28019
+ const core2 = trailing ? match.slice(0, -trailing.length) : match;
28020
+ return `${redactUrl(core2)}${trailing}`;
28021
+ });
28022
+ out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
28023
+ out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
28024
+ out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
28025
+ out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
28026
+ if (out.length > MAX_VALUE_LENGTH) {
28027
+ out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
28028
+ }
28029
+ return out;
28030
+ }
28031
+ function redactValue(value) {
28032
+ return redactValueDetectors(value);
28033
+ }
28034
+ function redactError(error) {
28035
+ const safe = new Error(redactValueDetectors(error.message ?? ""));
28036
+ safe.name = error.name;
28037
+ safe.stack = typeof error.stack === "string" ? redactValueDetectors(error.stack) : undefined;
28038
+ return safe;
28039
+ }
28040
+ function nameTokens(name) {
28041
+ 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);
28042
+ }
28043
+ function isSensitiveName(name) {
28044
+ const tokens = nameTokens(name);
28045
+ for (let i = 0;i < tokens.length; i++) {
28046
+ const token = tokens[i];
28047
+ if (SENSITIVE_NAME_TOKENS.has(token)) {
28048
+ return true;
28049
+ }
28050
+ if (token === "key" || token === "keys") {
28051
+ const prev = tokens[i - 1];
28052
+ if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
28053
+ return true;
28054
+ }
28055
+ }
28056
+ }
28057
+ return false;
28058
+ }
28059
+ function redactProperty(name, value) {
28060
+ if (value === undefined || value === null) {
28061
+ return;
28062
+ }
28063
+ if (isSensitiveName(name)) {
28064
+ return REDACTED;
28065
+ }
28066
+ if (typeof value === "boolean" || typeof value === "number") {
28067
+ return value;
28068
+ }
28069
+ if (typeof value !== "string") {
28070
+ return "[OBJECT]";
28071
+ }
28072
+ return redactValueDetectors(value);
28073
+ }
28074
+ function redactProperties(properties) {
28075
+ const out = {};
28076
+ for (const [name, value] of Object.entries(properties)) {
28077
+ const redacted = redactProperty(name, value);
28078
+ if (redacted !== undefined) {
28079
+ out[name] = redacted;
28080
+ }
28081
+ }
28082
+ return out;
28083
+ }
28084
+
27917
28085
  // ../../common/src/telemetry/telemetry-service.ts
28086
+ var TELEMETRY_OPERATION_ID_PROPERTY = "uip.trace.operation_id";
28087
+ var TELEMETRY_PARENT_ID_PROPERTY = "uip.trace.parent_id";
28088
+ var TELEMETRY_SPAN_ID_PROPERTY = "uip.trace.span_id";
28089
+
27918
28090
  class TelemetryService {
27919
28091
  telemetryProvider;
27920
28092
  contextStorage;
@@ -27941,11 +28113,15 @@ class TelemetryService {
27941
28113
  trackException(error, properties) {
27942
28114
  const context = this.getCurrentContext();
27943
28115
  const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
27944
- this.telemetryProvider.trackException(error, enrichedProperties);
28116
+ this.telemetryProvider.trackException(redactError(error), enrichedProperties);
27945
28117
  }
27946
28118
  async trackRequest(name, fn, properties) {
28119
+ const parentContext = this.getCurrentContext();
28120
+ const operationId = parentContext?.operationId ?? this.operationId ?? getTelemetryOperationId();
28121
+ const parentId = parentContext ? parentContext.id : this.inboundParentIdFor(operationId);
27947
28122
  const context = {
27948
- operationId: this.operationId ?? this.generateId(),
28123
+ operationId,
28124
+ ...parentId !== undefined ? { parentId } : {},
27949
28125
  id: this.generateId()
27950
28126
  };
27951
28127
  const startTime = performance.now();
@@ -27963,6 +28139,45 @@ class TelemetryService {
27963
28139
  throw error;
27964
28140
  }
27965
28141
  }
28142
+ trackRequestResult(name, durationMs, success, properties, context) {
28143
+ const requestContext = context ?? {
28144
+ operationId: this.operationId ?? getTelemetryOperationId(),
28145
+ id: this.generateId()
28146
+ };
28147
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, requestContext);
28148
+ this.telemetryProvider.trackRequest(name, durationMs, success, enrichedProperties);
28149
+ }
28150
+ createRequestContext() {
28151
+ const operationId = this.operationId ?? getTelemetryOperationId();
28152
+ const parentId = this.inboundParentIdFor(operationId);
28153
+ return {
28154
+ operationId,
28155
+ ...parentId !== undefined ? { parentId } : {},
28156
+ id: this.generateId()
28157
+ };
28158
+ }
28159
+ inboundParentIdFor(operationId) {
28160
+ const inbound = getInboundTraceContext();
28161
+ return inbound && inbound.traceId === operationId ? inbound.parentSpanId : undefined;
28162
+ }
28163
+ runWithContext(context, fn) {
28164
+ return this.contextStorage.run(context, fn);
28165
+ }
28166
+ createDependencyContext() {
28167
+ const parentContext = this.getCurrentContext();
28168
+ if (!parentContext) {
28169
+ return;
28170
+ }
28171
+ return {
28172
+ operationId: parentContext.operationId,
28173
+ parentId: parentContext.id,
28174
+ id: this.generateId()
28175
+ };
28176
+ }
28177
+ trackDependencyResult(name, type2, durationMs, success, properties, context, resultCode) {
28178
+ const enrichedProperties = this.enrichPropertiesWithContext(properties, context);
28179
+ this.telemetryProvider.trackDependency(redactValue(name), type2, durationMs, success, enrichedProperties, resultCode);
28180
+ }
27966
28181
  async trackDependencyOperation(name, type2, fn, properties) {
27967
28182
  const parentContext = this.getCurrentContext();
27968
28183
  if (!parentContext) {
@@ -27999,8 +28214,12 @@ class TelemetryService {
27999
28214
  ...getExecutionContextTelemetryProperties(),
28000
28215
  ...globalProperties,
28001
28216
  ...this.defaultProperties,
28002
- ...properties,
28003
- ...context
28217
+ ...redactProperties(properties ?? {}),
28218
+ ...context ? {
28219
+ [TELEMETRY_OPERATION_ID_PROPERTY]: context.operationId,
28220
+ ...context.parentId !== undefined ? { [TELEMETRY_PARENT_ID_PROPERTY]: context.parentId } : {},
28221
+ [TELEMETRY_SPAN_ID_PROPERTY]: context.id
28222
+ } : {}
28004
28223
  };
28005
28224
  if (sessionId === undefined) {
28006
28225
  delete enriched[TELEMETRY_SESSION_ID_PROPERTY];
@@ -28010,7 +28229,16 @@ class TelemetryService {
28010
28229
  return enriched;
28011
28230
  }
28012
28231
  generateId() {
28013
- return crypto.randomUUID().replaceAll("-", "");
28232
+ const bytes = new Uint8Array(8);
28233
+ let hex = "";
28234
+ do {
28235
+ crypto.getRandomValues(bytes);
28236
+ hex = "";
28237
+ for (const byte of bytes) {
28238
+ hex += byte.toString(16).padStart(2, "0");
28239
+ }
28240
+ } while (/^0+$/.test(hex));
28241
+ return hex;
28014
28242
  }
28015
28243
  }
28016
28244
  // ../../common/src/telemetry/node-appinsights-telemetry-provider.ts
@@ -28715,134 +28943,11 @@ function buildCommandTelemetryAttribution(commandPath, skillSource) {
28715
28943
  };
28716
28944
  }
28717
28945
 
28718
- // ../../common/src/telemetry/pii-redactor.ts
28719
- var REDACTED = "[REDACTED]";
28720
- var MAX_VALUE_LENGTH = 200;
28721
- var SENSITIVE_NAME_TOKENS = new Set([
28722
- "token",
28723
- "tokens",
28724
- "secret",
28725
- "secrets",
28726
- "password",
28727
- "passwords",
28728
- "pwd",
28729
- "credential",
28730
- "credentials",
28731
- "auth",
28732
- "authentication",
28733
- "authorization",
28734
- "authority",
28735
- "cert",
28736
- "certificate",
28737
- "certificates"
28738
- ]);
28739
- var SENSITIVE_KEY_PREFIXES = new Set([
28740
- "api",
28741
- "access",
28742
- "client",
28743
- "private",
28744
- "public",
28745
- "signing",
28746
- "encryption",
28747
- "session",
28748
- "master",
28749
- "shared",
28750
- "root",
28751
- "ssh",
28752
- "rsa",
28753
- "aes",
28754
- "hmac",
28755
- "oauth"
28756
- ]);
28757
- 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;
28758
- var EMAIL_PATTERN = /\b[^\s@]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
28759
- var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
28760
- var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
28761
- var USER_HOME_PATTERN = /([/\\])(Users|home)([/\\])([^/\\]+)/gi;
28762
- var URL_PATTERN = /\bhttps?:\/\/[^\s,;]+/gi;
28763
- var URL_TRAILING_PUNCT = /[.,;:!?)\]}>'"]+$/;
28764
- function shortHash(input) {
28765
- let hash = 2166136261;
28766
- for (let i = 0;i < input.length; i++) {
28767
- hash ^= input.charCodeAt(i);
28768
- hash = Math.imul(hash, 16777619);
28769
- }
28770
- return (hash >>> 0).toString(16).padStart(8, "0");
28771
- }
28772
- function redactUrl(raw) {
28773
- try {
28774
- const url = new URL(raw);
28775
- return `${url.protocol}//${url.host}`;
28776
- } catch {
28777
- return `url#${shortHash(raw)}`;
28778
- }
28779
- }
28780
- function redactValueDetectors(value) {
28781
- let out = value;
28782
- out = out.replace(JWT_PATTERN, () => REDACTED);
28783
- out = out.replace(URL_PATTERN, (match) => {
28784
- const trailing = match.match(URL_TRAILING_PUNCT)?.[0] ?? "";
28785
- const core2 = trailing ? match.slice(0, -trailing.length) : match;
28786
- return `${redactUrl(core2)}${trailing}`;
28787
- });
28788
- out = out.replace(USER_HOME_PATTERN, (_match, sep1, folder, sep2) => `${sep1}${folder}${sep2}<user>`);
28789
- out = out.replace(EMAIL_PATTERN, (match) => `email#${shortHash(match)}`);
28790
- out = out.replace(UUID_PATTERN, (match) => `uuid#${shortHash(match)}`);
28791
- out = out.replace(LONG_TOKEN_PATTERN, () => REDACTED);
28792
- if (out.length > MAX_VALUE_LENGTH) {
28793
- out = `${out.slice(0, MAX_VALUE_LENGTH)}…`;
28794
- }
28795
- return out;
28796
- }
28797
- function nameTokens(name) {
28798
- 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);
28799
- }
28800
- function isSensitiveName(name) {
28801
- const tokens = nameTokens(name);
28802
- for (let i = 0;i < tokens.length; i++) {
28803
- const token = tokens[i];
28804
- if (SENSITIVE_NAME_TOKENS.has(token)) {
28805
- return true;
28806
- }
28807
- if (token === "key" || token === "keys") {
28808
- const prev = tokens[i - 1];
28809
- if (prev && SENSITIVE_KEY_PREFIXES.has(prev)) {
28810
- return true;
28811
- }
28812
- }
28813
- }
28814
- return false;
28815
- }
28816
- function redactProperty(name, value) {
28817
- if (value === undefined || value === null) {
28818
- return;
28819
- }
28820
- if (isSensitiveName(name)) {
28821
- return REDACTED;
28822
- }
28823
- if (typeof value === "boolean" || typeof value === "number") {
28824
- return value;
28825
- }
28826
- if (typeof value !== "string") {
28827
- return "[OBJECT]";
28828
- }
28829
- return redactValueDetectors(value);
28830
- }
28831
- function redactProperties(properties) {
28832
- const out = {};
28833
- for (const [name, value] of Object.entries(properties)) {
28834
- const redacted = redactProperty(name, value);
28835
- if (redacted !== undefined) {
28836
- out[name] = redacted;
28837
- }
28838
- }
28839
- return out;
28840
- }
28841
-
28842
28946
  // ../../common/src/trackedAction.ts
28843
28947
  var pollSignalSlot = singleton("PollSignal");
28844
28948
  var cliErrorCodeValues = new Set(CLI_ERROR_CODES);
28845
28949
  var retryHintValues = new Set(RETRY_HINTS);
28950
+ var TELEMETRY_COMMAND_ARG_PREFIX = "uip.cmd.arg.";
28846
28951
  var processContext = {
28847
28952
  exit: (code) => {
28848
28953
  process.exitCode = code;
@@ -28853,22 +28958,18 @@ var processContext = {
28853
28958
  };
28854
28959
  function extractCommandParams(cmd) {
28855
28960
  const params = {};
28961
+ const add2 = (name, value) => {
28962
+ if (name && value !== undefined) {
28963
+ params[`${TELEMETRY_COMMAND_ARG_PREFIX}${name}`] = value;
28964
+ }
28965
+ };
28856
28966
  const registered = cmd.registeredArguments ?? [];
28857
28967
  const processed = cmd.processedArgs ?? [];
28858
28968
  for (let i = 0;i < registered.length; i++) {
28859
- const value = processed[i];
28860
- if (value === undefined) {
28861
- continue;
28862
- }
28863
- const name = registered[i].name();
28864
- if (name) {
28865
- params[name] = value;
28866
- }
28969
+ add2(registered[i].name(), processed[i]);
28867
28970
  }
28868
28971
  for (const [key, value] of Object.entries(cmd.opts())) {
28869
- if (value !== undefined) {
28870
- params[key] = value;
28871
- }
28972
+ add2(key, value);
28872
28973
  }
28873
28974
  return params;
28874
28975
  }
@@ -28911,11 +29012,12 @@ Command2.prototype.trackedAction = function(context, fn, properties) {
28911
29012
  return this.action(async (...args) => {
28912
29013
  const telemetryName = deriveCommandPath(command);
28913
29014
  const props = typeof properties === "function" ? properties(...args) : properties;
29015
+ const requestContext = telemetry.createRequestContext();
28914
29016
  const startTime = performance.now();
28915
29017
  let errorMessage2;
28916
29018
  let fallbackExitCode = EXIT_CODES.Success;
28917
29019
  clearRecordedCommandFailureTelemetry();
28918
- const [error] = await catchError2(fn(...args));
29020
+ const [error] = await catchError2(telemetry.runWithContext(requestContext, () => fn(...args)));
28919
29021
  if (error) {
28920
29022
  errorMessage2 = error instanceof Error ? error.message : String(error);
28921
29023
  logger.debug(`[trackedAction] ${telemetryName} failed: ${errorMessage2}`);
@@ -28951,16 +29053,21 @@ Command2.prototype.trackedAction = function(context, fn, properties) {
28951
29053
  recordedFailure,
28952
29054
  pollSignal: context.pollSignal
28953
29055
  });
28954
- telemetry.trackEvent(telemetryName, redactProperties({
28955
- ...extractCommandParams(command),
29056
+ const commandParams = extractCommandParams(command);
29057
+ if (props) {
29058
+ for (const key of Object.keys(props)) {
29059
+ delete commandParams[`${TELEMETRY_COMMAND_ARG_PREFIX}${key}`];
29060
+ }
29061
+ }
29062
+ const baseProperties = redactProperties({
29063
+ ...commandParams,
28956
29064
  ...props,
28957
29065
  ...buildCommandTelemetryAttribution(telemetryName, process.env.UIPATH_SKILL),
28958
29066
  command: "true",
28959
- duration: String(durationMs),
28960
- success: String(success),
28961
29067
  ...terminalTelemetry,
28962
29068
  ...errorMessage2 ? { errorMessage: errorMessage2 } : {}
28963
- }));
29069
+ });
29070
+ telemetry.trackRequestResult(telemetryName, durationMs, success, baseProperties, requestContext);
28964
29071
  });
28965
29072
  };
28966
29073
  // ../../common/src/console-guard.ts
@@ -30178,4 +30285,4 @@ export {
30178
30285
  metadata
30179
30286
  };
30180
30287
 
30181
- //# debugId=008CA0C5338075BD64756E2164756E21
30288
+ //# debugId=59840D9E46999C2764756E2164756E21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uipath/apms-tool",
3
3
  "license": "MIT",
4
- "version": "1.198.0-preview.95",
4
+ "version": "1.198.0",
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": "7f6f14e06688fe417ecaac94186ab795a9106caa"
29
+ "gitHead": "1fadf03d7a8dd102742571dff569fdac11808afb"
30
30
  }