@stainlessdev/xray-core 0.1.0 → 0.2.0-branch.bg-basic-auth.4c8723c

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.
@@ -37,6 +37,18 @@ function encodeBase64(bytes) {
37
37
  }
38
38
  return "";
39
39
  }
40
+ function encodeBase64String(value) {
41
+ if (maybeBuffer) {
42
+ return maybeBuffer.from(value, "utf8").toString("base64");
43
+ }
44
+ if (typeof TextEncoder !== "undefined") {
45
+ return encodeBase64(new TextEncoder().encode(value));
46
+ }
47
+ if (typeof btoa !== "undefined") {
48
+ return btoa(unescape(encodeURIComponent(value)));
49
+ }
50
+ return "";
51
+ }
40
52
  function isValidUtf8(bytes) {
41
53
  if (!utf8Decoder) {
42
54
  return false;
@@ -160,6 +172,7 @@ function findNestedTarget(obj) {
160
172
  }
161
173
 
162
174
  export {
175
+ encodeBase64String,
163
176
  logWithLevel,
164
177
  sanitizeLogString,
165
178
  sanitizeHeaderValues,
@@ -169,4 +182,4 @@ export {
169
182
  bindObject,
170
183
  getContextFromObject
171
184
  };
172
- //# sourceMappingURL=chunk-SQHI5JZH.js.map
185
+ //# sourceMappingURL=chunk-HTZYZB7O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/logger.ts","../src/encoding.ts","../src/request_log.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?: {\n from(\n data: Uint8Array | string,\n encoding?: string,\n ): {\n toString(encoding?: string): string;\n };\n };\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 encodeBase64String(value: string): string {\n if (maybeBuffer) {\n return maybeBuffer.from(value, 'utf8').toString('base64');\n }\n if (typeof TextEncoder !== 'undefined') {\n return encodeBase64(new TextEncoder().encode(value));\n }\n if (typeof btoa !== 'undefined') {\n return btoa(unescape(encodeURIComponent(value)));\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","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
@@ -26,6 +26,40 @@ __export(index_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(index_exports);
28
28
 
29
+ // src/encoding.ts
30
+ var utf8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8", { fatal: true }) : null;
31
+ var utf8DecoderLenient = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8") : null;
32
+ var maybeBuffer = globalThis.Buffer;
33
+ function encodeBase64(bytes) {
34
+ if (maybeBuffer) {
35
+ return maybeBuffer.from(bytes).toString("base64");
36
+ }
37
+ let binary = "";
38
+ for (let i = 0; i < bytes.length; i += 1) {
39
+ const byte = bytes[i];
40
+ if (byte === void 0) {
41
+ continue;
42
+ }
43
+ binary += String.fromCharCode(byte);
44
+ }
45
+ if (typeof btoa !== "undefined") {
46
+ return btoa(binary);
47
+ }
48
+ return "";
49
+ }
50
+ function encodeBase64String(value) {
51
+ if (maybeBuffer) {
52
+ return maybeBuffer.from(value, "utf8").toString("base64");
53
+ }
54
+ if (typeof TextEncoder !== "undefined") {
55
+ return encodeBase64(new TextEncoder().encode(value));
56
+ }
57
+ if (typeof btoa !== "undefined") {
58
+ return btoa(unescape(encodeURIComponent(value)));
59
+ }
60
+ return "";
61
+ }
62
+
29
63
  // src/route.ts
30
64
  function normalizeRoutePattern(route) {
31
65
  if (!route) {
@@ -35,7 +69,8 @@ function normalizeRoutePattern(route) {
35
69
  if (!cleaned) {
36
70
  return "/";
37
71
  }
38
- const leading = cleaned.startsWith("/") ? cleaned : `/${cleaned}`;
72
+ const withoutMethod = stripMethodPrefix(cleaned);
73
+ const leading = withoutMethod.startsWith("/") ? withoutMethod : `/${withoutMethod}`;
39
74
  const segments = leading.split("/").filter(Boolean);
40
75
  if (segments.length === 0) {
41
76
  return "/";
@@ -43,6 +78,16 @@ function normalizeRoutePattern(route) {
43
78
  const normalized = segments.map(normalizeRouteSegment).join("/");
44
79
  return `/${normalized}`;
45
80
  }
81
+ function stripMethodPrefix(value) {
82
+ if (!/^[A-Z]+\s+\//.test(value)) {
83
+ return value;
84
+ }
85
+ const spaceIndex = value.search(/\s+/);
86
+ if (spaceIndex < 0) {
87
+ return value;
88
+ }
89
+ return value.slice(spaceIndex).trim();
90
+ }
46
91
  function stripQueryAndFragment(value) {
47
92
  const hashIndex = value.indexOf("#");
48
93
  const beforeHash = hashIndex >= 0 ? value.slice(0, hashIndex) : value;
@@ -51,25 +96,57 @@ function stripQueryAndFragment(value) {
51
96
  }
52
97
  function normalizeRouteSegment(segment) {
53
98
  if (segment === "*") {
54
- return "*";
99
+ return "{wildcard}";
100
+ }
101
+ const param = extractRouteParam(segment);
102
+ if (param) {
103
+ return `{${param}}`;
104
+ }
105
+ return segment;
106
+ }
107
+ function extractRouteParam(segment) {
108
+ if (!segment) {
109
+ return null;
55
110
  }
56
111
  if (segment.startsWith("[") && segment.endsWith("]")) {
57
- const inner = segment.slice(1, -1);
58
- if (inner.startsWith("...") || inner.startsWith("[...")) {
59
- return "*";
60
- }
61
- return `:${inner}`;
112
+ return normalizeNextParam(segment);
62
113
  }
63
114
  if (segment.startsWith("{") && segment.endsWith("}")) {
64
- return `:${segment.slice(1, -1)}`;
115
+ const inner = segment.slice(1, -1);
116
+ const trimmed = stripParamDecorators(inner);
117
+ return extractParamName(trimmed);
65
118
  }
66
- if (segment.startsWith("$")) {
67
- return `:${segment.slice(1)}`;
119
+ if (segment.startsWith(":") || segment.startsWith("$")) {
120
+ return extractParamName(segment.slice(1));
68
121
  }
69
- if (segment.startsWith(":")) {
70
- return `:${segment.slice(1)}`;
122
+ return null;
123
+ }
124
+ function normalizeNextParam(segment) {
125
+ let inner = segment.slice(1, -1);
126
+ if (inner.startsWith("[") && inner.endsWith("]")) {
127
+ inner = inner.slice(1, -1);
71
128
  }
72
- return segment;
129
+ if (inner.startsWith("...")) {
130
+ inner = inner.slice(3);
131
+ }
132
+ return extractParamName(inner);
133
+ }
134
+ function stripParamDecorators(value) {
135
+ let trimmed = value.trim();
136
+ if (!trimmed) {
137
+ return trimmed;
138
+ }
139
+ if (trimmed.endsWith("...")) {
140
+ trimmed = trimmed.slice(0, -3);
141
+ }
142
+ return trimmed.replace(/[?*+]+$/, "");
143
+ }
144
+ function extractParamName(value) {
145
+ if (!value) {
146
+ return null;
147
+ }
148
+ const match = value.match(/^[A-Za-z0-9_-]+/);
149
+ return match?.[0] ?? null;
73
150
  }
74
151
 
75
152
  // src/config.ts
@@ -95,9 +172,10 @@ var defaultRoute = {
95
172
  normalizer: normalizeRoutePattern
96
173
  };
97
174
  var DEFAULT_ENDPOINT_URL = "http://localhost:4318";
175
+ var defaultExporterHeaders = {};
98
176
  var defaultExporterBase = {
99
177
  endpointUrl: DEFAULT_ENDPOINT_URL,
100
- headers: {},
178
+ headers: defaultExporterHeaders,
101
179
  timeoutMs: 5e3,
102
180
  spanProcessor: "batch",
103
181
  sampler: { type: "ratio", ratio: 1 }
@@ -190,14 +268,15 @@ function normalizeRoute(cfg) {
190
268
  return route;
191
269
  }
192
270
  function normalizeExporter(endpointUrl, cfg) {
193
- const resolvedEndpoint = normalizeExporterEndpoint(cfg?.endpointUrl ?? endpointUrl);
271
+ const resolved = normalizeExporterEndpoint(cfg?.endpointUrl ?? endpointUrl);
194
272
  const enabled = cfg?.enabled ?? true;
273
+ const headers = normalizeExporterHeaders(cfg?.headers, resolved.authHeader);
195
274
  const exporter = {
196
275
  ...defaultExporterBase,
197
276
  ...cfg,
198
277
  enabled,
199
- endpointUrl: resolvedEndpoint,
200
- headers: cfg?.headers ?? defaultExporterBase.headers,
278
+ endpointUrl: resolved.endpointUrl,
279
+ headers,
201
280
  timeoutMs: cfg?.timeoutMs ?? defaultExporterBase.timeoutMs,
202
281
  spanProcessor: cfg?.spanProcessor ?? defaultExporterBase.spanProcessor,
203
282
  sampler: cfg?.sampler ?? defaultExporterBase.sampler
@@ -212,14 +291,12 @@ function normalizeExporter(endpointUrl, cfg) {
212
291
  return exporter;
213
292
  }
214
293
  function normalizeExporterEndpoint(endpointUrl) {
215
- const envUrl = typeof process !== "undefined" ? process.env?.["STAINLESS_ENDPOINT_URL"] : void 0;
294
+ const envUrl = typeof process !== "undefined" ? process.env?.["STAINLESS_XRAY_ENDPOINT_URL"] : void 0;
216
295
  const resolved = endpointUrl ?? envUrl ?? DEFAULT_ENDPOINT_URL;
217
296
  const trimmed = resolved.trim();
218
297
  const withoutTrailingSlash = trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
219
- if (withoutTrailingSlash.endsWith("/v1/traces")) {
220
- return withoutTrailingSlash;
221
- }
222
- return `${withoutTrailingSlash}/v1/traces`;
298
+ const withTraces = withoutTrailingSlash.endsWith("/v1/traces") ? withoutTrailingSlash : `${withoutTrailingSlash}/v1/traces`;
299
+ return extractBasicAuth(withTraces);
223
300
  }
224
301
  function normalizeStringList(values) {
225
302
  if (!values) {
@@ -227,6 +304,42 @@ function normalizeStringList(values) {
227
304
  }
228
305
  return values.map((entry) => entry.trim()).filter(Boolean);
229
306
  }
307
+ function normalizeExporterHeaders(headers, authHeader) {
308
+ const resolved = headers ?? defaultExporterHeaders;
309
+ if (!authHeader) {
310
+ return resolved;
311
+ }
312
+ const existingKey = findHeaderKey(resolved, "authorization");
313
+ if (existingKey) {
314
+ const value = resolved[existingKey];
315
+ if (value && value.trim()) {
316
+ return resolved;
317
+ }
318
+ return { ...resolved, [existingKey]: authHeader };
319
+ }
320
+ return { ...resolved, Authorization: authHeader };
321
+ }
322
+ function extractBasicAuth(endpointUrl) {
323
+ try {
324
+ const url = new URL(endpointUrl);
325
+ if (!url.username && !url.password) {
326
+ return { endpointUrl };
327
+ }
328
+ const username = url.username;
329
+ const password = url.password;
330
+ url.username = "";
331
+ url.password = "";
332
+ const credentials = `${username}:${password}`;
333
+ const authHeader = `Basic ${encodeBase64String(credentials)}`;
334
+ return { endpointUrl: url.toString(), authHeader };
335
+ } catch {
336
+ return { endpointUrl };
337
+ }
338
+ }
339
+ function findHeaderKey(headers, name) {
340
+ const target = name.toLowerCase();
341
+ return Object.keys(headers).find((key) => key.toLowerCase() === target);
342
+ }
230
343
 
231
344
  // src/logger.ts
232
345
  var logLevelOrder = {
@@ -596,11 +709,6 @@ function redactJsonPath(value, segments, replacement) {
596
709
  }
597
710
  }
598
711
 
599
- // src/encoding.ts
600
- var utf8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8", { fatal: true }) : null;
601
- var utf8DecoderLenient = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8") : null;
602
- var maybeBuffer = globalThis.Buffer;
603
-
604
712
  // src/request_log.ts
605
713
  var controlChars = /[\x00-\x1F\x7F]/g;
606
714
  function sanitizeLogString(value) {
@@ -888,7 +996,7 @@ function createSampler(config) {
888
996
  }
889
997
  function sdkVersion() {
890
998
  if (true) {
891
- return "0.1.0";
999
+ return "0.2.0";
892
1000
  }
893
1001
  return "unknown";
894
1002
  }
@@ -1064,6 +1172,10 @@ function endRequest(config, ctx, res, err) {
1064
1172
  timestamp: new Date(endTimeMs).toISOString()
1065
1173
  };
1066
1174
  const redacted = applyRedaction(redaction, log);
1175
+ if (redacted.route && config.route.normalize) {
1176
+ const normalized = config.route.normalizer ? config.route.normalizer(redacted.route) : normalizeRoutePattern(redacted.route);
1177
+ redacted.route = normalized;
1178
+ }
1067
1179
  const span = state.span;
1068
1180
  if (span) {
1069
1181
  try {
@@ -1074,9 +1186,8 @@ function endRequest(config, ctx, res, err) {
1074
1186
  setResponseStatusAttribute(span, redacted.statusCode);
1075
1187
  }
1076
1188
  if (redacted.route) {
1077
- const normalized = config.route.normalize ? config.route.normalizer ? config.route.normalizer(redacted.route) : normalizeRoutePattern(redacted.route) : redacted.route;
1078
- setRouteAttribute(span, normalized);
1079
- span.updateName(`${request.method} ${normalized}`);
1189
+ setRouteAttribute(span, redacted.route);
1190
+ span.updateName(`${request.method} ${redacted.route}`);
1080
1191
  } else {
1081
1192
  span.updateName(spanNameFromRequest(request));
1082
1193
  }