@stainlessdev/xray-core 0.5.1 → 0.6.0-branch.bg-fix-req-id-gen.e29953f

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.
@@ -109,6 +109,25 @@ function makeCapturedBody(bytes, totalBytes, truncated, mode) {
109
109
  };
110
110
  }
111
111
 
112
+ // src/uuid.ts
113
+ function uuidv7() {
114
+ const bytes = new Uint8Array(16);
115
+ crypto.getRandomValues(bytes);
116
+ const timestamp = BigInt(Date.now());
117
+ bytes[0] = Number(timestamp >> 40n & 0xffn);
118
+ bytes[1] = Number(timestamp >> 32n & 0xffn);
119
+ bytes[2] = Number(timestamp >> 24n & 0xffn);
120
+ bytes[3] = Number(timestamp >> 16n & 0xffn);
121
+ bytes[4] = Number(timestamp >> 8n & 0xffn);
122
+ bytes[5] = Number(timestamp & 0xffn);
123
+ const byte6 = bytes[6] ?? 0;
124
+ const byte8 = bytes[8] ?? 0;
125
+ bytes[6] = byte6 & 15 | 112;
126
+ bytes[8] = byte8 & 63 | 128;
127
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
128
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
129
+ }
130
+
112
131
  // src/state.ts
113
132
  var contextMap = /* @__PURE__ */ new WeakMap();
114
133
  var objectMap = /* @__PURE__ */ new WeakMap();
@@ -165,9 +184,10 @@ export {
165
184
  sanitizeLogString,
166
185
  sanitizeHeaderValues,
167
186
  makeCapturedBody,
187
+ uuidv7,
168
188
  bindContext,
169
189
  getContextState,
170
190
  bindObject,
171
191
  getContextFromObject
172
192
  };
173
- //# sourceMappingURL=chunk-XI5E6C7G.js.map
193
+ //# sourceMappingURL=chunk-HGFCHC7O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/logger.ts","../src/encoding.ts","../src/request_log.ts","../src/uuid.ts","../src/state.ts"],"sourcesContent":["import type { Logger, LogLevel } from './types';\n\nconst logLevelOrder: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\nexport function logWithLevel(\n logger: Logger,\n level: LogLevel,\n threshold: LogLevel,\n message: string,\n fields?: Record<string, unknown>,\n): void {\n if (logLevelOrder[level] < logLevelOrder[threshold]) {\n return;\n }\n\n const fn =\n logger[level] ?? logger.warn ?? logger.info ?? logger.debug ?? logger.error ?? console.log;\n\n try {\n fn.call(logger, message, fields);\n } catch {\n // Logging should never disrupt instrumentation.\n }\n}\n","const utf8Decoder =\n typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { fatal: true }) : null;\nconst utf8DecoderLenient = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8') : null;\nconst maybeBuffer = (\n globalThis as typeof globalThis & {\n Buffer?: { from(data: Uint8Array): { toString(encoding?: string): string } };\n }\n).Buffer;\n\nexport function encodeBase64(bytes: Uint8Array): string {\n if (maybeBuffer) {\n return maybeBuffer.from(bytes).toString('base64');\n }\n let binary = '';\n for (let i = 0; i < bytes.length; i += 1) {\n const byte = bytes[i];\n if (byte === undefined) {\n continue;\n }\n binary += String.fromCharCode(byte);\n }\n if (typeof btoa !== 'undefined') {\n return btoa(binary);\n }\n return '';\n}\n\nexport function isValidUtf8(bytes: Uint8Array): boolean {\n if (!utf8Decoder) {\n return false;\n }\n try {\n utf8Decoder.decode(bytes);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function decodeUtf8(bytes: Uint8Array): string {\n if (utf8DecoderLenient) {\n return utf8DecoderLenient.decode(bytes);\n }\n if (maybeBuffer) {\n return maybeBuffer.from(bytes).toString('utf8');\n }\n return '';\n}\n","import type { CapturedBody } from './types';\nimport { decodeUtf8, encodeBase64, isValidUtf8 } from './encoding';\n\n// eslint-disable-next-line no-control-regex\nconst controlChars = /[\\x00-\\x1F\\x7F]/g;\n\nexport function sanitizeLogString(value: string): string {\n if (!value) {\n return value;\n }\n return value.replace(controlChars, '');\n}\n\nexport function sanitizeHeaderValues(\n headers: Record<string, string | string[]> | undefined,\n): Record<string, string | string[]> | undefined {\n if (!headers) {\n return undefined;\n }\n\n const sanitized: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(headers)) {\n const name = sanitizeLogString(key);\n if (Array.isArray(value)) {\n sanitized[name] = value.map((entry) => sanitizeLogString(entry));\n } else {\n sanitized[name] = sanitizeLogString(value);\n }\n }\n return sanitized;\n}\n\nexport function makeCapturedBody(\n bytes: Uint8Array | undefined,\n totalBytes: number,\n truncated: boolean,\n mode: 'text' | 'base64',\n): CapturedBody | undefined {\n if (!bytes) {\n return undefined;\n }\n\n if (mode === 'base64') {\n return {\n bytes: totalBytes,\n encoding: 'base64',\n truncated,\n value: encodeBase64(bytes),\n };\n }\n\n if (isValidUtf8(bytes)) {\n return {\n bytes: totalBytes,\n encoding: 'utf8',\n truncated,\n value: decodeUtf8(bytes),\n };\n }\n\n return {\n bytes: totalBytes,\n encoding: 'base64',\n truncated,\n value: encodeBase64(bytes),\n };\n}\n","/**\n * Generates a UUIDv7 string.\n * Uses crypto.getRandomValues which is available in all modern JS runtimes\n * (browsers, Node.js 15+, Deno, Bun, Cloudflare Workers, Vercel Edge, etc.)\n */\nexport function uuidv7(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n\n // Encode timestamp in first 48 bits\n const timestamp = BigInt(Date.now());\n bytes[0] = Number((timestamp >> 40n) & 0xffn);\n bytes[1] = Number((timestamp >> 32n) & 0xffn);\n bytes[2] = Number((timestamp >> 24n) & 0xffn);\n bytes[3] = Number((timestamp >> 16n) & 0xffn);\n bytes[4] = Number((timestamp >> 8n) & 0xffn);\n bytes[5] = Number(timestamp & 0xffn);\n\n // Set version (7) and variant (RFC 4122)\n const byte6 = bytes[6] ?? 0;\n const byte8 = bytes[8] ?? 0;\n bytes[6] = (byte6 & 0x0f) | 0x70;\n bytes[8] = (byte8 & 0x3f) | 0x80;\n\n // Format as UUID string\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0'));\n return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10).join('')}`;\n}\n","import type { Span } from '@opentelemetry/api';\nimport type { AttributeValue, NormalizedRequest, XrayContext } from './types';\nimport type { CaptureConfig, RedactionConfig, ResolvedXrayConfig } from './config';\n\nexport type RequestState = {\n request: NormalizedRequest;\n config: ResolvedXrayConfig;\n span?: Span;\n context: XrayContext;\n attributes: Record<string, AttributeValue>;\n events: Array<{ name: string; attributes?: Record<string, AttributeValue> }>;\n userId?: string;\n sessionId?: string;\n error?: unknown;\n captureOverride?: Partial<CaptureConfig>;\n redactionOverride?: Partial<RedactionConfig>;\n};\n\nconst contextMap = new WeakMap<XrayContext, RequestState>();\nconst objectMap = new WeakMap<object, RequestState>();\n\nexport function bindContext(ctx: XrayContext, state: RequestState): void {\n contextMap.set(ctx, state);\n}\n\nexport function getContextState(ctx: XrayContext): RequestState | undefined {\n return contextMap.get(ctx);\n}\n\nexport function bindObject(target: object, state: RequestState): void {\n objectMap.set(target, state);\n}\n\nexport function getContextFromObject(target: unknown): XrayContext | undefined {\n const state = getStateFromObject(target);\n return state?.context;\n}\n\nexport function getStateFromObject(target: unknown): RequestState | undefined {\n if (!target || typeof target !== 'object') {\n return undefined;\n }\n if (objectMap.has(target)) {\n return objectMap.get(target);\n }\n\n const fallback = findNestedTarget(target as Record<string, unknown>);\n if (fallback && objectMap.has(fallback)) {\n return objectMap.get(fallback);\n }\n return undefined;\n}\n\nfunction findNestedTarget(obj: Record<string, unknown>): object | null {\n if (obj.raw && typeof obj.raw === 'object') {\n return obj.raw as object;\n }\n if (obj.req && typeof obj.req === 'object') {\n const req = obj.req as Record<string, unknown>;\n if (req.raw && typeof req.raw === 'object') {\n return req.raw as object;\n }\n return req as object;\n }\n if (obj.request && typeof obj.request === 'object') {\n const request = obj.request as Record<string, unknown>;\n if (request.raw && typeof request.raw === 'object') {\n return request.raw as object;\n }\n return request as object;\n }\n return null;\n}\n"],"mappings":"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","names":[]}
package/dist/index.cjs CHANGED
@@ -152,8 +152,7 @@ var defaultRedaction = {
152
152
  replacement: "[REDACTED]"
153
153
  };
154
154
  var defaultRequestId = {
155
- header: "x-request-id",
156
- generate: true
155
+ header: "request-id"
157
156
  };
158
157
  var defaultRoute = {
159
158
  normalize: true,
@@ -768,15 +767,24 @@ function setHeaderAttributes(span, headers, prefix) {
768
767
  span.setAttribute(prefix + key.toLowerCase(), Array.isArray(values) ? values : [values]);
769
768
  }
770
769
  }
771
- function setRequestAttributes(span, method, urlFull) {
772
- span.setAttribute(import_incubating.ATTR_HTTP_REQUEST_METHOD, method);
773
- if (urlFull) {
774
- span.setAttribute(import_incubating.ATTR_URL_FULL, urlFull);
775
- const path = extractPath(urlFull);
770
+ function setRequestAttributes(span, request, urlFull) {
771
+ span.setAttribute(import_incubating.ATTR_HTTP_REQUEST_METHOD, request.method);
772
+ const effectiveUrl = urlFull ?? request.url;
773
+ if (effectiveUrl) {
774
+ span.setAttribute(import_incubating.ATTR_URL_FULL, effectiveUrl);
775
+ const path = extractPath(effectiveUrl);
776
776
  if (path) {
777
777
  span.setAttribute(import_incubating.ATTR_URL_PATH, path);
778
778
  }
779
779
  }
780
+ const clientAddress = clientAddressForRequest(
781
+ request.headers,
782
+ request.remoteAddress,
783
+ request.redactionReplacement
784
+ );
785
+ if (clientAddress) {
786
+ span.setAttribute(import_incubating.ATTR_CLIENT_ADDRESS, clientAddress);
787
+ }
780
788
  }
781
789
  function extractPath(url) {
782
790
  try {
@@ -786,6 +794,144 @@ function extractPath(url) {
786
794
  return match?.[0] || void 0;
787
795
  }
788
796
  }
797
+ function clientAddressForRequest(headers, remoteAddress, redactionReplacement) {
798
+ const forwarded = forwardedClientAddress(
799
+ headerValues(headers, "forwarded"),
800
+ redactionReplacement
801
+ );
802
+ if (forwarded) {
803
+ return forwarded;
804
+ }
805
+ const xForwarded = xForwardedForClientAddress(
806
+ headerValues(headers, "x-forwarded-for"),
807
+ redactionReplacement
808
+ );
809
+ if (xForwarded) {
810
+ return xForwarded;
811
+ }
812
+ const xRealIp = xRealIpClientAddress(headerValues(headers, "x-real-ip"), redactionReplacement);
813
+ if (xRealIp) {
814
+ return xRealIp;
815
+ }
816
+ if (!remoteAddress) {
817
+ return void 0;
818
+ }
819
+ return remoteAddrHost(remoteAddress);
820
+ }
821
+ function forwardedClientAddress(values, redactionReplacement) {
822
+ for (const value of values) {
823
+ if (!value) {
824
+ continue;
825
+ }
826
+ const entries = value.split(",");
827
+ for (const entry of entries) {
828
+ const params = entry.split(";");
829
+ for (const param of params) {
830
+ const [rawKey, ...rest] = param.split("=");
831
+ if (!rawKey) {
832
+ continue;
833
+ }
834
+ if (rawKey.trim().toLowerCase() !== "for") {
835
+ continue;
836
+ }
837
+ const rawValue = rest.join("=").trim();
838
+ const normalized = normalizeKnownAddress(rawValue, redactionReplacement);
839
+ if (normalized) {
840
+ return normalized;
841
+ }
842
+ }
843
+ }
844
+ }
845
+ return void 0;
846
+ }
847
+ function xForwardedForClientAddress(values, redactionReplacement) {
848
+ for (const value of values) {
849
+ if (!value) {
850
+ continue;
851
+ }
852
+ const entries = value.split(",");
853
+ for (const entry of entries) {
854
+ const normalized = normalizeKnownAddress(entry, redactionReplacement);
855
+ if (normalized) {
856
+ return normalized;
857
+ }
858
+ }
859
+ }
860
+ return void 0;
861
+ }
862
+ function xRealIpClientAddress(values, redactionReplacement) {
863
+ for (const value of values) {
864
+ if (!value) {
865
+ continue;
866
+ }
867
+ const normalized = normalizeKnownAddress(value, redactionReplacement);
868
+ if (normalized) {
869
+ return normalized;
870
+ }
871
+ }
872
+ return void 0;
873
+ }
874
+ function normalizeKnownAddress(value, redactionReplacement) {
875
+ const normalized = normalizeAddress(value, redactionReplacement);
876
+ if (!normalized) {
877
+ return void 0;
878
+ }
879
+ if (normalized.toLowerCase() === "unknown") {
880
+ return void 0;
881
+ }
882
+ return normalized;
883
+ }
884
+ function normalizeAddress(value, redactionReplacement) {
885
+ if (!value) {
886
+ return void 0;
887
+ }
888
+ let trimmed = value.trim();
889
+ if (!trimmed) {
890
+ return void 0;
891
+ }
892
+ if (redactionReplacement && trimmed === redactionReplacement) {
893
+ return void 0;
894
+ }
895
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') && trimmed.length > 1) {
896
+ trimmed = trimmed.slice(1, -1).trim();
897
+ }
898
+ if (!trimmed) {
899
+ return void 0;
900
+ }
901
+ if (trimmed.startsWith("[")) {
902
+ const end = trimmed.indexOf("]");
903
+ if (end !== -1) {
904
+ return trimmed.slice(1, end);
905
+ }
906
+ }
907
+ const colonCount = (trimmed.match(/:/g) ?? []).length;
908
+ if (colonCount === 1) {
909
+ const host = trimmed.split(":")[0];
910
+ return host || void 0;
911
+ }
912
+ return trimmed;
913
+ }
914
+ function remoteAddrHost(value) {
915
+ return normalizeAddress(value);
916
+ }
917
+ function headerValues(headers, name) {
918
+ if (!headers) {
919
+ return [];
920
+ }
921
+ const target = name.toLowerCase();
922
+ const values = [];
923
+ for (const [key, value] of Object.entries(headers)) {
924
+ if (key.toLowerCase() !== target) {
925
+ continue;
926
+ }
927
+ if (Array.isArray(value)) {
928
+ values.push(...value);
929
+ } else {
930
+ values.push(value);
931
+ }
932
+ }
933
+ return values;
934
+ }
789
935
  function setRequestBodyAttributes(span, body) {
790
936
  if (!body.value) {
791
937
  return;
@@ -915,7 +1061,7 @@ function createSpanProcessor(mode, exporter) {
915
1061
  }
916
1062
  function sdkVersion() {
917
1063
  if (true) {
918
- return "0.5.0";
1064
+ return "0.6.0";
919
1065
  }
920
1066
  return "unknown";
921
1067
  }
@@ -981,14 +1127,14 @@ function createEmitter(config, exporter) {
981
1127
  function startRequest(config, tracer, req) {
982
1128
  const startTimeMs = Number.isFinite(req.startTimeMs) ? req.startTimeMs : Date.now();
983
1129
  req.startTimeMs = startTimeMs;
984
- const requestId = resolveRequestId(config, req.requestId, req.headers);
985
- req.requestId = requestId;
1130
+ const explicitRequestId = normalizeRequestIdCandidate(req.requestId);
1131
+ req.requestId = explicitRequestId;
986
1132
  if (req.route && config.route.normalize) {
987
1133
  req.route = config.route.normalizer ? config.route.normalizer(req.route) : normalizeRoutePattern(req.route);
988
1134
  }
989
1135
  const span = spanFromTracer(tracer, spanNameFromRequest(req));
990
1136
  const context = {
991
- requestId,
1137
+ requestId: explicitRequestId ?? "",
992
1138
  traceId: span?.spanContext().traceId,
993
1139
  spanId: span?.spanContext().spanId,
994
1140
  setUserId: (id) => {
@@ -1067,8 +1213,10 @@ function endRequest(config, ctx, res, err) {
1067
1213
  const endTimeMs = Number.isFinite(res.endTimeMs) ? res.endTimeMs : Date.now();
1068
1214
  res.endTimeMs = endTimeMs;
1069
1215
  if (!state) {
1216
+ const resolvedRequestId2 = resolveFinalRequestId(config, ctx.requestId, res.headers);
1217
+ ctx.requestId = resolvedRequestId2;
1070
1218
  const fallbackLog = {
1071
- requestId: ctx.requestId,
1219
+ requestId: resolvedRequestId2,
1072
1220
  serviceName: config.serviceName,
1073
1221
  method: res.statusCode ? "UNKNOWN" : "UNKNOWN",
1074
1222
  url: "",
@@ -1079,12 +1227,19 @@ function endRequest(config, ctx, res, err) {
1079
1227
  return fallbackLog;
1080
1228
  }
1081
1229
  const request = state.request;
1230
+ const resolvedRequestId = resolveFinalRequestId(
1231
+ config,
1232
+ request.requestId || ctx.requestId,
1233
+ res.headers
1234
+ );
1235
+ request.requestId = resolvedRequestId;
1236
+ ctx.requestId = resolvedRequestId;
1082
1237
  const capture = resolveCapture(config.capture, state.captureOverride);
1083
1238
  const redaction = resolveRedaction(config.redaction, state.redactionOverride);
1084
1239
  const route = request.route;
1085
1240
  const url = sanitizeLogString(request.url);
1086
1241
  const log = {
1087
- requestId: request.requestId ?? ctx.requestId,
1242
+ requestId: resolvedRequestId,
1088
1243
  traceId: state.span?.spanContext().traceId,
1089
1244
  spanId: state.span?.spanContext().spanId,
1090
1245
  serviceName: config.serviceName,
@@ -1111,7 +1266,16 @@ function endRequest(config, ctx, res, err) {
1111
1266
  const span = state.span;
1112
1267
  if (span) {
1113
1268
  try {
1114
- setRequestAttributes(span, request.method, redacted.url);
1269
+ const clientAddressHeaders = redactHeaders(request.headers, redaction);
1270
+ setRequestAttributes(
1271
+ span,
1272
+ {
1273
+ ...request,
1274
+ headers: clientAddressHeaders,
1275
+ redactionReplacement: redaction.replacement
1276
+ },
1277
+ redacted.url
1278
+ );
1115
1279
  setRequestIdAttribute(span, redacted.requestId);
1116
1280
  span.setAttribute("service.name", config.serviceName);
1117
1281
  if (redacted.statusCode != null) {
@@ -1152,22 +1316,40 @@ function endRequest(config, ctx, res, err) {
1152
1316
  }
1153
1317
  return redacted;
1154
1318
  }
1155
- function resolveRequestId(config, requestId, headers) {
1156
- if (requestId) {
1157
- return requestId;
1319
+ function resolveFinalRequestId(config, explicitRequestId, responseHeaders) {
1320
+ const explicit = normalizeRequestIdCandidate(explicitRequestId);
1321
+ if (explicit) {
1322
+ return explicit;
1158
1323
  }
1159
- const headerName = config.requestId.header.toLowerCase();
1160
- const headerValue = headers[headerName];
1324
+ const headerValue = resolveHeaderRequestId(config.requestId.header, responseHeaders);
1161
1325
  if (headerValue) {
1162
- const value = Array.isArray(headerValue) ? headerValue[0] : headerValue;
1163
- if (value && value.trim()) {
1164
- return value.trim();
1326
+ return headerValue;
1327
+ }
1328
+ return uuidv7();
1329
+ }
1330
+ function resolveHeaderRequestId(headerName, headers) {
1331
+ if (!headers) {
1332
+ return void 0;
1333
+ }
1334
+ const target = headerName.toLowerCase();
1335
+ for (const [name, value] of Object.entries(headers)) {
1336
+ if (name.toLowerCase() !== target) {
1337
+ continue;
1338
+ }
1339
+ const entry = Array.isArray(value) ? value[0] : value;
1340
+ const normalized = normalizeRequestIdCandidate(entry);
1341
+ if (normalized) {
1342
+ return normalized;
1165
1343
  }
1166
1344
  }
1167
- if (!config.requestId.generate) {
1168
- return uuidv7();
1345
+ return void 0;
1346
+ }
1347
+ function normalizeRequestIdCandidate(value) {
1348
+ if (!value) {
1349
+ return void 0;
1169
1350
  }
1170
- return uuidv7();
1351
+ const trimmed = value.trim();
1352
+ return trimmed ? trimmed : void 0;
1171
1353
  }
1172
1354
  function resolveCapture(base, override) {
1173
1355
  if (!override) {