@stainlessdev/xray-emitter 0.3.1-dev.2076868 → 0.3.1-dev.253ef91

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 (41) hide show
  1. package/dist/{chunk-DV3MVQBB.js → chunk-2U5UHEQ6.js} +2 -2
  2. package/dist/{chunk-FGXXKIF7.js → chunk-AB2LRSJ4.js} +2 -2
  3. package/dist/{chunk-SUVCVINA.cjs → chunk-DLNU4YMG.cjs} +4 -4
  4. package/dist/{chunk-SUVCVINA.cjs.map → chunk-DLNU4YMG.cjs.map} +1 -1
  5. package/dist/{chunk-UJWD5CFA.cjs → chunk-E2ZM6DIT.cjs} +26 -9
  6. package/dist/chunk-E2ZM6DIT.cjs.map +1 -0
  7. package/dist/{chunk-55YD27PV.cjs → chunk-N2MJE6CJ.cjs} +4 -4
  8. package/dist/{chunk-55YD27PV.cjs.map → chunk-N2MJE6CJ.cjs.map} +1 -1
  9. package/dist/{chunk-GYXI3DWB.js → chunk-T5GUIVFZ.js} +19 -2
  10. package/dist/chunk-T5GUIVFZ.js.map +1 -0
  11. package/dist/effect.cjs +4 -4
  12. package/dist/effect.js +2 -2
  13. package/dist/express.cjs +5 -5
  14. package/dist/express.js +2 -2
  15. package/dist/fastify.cjs +7 -7
  16. package/dist/fastify.js +2 -2
  17. package/dist/fetch.cjs +3 -3
  18. package/dist/fetch.js +2 -2
  19. package/dist/hono.cjs +6 -6
  20. package/dist/hono.js +2 -2
  21. package/dist/index.cjs +2 -2
  22. package/dist/index.js +1 -1
  23. package/dist/next.cjs +40 -6
  24. package/dist/next.cjs.map +1 -1
  25. package/dist/next.js +37 -3
  26. package/dist/next.js.map +1 -1
  27. package/dist/node.cjs +3 -3
  28. package/dist/node.js +2 -2
  29. package/dist/remix.cjs +5 -5
  30. package/dist/remix.js +2 -2
  31. package/dist/stub.cjs +121 -0
  32. package/dist/stub.cjs.map +1 -0
  33. package/dist/stub.d.cts +12 -0
  34. package/dist/stub.d.ts +12 -0
  35. package/dist/stub.js +121 -0
  36. package/dist/stub.js.map +1 -0
  37. package/package.json +10 -3
  38. package/dist/chunk-GYXI3DWB.js.map +0 -1
  39. package/dist/chunk-UJWD5CFA.cjs.map +0 -1
  40. /package/dist/{chunk-DV3MVQBB.js.map → chunk-2U5UHEQ6.js.map} +0 -0
  41. /package/dist/{chunk-FGXXKIF7.js.map → chunk-AB2LRSJ4.js.map} +0 -0
package/dist/fetch.cjs CHANGED
@@ -3,8 +3,8 @@
3
3
 
4
4
 
5
5
 
6
- var _chunkSUVCVINAcjs = require('./chunk-SUVCVINA.cjs');
7
- require('./chunk-UJWD5CFA.cjs');
6
+ var _chunkDLNU4YMGcjs = require('./chunk-DLNU4YMG.cjs');
7
+ require('./chunk-E2ZM6DIT.cjs');
8
8
  require('./chunk-CPHFCOA5.cjs');
9
9
  require('./chunk-DNBARLGB.cjs');
10
10
 
@@ -12,5 +12,5 @@ require('./chunk-DNBARLGB.cjs');
12
12
 
13
13
 
14
14
 
15
- exports.createEmitter = _chunkSUVCVINAcjs.createEmitter; exports.getXrayContext = _chunkSUVCVINAcjs.getXrayContext; exports.wrapFetch = _chunkSUVCVINAcjs.wrapFetch; exports.wrapFetchPreserve = _chunkSUVCVINAcjs.wrapFetchPreserve;
15
+ exports.createEmitter = _chunkDLNU4YMGcjs.createEmitter; exports.getXrayContext = _chunkDLNU4YMGcjs.getXrayContext; exports.wrapFetch = _chunkDLNU4YMGcjs.wrapFetch; exports.wrapFetchPreserve = _chunkDLNU4YMGcjs.wrapFetchPreserve;
16
16
  //# sourceMappingURL=fetch.cjs.map
package/dist/fetch.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  getXrayContext,
4
4
  wrapFetch,
5
5
  wrapFetchPreserve
6
- } from "./chunk-DV3MVQBB.js";
7
- import "./chunk-GYXI3DWB.js";
6
+ } from "./chunk-2U5UHEQ6.js";
7
+ import "./chunk-T5GUIVFZ.js";
8
8
  import "./chunk-NTIUR3OC.js";
9
9
  import "./chunk-7KT6EPVZ.js";
10
10
  export {
package/dist/hono.cjs CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkSUVCVINAcjs = require('./chunk-SUVCVINA.cjs');
6
- require('./chunk-UJWD5CFA.cjs');
5
+ var _chunkDLNU4YMGcjs = require('./chunk-DLNU4YMG.cjs');
6
+ require('./chunk-E2ZM6DIT.cjs');
7
7
 
8
8
 
9
9
  var _chunkCPHFCOA5cjs = require('./chunk-CPHFCOA5.cjs');
@@ -11,7 +11,7 @@ require('./chunk-DNBARLGB.cjs');
11
11
 
12
12
  // src/hono/hono.ts
13
13
  function createEmitter2(config, options) {
14
- const emitter = _chunkSUVCVINAcjs.createEmitter.call(void 0, config);
14
+ const emitter = _chunkDLNU4YMGcjs.createEmitter.call(void 0, config);
15
15
  const middleware = createHonoMiddleware(emitter, options);
16
16
  middleware.flush = emitter.flush;
17
17
  middleware.shutdown = emitter.shutdown;
@@ -25,9 +25,9 @@ function createHonoMiddleware(xray, options) {
25
25
  await next();
26
26
  return;
27
27
  }
28
- const wrapped = _chunkSUVCVINAcjs.wrapFetchPreserve.call(void 0,
28
+ const wrapped = _chunkDLNU4YMGcjs.wrapFetchPreserve.call(void 0,
29
29
  async (req) => {
30
- const ctx = _chunkSUVCVINAcjs.getXrayContext.call(void 0, req);
30
+ const ctx = _chunkDLNU4YMGcjs.getXrayContext.call(void 0, req);
31
31
  if (ctx) {
32
32
  c.set("xray", ctx);
33
33
  }
@@ -67,5 +67,5 @@ function resolveRoutePath(fn, ctx, index) {
67
67
 
68
68
 
69
69
 
70
- exports.createCoreEmitter = _chunkSUVCVINAcjs.createEmitter; exports.createEmitter = createEmitter2; exports.createHonoMiddleware = createHonoMiddleware;
70
+ exports.createCoreEmitter = _chunkDLNU4YMGcjs.createEmitter; exports.createEmitter = createEmitter2; exports.createHonoMiddleware = createHonoMiddleware;
71
71
  //# sourceMappingURL=hono.cjs.map
package/dist/hono.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  createEmitter,
3
3
  getXrayContext,
4
4
  wrapFetchPreserve
5
- } from "./chunk-DV3MVQBB.js";
6
- import "./chunk-GYXI3DWB.js";
5
+ } from "./chunk-2U5UHEQ6.js";
6
+ import "./chunk-T5GUIVFZ.js";
7
7
  import {
8
8
  setContextRoute
9
9
  } from "./chunk-NTIUR3OC.js";
package/dist/index.cjs CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkUJWD5CFAcjs = require('./chunk-UJWD5CFA.cjs');
5
+ var _chunkE2ZM6DITcjs = require('./chunk-E2ZM6DIT.cjs');
6
6
  require('./chunk-DNBARLGB.cjs');
7
7
 
8
8
 
9
9
 
10
10
 
11
- exports.XrayConfigError = _chunkUJWD5CFAcjs.XrayConfigError; exports.createEmitter = _chunkUJWD5CFAcjs.createEmitter; exports.normalizeConfig = _chunkUJWD5CFAcjs.normalizeConfig;
11
+ exports.XrayConfigError = _chunkE2ZM6DITcjs.XrayConfigError; exports.createEmitter = _chunkE2ZM6DITcjs.createEmitter; exports.normalizeConfig = _chunkE2ZM6DITcjs.normalizeConfig;
12
12
  //# sourceMappingURL=index.cjs.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  XrayConfigError,
3
3
  createEmitter,
4
4
  normalizeConfig
5
- } from "./chunk-GYXI3DWB.js";
5
+ } from "./chunk-T5GUIVFZ.js";
6
6
  import "./chunk-7KT6EPVZ.js";
7
7
  export {
8
8
  XrayConfigError,
package/dist/next.cjs CHANGED
@@ -1,15 +1,15 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
4
 
5
- var _chunkSUVCVINAcjs = require('./chunk-SUVCVINA.cjs');
6
- require('./chunk-UJWD5CFA.cjs');
5
+ var _chunkDLNU4YMGcjs = require('./chunk-DLNU4YMG.cjs');
6
+ require('./chunk-E2ZM6DIT.cjs');
7
7
  require('./chunk-CPHFCOA5.cjs');
8
8
  require('./chunk-DNBARLGB.cjs');
9
9
 
10
10
  // src/next/next.ts
11
11
  function createEmitter2(config, options) {
12
- const emitter = _chunkSUVCVINAcjs.createEmitter.call(void 0, config);
12
+ const emitter = _chunkDLNU4YMGcjs.createEmitter.call(void 0, config);
13
13
  const wrap = ((handler) => wrapNextRoute(handler, emitter, options));
14
14
  wrap.flush = emitter.flush;
15
15
  wrap.shutdown = emitter.shutdown;
@@ -17,14 +17,48 @@ function createEmitter2(config, options) {
17
17
  }
18
18
  function wrapNextRoute(handler, xray, options) {
19
19
  return async (request, context) => {
20
- const wrapped = _chunkSUVCVINAcjs.wrapFetchPreserve.call(void 0, (req) => handler(req, context), xray, options);
20
+ let effectiveOptions = options;
21
+ if (!_optionalChain([options, 'optionalAccess', _ => _.route])) {
22
+ const params = await context.params;
23
+ const route = inferRoute(new URL(request.url).pathname, params);
24
+ if (route) {
25
+ effectiveOptions = { ...options, route };
26
+ }
27
+ }
28
+ const wrapped = _chunkDLNU4YMGcjs.wrapFetchPreserve.call(void 0,
29
+ (req) => handler(req, context),
30
+ xray,
31
+ effectiveOptions
32
+ );
21
33
  return wrapped(request);
22
34
  };
23
35
  }
36
+ function inferRoute(pathname, params) {
37
+ const replacements = /* @__PURE__ */ new Map();
38
+ for (const [key, value] of Object.entries(params)) {
39
+ if (typeof value === "string") {
40
+ replacements.set(value, `[${key}]`);
41
+ }
42
+ }
43
+ if (replacements.size === 0) return void 0;
44
+ const segments = pathname.split("/");
45
+ let replaced = false;
46
+ for (let i = 0; i < segments.length; i++) {
47
+ const seg = segments[i];
48
+ const placeholder = replacements.get(seg);
49
+ if (placeholder) {
50
+ if (segments.indexOf(seg, i + 1) !== -1) return void 0;
51
+ segments[i] = placeholder;
52
+ replacements.delete(seg);
53
+ replaced = true;
54
+ }
55
+ }
56
+ return replaced ? segments.join("/") : void 0;
57
+ }
24
58
 
25
59
 
26
60
 
27
61
 
28
62
 
29
- exports.createCoreEmitter = _chunkSUVCVINAcjs.createEmitter; exports.createEmitter = createEmitter2; exports.getXrayContext = _chunkSUVCVINAcjs.getXrayContext; exports.wrapNextRoute = wrapNextRoute;
63
+ exports.createCoreEmitter = _chunkDLNU4YMGcjs.createEmitter; exports.createEmitter = createEmitter2; exports.getXrayContext = _chunkDLNU4YMGcjs.getXrayContext; exports.wrapNextRoute = wrapNextRoute;
30
64
  //# sourceMappingURL=next.cjs.map
package/dist/next.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/xray-emitter-js/xray-emitter-js/dist/next.cjs","../src/next/next.ts"],"names":["createEmitter"],"mappings":"AAAA;AACE;AACA;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACA;AC8BO,SAASA,cAAAA,CAAc,MAAA,EAA2B,OAAA,EAAoC;AAC3F,EAAA,MAAM,QAAA,EAAU,6CAAA,MAAyB,CAAA;AACzC,EAAA,MAAM,KAAA,EAAA,CAAQ,CAAC,OAAA,EAAA,GACb,aAAA,CAAc,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA,CAAA;AACzC,EAAA,IAAA,CAAK,MAAA,EAAQ,OAAA,CAAQ,KAAA;AACrB,EAAA,IAAA,CAAK,SAAA,EAAW,OAAA,CAAQ,QAAA;AACxB,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,aAAA,CACd,OAAA,EACA,IAAA,EACA,OAAA,EACoE;AACpE,EAAA,OAAO,MAAA,CAAO,OAAA,EAAS,OAAA,EAAA,GAAY;AACjC,IAAA,MAAM,QAAA,EAAU,iDAAA,CAAmB,GAAA,EAAA,GAAiB,OAAA,CAAQ,GAAA,EAAK,OAAO,CAAA,EAAG,IAAA,EAAM,OAAO,CAAA;AACxF,IAAA,OAAO,OAAA,CAAQ,OAAO,CAAA;AAAA,EACxB,CAAA;AACF;ADrCA;AACE;AACA;AACA;AACA;AACF,sMAAC","file":"/home/runner/work/xray-emitter-js/xray-emitter-js/dist/next.cjs","sourcesContent":[null,"import type { XrayEmitter, XrayRuntimeConfig } from '../core/index';\nimport {\n createEmitter as createFetchEmitter,\n getXrayContext,\n wrapFetchPreserve,\n type WrapOptions,\n} from '../fetch/fetch';\n\nexport { createFetchEmitter as createCoreEmitter };\nexport type {\n CaptureConfig,\n RedactionConfig,\n RequestLog,\n XrayConfig,\n XrayContext,\n XrayEmitter,\n XrayRuntimeConfig,\n} from '../core/index';\nexport type { WrapOptions } from '../fetch/fetch';\nexport { getXrayContext };\n\n// copy types from Next.js to avoid a package dependency\ntype NextRouteContext = {\n params: Promise<Record<string, string | string[]>>;\n};\n\ntype NextRouteHandler = (\n request: Request,\n context: NextRouteContext,\n) => Response | Promise<Response>;\n\ntype NextEmitter = ((handler: NextRouteHandler) => ReturnType<typeof wrapNextRoute>) & {\n flush: XrayEmitter['flush'];\n shutdown: XrayEmitter['shutdown'];\n};\n\n/**\n * Create a Next.js App Router wrapper and expose `flush()`/`shutdown()`.\n */\nexport function createEmitter(config: XrayRuntimeConfig, options?: WrapOptions): NextEmitter {\n const emitter = createFetchEmitter(config);\n const wrap = ((handler: NextRouteHandler) =>\n wrapNextRoute(handler, emitter, options)) as NextEmitter;\n wrap.flush = emitter.flush;\n wrap.shutdown = emitter.shutdown;\n return wrap;\n}\n\n/**\n * Wrap a Next.js route handler using an existing core `XrayEmitter`.\n */\nexport function wrapNextRoute(\n handler: NextRouteHandler,\n xray: XrayEmitter,\n options?: WrapOptions,\n): (request: Request, context: NextRouteContext) => Promise<Response> {\n return async (request, context) => {\n const wrapped = wrapFetchPreserve((req: Request) => handler(req, context), xray, options);\n return wrapped(request);\n };\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/xray-emitter-js/xray-emitter-js/dist/next.cjs","../src/next/next.ts"],"names":["createEmitter"],"mappings":"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","file":"/home/runner/work/xray-emitter-js/xray-emitter-js/dist/next.cjs","sourcesContent":[null,"import type { XrayEmitter, XrayRuntimeConfig } from '../core/index';\nimport {\n createEmitter as createFetchEmitter,\n getXrayContext,\n wrapFetchPreserve,\n type WrapOptions,\n} from '../fetch/fetch';\n\nexport { createFetchEmitter as createCoreEmitter };\nexport type {\n CaptureConfig,\n RedactionConfig,\n RequestLog,\n XrayConfig,\n XrayContext,\n XrayEmitter,\n XrayRuntimeConfig,\n} from '../core/index';\nexport type { WrapOptions } from '../fetch/fetch';\nexport { getXrayContext };\n\n// copy types from Next.js to avoid a package dependency\ntype NextRouteContext = {\n params: Promise<Record<string, string | string[]>>;\n};\n\ntype NextRouteHandler = (\n request: Request,\n context: NextRouteContext,\n) => Response | Promise<Response>;\n\ntype NextEmitter = ((handler: NextRouteHandler) => ReturnType<typeof wrapNextRoute>) & {\n flush: XrayEmitter['flush'];\n shutdown: XrayEmitter['shutdown'];\n};\n\n/**\n * Create a Next.js App Router wrapper and expose `flush()`/`shutdown()`.\n */\nexport function createEmitter(config: XrayRuntimeConfig, options?: WrapOptions): NextEmitter {\n const emitter = createFetchEmitter(config);\n const wrap = ((handler: NextRouteHandler) =>\n wrapNextRoute(handler, emitter, options)) as NextEmitter;\n wrap.flush = emitter.flush;\n wrap.shutdown = emitter.shutdown;\n return wrap;\n}\n\n/**\n * Wrap a Next.js route handler using an existing core `XrayEmitter`.\n */\nexport function wrapNextRoute(\n handler: NextRouteHandler,\n xray: XrayEmitter,\n options?: WrapOptions,\n): (request: Request, context: NextRouteContext) => Promise<Response> {\n return async (request, context) => {\n // When no explicit route option was provided, infer the route pattern\n // from the URL pathname and the resolved params (e.g. { subject: \"test\" }\n // turns /hello/test into /hello/[subject]).\n let effectiveOptions = options;\n if (!options?.route) {\n const params = await context.params;\n const route = inferRoute(new URL(request.url).pathname, params);\n if (route) {\n effectiveOptions = { ...options, route };\n }\n }\n\n const wrapped = wrapFetchPreserve(\n (req: Request) => handler(req, context),\n xray,\n effectiveOptions,\n );\n return wrapped(request);\n };\n}\n\nfunction inferRoute(\n pathname: string,\n params: Record<string, string | string[]>,\n): string | undefined {\n // Build a map from param value → placeholder for single-segment params.\n const replacements = new Map<string, string>();\n for (const [key, value] of Object.entries(params)) {\n if (typeof value === 'string') {\n replacements.set(value, `[${key}]`);\n }\n }\n if (replacements.size === 0) return undefined;\n\n const segments = pathname.split('/');\n let replaced = false;\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]!;\n const placeholder = replacements.get(seg);\n if (placeholder) {\n // If this param value appears in more than one segment we cannot\n // tell which is the dynamic one — bail out entirely.\n if (segments.indexOf(seg, i + 1) !== -1) return undefined;\n segments[i] = placeholder;\n replacements.delete(seg);\n replaced = true;\n }\n }\n return replaced ? segments.join('/') : undefined;\n}\n"]}
package/dist/next.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  createEmitter,
3
3
  getXrayContext,
4
4
  wrapFetchPreserve
5
- } from "./chunk-DV3MVQBB.js";
6
- import "./chunk-GYXI3DWB.js";
5
+ } from "./chunk-2U5UHEQ6.js";
6
+ import "./chunk-T5GUIVFZ.js";
7
7
  import "./chunk-NTIUR3OC.js";
8
8
  import "./chunk-7KT6EPVZ.js";
9
9
 
@@ -17,10 +17,44 @@ function createEmitter2(config, options) {
17
17
  }
18
18
  function wrapNextRoute(handler, xray, options) {
19
19
  return async (request, context) => {
20
- const wrapped = wrapFetchPreserve((req) => handler(req, context), xray, options);
20
+ let effectiveOptions = options;
21
+ if (!options?.route) {
22
+ const params = await context.params;
23
+ const route = inferRoute(new URL(request.url).pathname, params);
24
+ if (route) {
25
+ effectiveOptions = { ...options, route };
26
+ }
27
+ }
28
+ const wrapped = wrapFetchPreserve(
29
+ (req) => handler(req, context),
30
+ xray,
31
+ effectiveOptions
32
+ );
21
33
  return wrapped(request);
22
34
  };
23
35
  }
36
+ function inferRoute(pathname, params) {
37
+ const replacements = /* @__PURE__ */ new Map();
38
+ for (const [key, value] of Object.entries(params)) {
39
+ if (typeof value === "string") {
40
+ replacements.set(value, `[${key}]`);
41
+ }
42
+ }
43
+ if (replacements.size === 0) return void 0;
44
+ const segments = pathname.split("/");
45
+ let replaced = false;
46
+ for (let i = 0; i < segments.length; i++) {
47
+ const seg = segments[i];
48
+ const placeholder = replacements.get(seg);
49
+ if (placeholder) {
50
+ if (segments.indexOf(seg, i + 1) !== -1) return void 0;
51
+ segments[i] = placeholder;
52
+ replacements.delete(seg);
53
+ replaced = true;
54
+ }
55
+ }
56
+ return replaced ? segments.join("/") : void 0;
57
+ }
24
58
  export {
25
59
  createEmitter as createCoreEmitter,
26
60
  createEmitter2 as createEmitter,
package/dist/next.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/next/next.ts"],"sourcesContent":["import type { XrayEmitter, XrayRuntimeConfig } from '../core/index';\nimport {\n createEmitter as createFetchEmitter,\n getXrayContext,\n wrapFetchPreserve,\n type WrapOptions,\n} from '../fetch/fetch';\n\nexport { createFetchEmitter as createCoreEmitter };\nexport type {\n CaptureConfig,\n RedactionConfig,\n RequestLog,\n XrayConfig,\n XrayContext,\n XrayEmitter,\n XrayRuntimeConfig,\n} from '../core/index';\nexport type { WrapOptions } from '../fetch/fetch';\nexport { getXrayContext };\n\n// copy types from Next.js to avoid a package dependency\ntype NextRouteContext = {\n params: Promise<Record<string, string | string[]>>;\n};\n\ntype NextRouteHandler = (\n request: Request,\n context: NextRouteContext,\n) => Response | Promise<Response>;\n\ntype NextEmitter = ((handler: NextRouteHandler) => ReturnType<typeof wrapNextRoute>) & {\n flush: XrayEmitter['flush'];\n shutdown: XrayEmitter['shutdown'];\n};\n\n/**\n * Create a Next.js App Router wrapper and expose `flush()`/`shutdown()`.\n */\nexport function createEmitter(config: XrayRuntimeConfig, options?: WrapOptions): NextEmitter {\n const emitter = createFetchEmitter(config);\n const wrap = ((handler: NextRouteHandler) =>\n wrapNextRoute(handler, emitter, options)) as NextEmitter;\n wrap.flush = emitter.flush;\n wrap.shutdown = emitter.shutdown;\n return wrap;\n}\n\n/**\n * Wrap a Next.js route handler using an existing core `XrayEmitter`.\n */\nexport function wrapNextRoute(\n handler: NextRouteHandler,\n xray: XrayEmitter,\n options?: WrapOptions,\n): (request: Request, context: NextRouteContext) => Promise<Response> {\n return async (request, context) => {\n const wrapped = wrapFetchPreserve((req: Request) => handler(req, context), xray, options);\n return wrapped(request);\n };\n}\n"],"mappings":";;;;;;;;;;AAuCO,SAASA,eAAc,QAA2B,SAAoC;AAC3F,QAAM,UAAU,cAAmB,MAAM;AACzC,QAAM,QAAQ,CAAC,YACb,cAAc,SAAS,SAAS,OAAO;AACzC,OAAK,QAAQ,QAAQ;AACrB,OAAK,WAAW,QAAQ;AACxB,SAAO;AACT;AAKO,SAAS,cACd,SACA,MACA,SACoE;AACpE,SAAO,OAAO,SAAS,YAAY;AACjC,UAAM,UAAU,kBAAkB,CAAC,QAAiB,QAAQ,KAAK,OAAO,GAAG,MAAM,OAAO;AACxF,WAAO,QAAQ,OAAO;AAAA,EACxB;AACF;","names":["createEmitter"]}
1
+ {"version":3,"sources":["../src/next/next.ts"],"sourcesContent":["import type { XrayEmitter, XrayRuntimeConfig } from '../core/index';\nimport {\n createEmitter as createFetchEmitter,\n getXrayContext,\n wrapFetchPreserve,\n type WrapOptions,\n} from '../fetch/fetch';\n\nexport { createFetchEmitter as createCoreEmitter };\nexport type {\n CaptureConfig,\n RedactionConfig,\n RequestLog,\n XrayConfig,\n XrayContext,\n XrayEmitter,\n XrayRuntimeConfig,\n} from '../core/index';\nexport type { WrapOptions } from '../fetch/fetch';\nexport { getXrayContext };\n\n// copy types from Next.js to avoid a package dependency\ntype NextRouteContext = {\n params: Promise<Record<string, string | string[]>>;\n};\n\ntype NextRouteHandler = (\n request: Request,\n context: NextRouteContext,\n) => Response | Promise<Response>;\n\ntype NextEmitter = ((handler: NextRouteHandler) => ReturnType<typeof wrapNextRoute>) & {\n flush: XrayEmitter['flush'];\n shutdown: XrayEmitter['shutdown'];\n};\n\n/**\n * Create a Next.js App Router wrapper and expose `flush()`/`shutdown()`.\n */\nexport function createEmitter(config: XrayRuntimeConfig, options?: WrapOptions): NextEmitter {\n const emitter = createFetchEmitter(config);\n const wrap = ((handler: NextRouteHandler) =>\n wrapNextRoute(handler, emitter, options)) as NextEmitter;\n wrap.flush = emitter.flush;\n wrap.shutdown = emitter.shutdown;\n return wrap;\n}\n\n/**\n * Wrap a Next.js route handler using an existing core `XrayEmitter`.\n */\nexport function wrapNextRoute(\n handler: NextRouteHandler,\n xray: XrayEmitter,\n options?: WrapOptions,\n): (request: Request, context: NextRouteContext) => Promise<Response> {\n return async (request, context) => {\n // When no explicit route option was provided, infer the route pattern\n // from the URL pathname and the resolved params (e.g. { subject: \"test\" }\n // turns /hello/test into /hello/[subject]).\n let effectiveOptions = options;\n if (!options?.route) {\n const params = await context.params;\n const route = inferRoute(new URL(request.url).pathname, params);\n if (route) {\n effectiveOptions = { ...options, route };\n }\n }\n\n const wrapped = wrapFetchPreserve(\n (req: Request) => handler(req, context),\n xray,\n effectiveOptions,\n );\n return wrapped(request);\n };\n}\n\nfunction inferRoute(\n pathname: string,\n params: Record<string, string | string[]>,\n): string | undefined {\n // Build a map from param value → placeholder for single-segment params.\n const replacements = new Map<string, string>();\n for (const [key, value] of Object.entries(params)) {\n if (typeof value === 'string') {\n replacements.set(value, `[${key}]`);\n }\n }\n if (replacements.size === 0) return undefined;\n\n const segments = pathname.split('/');\n let replaced = false;\n for (let i = 0; i < segments.length; i++) {\n const seg = segments[i]!;\n const placeholder = replacements.get(seg);\n if (placeholder) {\n // If this param value appears in more than one segment we cannot\n // tell which is the dynamic one — bail out entirely.\n if (segments.indexOf(seg, i + 1) !== -1) return undefined;\n segments[i] = placeholder;\n replacements.delete(seg);\n replaced = true;\n }\n }\n return replaced ? segments.join('/') : undefined;\n}\n"],"mappings":";;;;;;;;;;AAuCO,SAASA,eAAc,QAA2B,SAAoC;AAC3F,QAAM,UAAU,cAAmB,MAAM;AACzC,QAAM,QAAQ,CAAC,YACb,cAAc,SAAS,SAAS,OAAO;AACzC,OAAK,QAAQ,QAAQ;AACrB,OAAK,WAAW,QAAQ;AACxB,SAAO;AACT;AAKO,SAAS,cACd,SACA,MACA,SACoE;AACpE,SAAO,OAAO,SAAS,YAAY;AAIjC,QAAI,mBAAmB;AACvB,QAAI,CAAC,SAAS,OAAO;AACnB,YAAM,SAAS,MAAM,QAAQ;AAC7B,YAAM,QAAQ,WAAW,IAAI,IAAI,QAAQ,GAAG,EAAE,UAAU,MAAM;AAC9D,UAAI,OAAO;AACT,2BAAmB,EAAE,GAAG,SAAS,MAAM;AAAA,MACzC;AAAA,IACF;AAEA,UAAM,UAAU;AAAA,MACd,CAAC,QAAiB,QAAQ,KAAK,OAAO;AAAA,MACtC;AAAA,MACA;AAAA,IACF;AACA,WAAO,QAAQ,OAAO;AAAA,EACxB;AACF;AAEA,SAAS,WACP,UACA,QACoB;AAEpB,QAAM,eAAe,oBAAI,IAAoB;AAC7C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,OAAO,UAAU,UAAU;AAC7B,mBAAa,IAAI,OAAO,IAAI,GAAG,GAAG;AAAA,IACpC;AAAA,EACF;AACA,MAAI,aAAa,SAAS,EAAG,QAAO;AAEpC,QAAM,WAAW,SAAS,MAAM,GAAG;AACnC,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,MAAM,SAAS,CAAC;AACtB,UAAM,cAAc,aAAa,IAAI,GAAG;AACxC,QAAI,aAAa;AAGf,UAAI,SAAS,QAAQ,KAAK,IAAI,CAAC,MAAM,GAAI,QAAO;AAChD,eAAS,CAAC,IAAI;AACd,mBAAa,OAAO,GAAG;AACvB,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO,WAAW,SAAS,KAAK,GAAG,IAAI;AACzC;","names":["createEmitter"]}
package/dist/node.cjs CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
 
4
4
 
5
- var _chunk55YD27PVcjs = require('./chunk-55YD27PV.cjs');
6
- require('./chunk-UJWD5CFA.cjs');
5
+ var _chunkN2MJE6CJcjs = require('./chunk-N2MJE6CJ.cjs');
6
+ require('./chunk-E2ZM6DIT.cjs');
7
7
  require('./chunk-CPHFCOA5.cjs');
8
8
  require('./chunk-DNBARLGB.cjs');
9
9
 
10
10
 
11
11
 
12
12
 
13
- exports.createEmitter = _chunk55YD27PVcjs.createEmitter; exports.getXrayContext = _chunk55YD27PVcjs.getXrayContext; exports.wrapHttpHandler = _chunk55YD27PVcjs.wrapHttpHandler;
13
+ exports.createEmitter = _chunkN2MJE6CJcjs.createEmitter; exports.getXrayContext = _chunkN2MJE6CJcjs.getXrayContext; exports.wrapHttpHandler = _chunkN2MJE6CJcjs.wrapHttpHandler;
14
14
  //# sourceMappingURL=node.cjs.map
package/dist/node.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  createEmitter,
3
3
  getXrayContext,
4
4
  wrapHttpHandler
5
- } from "./chunk-FGXXKIF7.js";
6
- import "./chunk-GYXI3DWB.js";
5
+ } from "./chunk-AB2LRSJ4.js";
6
+ import "./chunk-T5GUIVFZ.js";
7
7
  import "./chunk-NTIUR3OC.js";
8
8
  import "./chunk-7KT6EPVZ.js";
9
9
  export {
package/dist/remix.cjs CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkSUVCVINAcjs = require('./chunk-SUVCVINA.cjs');
6
- require('./chunk-UJWD5CFA.cjs');
5
+ var _chunkDLNU4YMGcjs = require('./chunk-DLNU4YMG.cjs');
6
+ require('./chunk-E2ZM6DIT.cjs');
7
7
  require('./chunk-CPHFCOA5.cjs');
8
8
  require('./chunk-DNBARLGB.cjs');
9
9
 
10
10
  // src/remix/remix.ts
11
11
  function createEmitter2(config, options) {
12
- const emitter = _chunkSUVCVINAcjs.createEmitter.call(void 0, config);
12
+ const emitter = _chunkDLNU4YMGcjs.createEmitter.call(void 0, config);
13
13
  const wrap = ((handler) => wrapRemixRequestHandler(handler, emitter, options));
14
14
  wrap.flush = emitter.flush;
15
15
  wrap.shutdown = emitter.shutdown;
@@ -17,7 +17,7 @@ function createEmitter2(config, options) {
17
17
  }
18
18
  function wrapRemixRequestHandler(handler, xray, options) {
19
19
  return (request, loadContext) => {
20
- const wrapped = _chunkSUVCVINAcjs.wrapFetchPreserve.call(void 0, (req) => handler(req, loadContext), xray, options);
20
+ const wrapped = _chunkDLNU4YMGcjs.wrapFetchPreserve.call(void 0, (req) => handler(req, loadContext), xray, options);
21
21
  return wrapped(request);
22
22
  };
23
23
  }
@@ -26,5 +26,5 @@ function wrapRemixRequestHandler(handler, xray, options) {
26
26
 
27
27
 
28
28
 
29
- exports.createCoreEmitter = _chunkSUVCVINAcjs.createEmitter; exports.createEmitter = createEmitter2; exports.getXrayContext = _chunkSUVCVINAcjs.getXrayContext; exports.wrapRemixRequestHandler = wrapRemixRequestHandler;
29
+ exports.createCoreEmitter = _chunkDLNU4YMGcjs.createEmitter; exports.createEmitter = createEmitter2; exports.getXrayContext = _chunkDLNU4YMGcjs.getXrayContext; exports.wrapRemixRequestHandler = wrapRemixRequestHandler;
30
30
  //# sourceMappingURL=remix.cjs.map
package/dist/remix.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  createEmitter,
3
3
  getXrayContext,
4
4
  wrapFetchPreserve
5
- } from "./chunk-DV3MVQBB.js";
6
- import "./chunk-GYXI3DWB.js";
5
+ } from "./chunk-2U5UHEQ6.js";
6
+ import "./chunk-T5GUIVFZ.js";
7
7
  import "./chunk-NTIUR3OC.js";
8
8
  import "./chunk-7KT6EPVZ.js";
9
9
 
package/dist/stub.cjs ADDED
@@ -0,0 +1,121 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/stub/stub.ts
2
+ var _http = require('http'); var _http2 = _interopRequireDefault(_http);
3
+ var _rootjs = require('@opentelemetry/otlp-transformer/build/src/generated/root.js'); var _rootjs2 = _interopRequireDefault(_rootjs);
4
+ var root = _rootjs2.default;
5
+ var ExportTraceServiceRequest = root.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
6
+ function decodeAttributes(attrs) {
7
+ const result = {};
8
+ for (const attr of attrs) {
9
+ const v = attr.value;
10
+ if (v == null) continue;
11
+ if (v.stringValue != null) result[attr.key] = v.stringValue;
12
+ else if (v.intValue != null) result[attr.key] = Number(v.intValue);
13
+ else if (v.doubleValue != null) result[attr.key] = v.doubleValue;
14
+ else if (v.boolValue != null) result[attr.key] = v.boolValue;
15
+ else if (_optionalChain([v, 'access', _ => _.arrayValue, 'optionalAccess', _2 => _2.values])) {
16
+ result[attr.key] = v.arrayValue.values.map((item) => item.stringValue).filter((s) => s != null);
17
+ }
18
+ }
19
+ return result;
20
+ }
21
+ function buildCapturedBody(bodyValue, encoding, truncated, sizeBytes) {
22
+ if (bodyValue == null) return void 0;
23
+ return {
24
+ bytes: _nullishCoalesce(sizeBytes, () => ( 0)),
25
+ encoding: _nullishCoalesce(encoding, () => ( "utf8")),
26
+ truncated: _nullishCoalesce(truncated, () => ( false)),
27
+ value: bodyValue
28
+ };
29
+ }
30
+ function collectHeaders(attrs, prefix) {
31
+ const headers = {};
32
+ let found = false;
33
+ for (const [key, value] of Object.entries(attrs)) {
34
+ if (key.startsWith(prefix)) {
35
+ found = true;
36
+ const headerName = key.slice(prefix.length);
37
+ headers[headerName] = value;
38
+ }
39
+ }
40
+ return found ? headers : void 0;
41
+ }
42
+ function spanToRequestLog(attrs) {
43
+ const method = attrs["http.request.method"];
44
+ if (method == null) return void 0;
45
+ return {
46
+ requestId: _nullishCoalesce(attrs["http.request.id"], () => ( "")),
47
+ serviceName: _nullishCoalesce(attrs["service.name"], () => ( "")),
48
+ method,
49
+ url: _nullishCoalesce(attrs["url.full"], () => ( "")),
50
+ route: attrs["http.route"],
51
+ statusCode: attrs["http.response.status_code"],
52
+ durationMs: 0,
53
+ requestHeaders: collectHeaders(attrs, "http.request.header."),
54
+ responseHeaders: collectHeaders(attrs, "http.response.header."),
55
+ requestBody: buildCapturedBody(
56
+ attrs["http.request.body"],
57
+ attrs["http.request.body.encoding"],
58
+ attrs["http.request.body.truncated"],
59
+ attrs["http.request.body.size"]
60
+ ),
61
+ responseBody: buildCapturedBody(
62
+ attrs["http.response.body"],
63
+ attrs["http.response.body.encoding"],
64
+ attrs["http.response.body.truncated"],
65
+ attrs["http.response.body.size"]
66
+ ),
67
+ tenantId: attrs["stainlessxray.tenant.id"],
68
+ userId: attrs["enduser.id"],
69
+ timestamp: ""
70
+ };
71
+ }
72
+ function decodeRequestLogs(body) {
73
+ const msg = ExportTraceServiceRequest.decode(body);
74
+ const obj = ExportTraceServiceRequest.toObject(msg, { defaults: true });
75
+ const logs = [];
76
+ for (const rs of _nullishCoalesce(obj.resourceSpans, () => ( []))) {
77
+ for (const ss of _nullishCoalesce(rs.scopeSpans, () => ( []))) {
78
+ for (const span of _nullishCoalesce(ss.spans, () => ( []))) {
79
+ const attrs = decodeAttributes(_nullishCoalesce(span.attributes, () => ( [])));
80
+ const log = spanToRequestLog(attrs);
81
+ if (log) logs.push(log);
82
+ }
83
+ }
84
+ }
85
+ return logs;
86
+ }
87
+ function createStub() {
88
+ return new Promise((resolve) => {
89
+ const requestLogs = [];
90
+ const server = _http2.default.createServer((req, res) => {
91
+ if (req.method === "POST" && req.url === "/v1/traces") {
92
+ const chunks = [];
93
+ req.on("data", (chunk) => chunks.push(chunk));
94
+ req.on("end", () => {
95
+ const body = Buffer.concat(chunks);
96
+ const logs = decodeRequestLogs(body);
97
+ requestLogs.push(...logs);
98
+ res.writeHead(200);
99
+ res.end();
100
+ });
101
+ } else {
102
+ res.writeHead(404);
103
+ res.end();
104
+ }
105
+ });
106
+ server.listen(0, "127.0.0.1", () => {
107
+ const addr = server.address();
108
+ resolve({
109
+ url: `http://127.0.0.1:${addr.port}`,
110
+ requestLogs,
111
+ close() {
112
+ return new Promise((resolve2) => server.close(() => resolve2()));
113
+ }
114
+ });
115
+ });
116
+ });
117
+ }
118
+
119
+
120
+ exports.createStub = createStub;
121
+ //# sourceMappingURL=stub.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/xray-emitter-js/xray-emitter-js/dist/stub.cjs","../src/stub/stub.ts"],"names":[],"mappings":"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","file":"/home/runner/work/xray-emitter-js/xray-emitter-js/dist/stub.cjs","sourcesContent":[null,"import http from 'node:http';\nimport type { RequestLog, CapturedBody } from '../core/types';\n\nimport _root from '@opentelemetry/otlp-transformer/build/src/generated/root.js';\n\n// The generated protobuf root has deeply nested namespaces that aren't\n// reflected in its type declarations.\nconst root = _root as any;\nconst ExportTraceServiceRequest =\n root.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;\n\nexport type { RequestLog };\n\nexport interface XrayStub {\n url: string;\n /** Request logs reconstructed from exported spans. */\n requestLogs: RequestLog[];\n close(): Promise<void>;\n}\n\ntype SpanAttributes = Record<string, string | number | boolean | string[]>;\n\nfunction decodeAttributes(attrs: any[]): SpanAttributes {\n const result: SpanAttributes = {};\n for (const attr of attrs) {\n const v = attr.value;\n if (v == null) continue;\n if (v.stringValue != null) result[attr.key] = v.stringValue;\n else if (v.intValue != null) result[attr.key] = Number(v.intValue);\n else if (v.doubleValue != null) result[attr.key] = v.doubleValue;\n else if (v.boolValue != null) result[attr.key] = v.boolValue;\n else if (v.arrayValue?.values) {\n result[attr.key] = v.arrayValue.values\n .map((item: any) => item.stringValue)\n .filter((s: any) => s != null);\n }\n }\n return result;\n}\n\nfunction buildCapturedBody(\n bodyValue: string | undefined,\n encoding: string | undefined,\n truncated: boolean | undefined,\n sizeBytes: number | undefined,\n): CapturedBody | undefined {\n if (bodyValue == null) return undefined;\n return {\n bytes: sizeBytes ?? 0,\n encoding: (encoding as 'utf8' | 'base64') ?? 'utf8',\n truncated: truncated ?? false,\n value: bodyValue,\n };\n}\n\nfunction collectHeaders(\n attrs: SpanAttributes,\n prefix: string,\n): Record<string, string | string[]> | undefined {\n const headers: Record<string, string | string[]> = {};\n let found = false;\n for (const [key, value] of Object.entries(attrs)) {\n if (key.startsWith(prefix)) {\n found = true;\n const headerName = key.slice(prefix.length);\n headers[headerName] = value as string | string[];\n }\n }\n return found ? headers : undefined;\n}\n\nfunction spanToRequestLog(attrs: SpanAttributes): RequestLog | undefined {\n const method = attrs['http.request.method'] as string | undefined;\n if (method == null) return undefined;\n\n return {\n requestId: (attrs['http.request.id'] as string) ?? '',\n serviceName: (attrs['service.name'] as string) ?? '',\n method,\n url: (attrs['url.full'] as string) ?? '',\n route: attrs['http.route'] as string | undefined,\n statusCode: attrs['http.response.status_code'] as number | undefined,\n durationMs: 0,\n requestHeaders: collectHeaders(attrs, 'http.request.header.'),\n responseHeaders: collectHeaders(attrs, 'http.response.header.'),\n requestBody: buildCapturedBody(\n attrs['http.request.body'] as string | undefined,\n attrs['http.request.body.encoding'] as string | undefined,\n attrs['http.request.body.truncated'] as boolean | undefined,\n attrs['http.request.body.size'] as number | undefined,\n ),\n responseBody: buildCapturedBody(\n attrs['http.response.body'] as string | undefined,\n attrs['http.response.body.encoding'] as string | undefined,\n attrs['http.response.body.truncated'] as boolean | undefined,\n attrs['http.response.body.size'] as number | undefined,\n ),\n tenantId: attrs['stainlessxray.tenant.id'] as string | undefined,\n userId: attrs['enduser.id'] as string | undefined,\n timestamp: '',\n };\n}\n\nfunction decodeRequestLogs(body: Buffer): RequestLog[] {\n const msg = ExportTraceServiceRequest.decode(body);\n const obj = ExportTraceServiceRequest.toObject(msg, { defaults: true });\n\n const logs: RequestLog[] = [];\n for (const rs of obj.resourceSpans ?? []) {\n for (const ss of rs.scopeSpans ?? []) {\n for (const span of ss.spans ?? []) {\n const attrs = decodeAttributes(span.attributes ?? []);\n const log = spanToRequestLog(attrs);\n if (log) logs.push(log);\n }\n }\n }\n return logs;\n}\n\nexport function createStub(): Promise<XrayStub> {\n return new Promise((resolve) => {\n const requestLogs: RequestLog[] = [];\n\n const server = http.createServer((req, res) => {\n if (req.method === 'POST' && req.url === '/v1/traces') {\n const chunks: Buffer[] = [];\n req.on('data', (chunk: Buffer) => chunks.push(chunk));\n req.on('end', () => {\n const body = Buffer.concat(chunks);\n const logs = decodeRequestLogs(body);\n requestLogs.push(...logs);\n\n res.writeHead(200);\n res.end();\n });\n } else {\n res.writeHead(404);\n res.end();\n }\n });\n\n server.listen(0, '127.0.0.1', () => {\n const addr = server.address() as import('node:net').AddressInfo;\n resolve({\n url: `http://127.0.0.1:${addr.port}`,\n requestLogs,\n close() {\n return new Promise((resolve) => server.close(() => resolve()));\n },\n });\n });\n });\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { R as RequestLog } from './types-BrKvhHbn.cjs';
2
+ import '@opentelemetry/sdk-trace-base';
3
+
4
+ interface XrayStub {
5
+ url: string;
6
+ /** Request logs reconstructed from exported spans. */
7
+ requestLogs: RequestLog[];
8
+ close(): Promise<void>;
9
+ }
10
+ declare function createStub(): Promise<XrayStub>;
11
+
12
+ export { RequestLog, type XrayStub, createStub };
package/dist/stub.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { R as RequestLog } from './types-BrKvhHbn.js';
2
+ import '@opentelemetry/sdk-trace-base';
3
+
4
+ interface XrayStub {
5
+ url: string;
6
+ /** Request logs reconstructed from exported spans. */
7
+ requestLogs: RequestLog[];
8
+ close(): Promise<void>;
9
+ }
10
+ declare function createStub(): Promise<XrayStub>;
11
+
12
+ export { RequestLog, type XrayStub, createStub };
package/dist/stub.js ADDED
@@ -0,0 +1,121 @@
1
+ // src/stub/stub.ts
2
+ import http from "http";
3
+ import _root from "@opentelemetry/otlp-transformer/build/src/generated/root.js";
4
+ var root = _root;
5
+ var ExportTraceServiceRequest = root.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest;
6
+ function decodeAttributes(attrs) {
7
+ const result = {};
8
+ for (const attr of attrs) {
9
+ const v = attr.value;
10
+ if (v == null) continue;
11
+ if (v.stringValue != null) result[attr.key] = v.stringValue;
12
+ else if (v.intValue != null) result[attr.key] = Number(v.intValue);
13
+ else if (v.doubleValue != null) result[attr.key] = v.doubleValue;
14
+ else if (v.boolValue != null) result[attr.key] = v.boolValue;
15
+ else if (v.arrayValue?.values) {
16
+ result[attr.key] = v.arrayValue.values.map((item) => item.stringValue).filter((s) => s != null);
17
+ }
18
+ }
19
+ return result;
20
+ }
21
+ function buildCapturedBody(bodyValue, encoding, truncated, sizeBytes) {
22
+ if (bodyValue == null) return void 0;
23
+ return {
24
+ bytes: sizeBytes ?? 0,
25
+ encoding: encoding ?? "utf8",
26
+ truncated: truncated ?? false,
27
+ value: bodyValue
28
+ };
29
+ }
30
+ function collectHeaders(attrs, prefix) {
31
+ const headers = {};
32
+ let found = false;
33
+ for (const [key, value] of Object.entries(attrs)) {
34
+ if (key.startsWith(prefix)) {
35
+ found = true;
36
+ const headerName = key.slice(prefix.length);
37
+ headers[headerName] = value;
38
+ }
39
+ }
40
+ return found ? headers : void 0;
41
+ }
42
+ function spanToRequestLog(attrs) {
43
+ const method = attrs["http.request.method"];
44
+ if (method == null) return void 0;
45
+ return {
46
+ requestId: attrs["http.request.id"] ?? "",
47
+ serviceName: attrs["service.name"] ?? "",
48
+ method,
49
+ url: attrs["url.full"] ?? "",
50
+ route: attrs["http.route"],
51
+ statusCode: attrs["http.response.status_code"],
52
+ durationMs: 0,
53
+ requestHeaders: collectHeaders(attrs, "http.request.header."),
54
+ responseHeaders: collectHeaders(attrs, "http.response.header."),
55
+ requestBody: buildCapturedBody(
56
+ attrs["http.request.body"],
57
+ attrs["http.request.body.encoding"],
58
+ attrs["http.request.body.truncated"],
59
+ attrs["http.request.body.size"]
60
+ ),
61
+ responseBody: buildCapturedBody(
62
+ attrs["http.response.body"],
63
+ attrs["http.response.body.encoding"],
64
+ attrs["http.response.body.truncated"],
65
+ attrs["http.response.body.size"]
66
+ ),
67
+ tenantId: attrs["stainlessxray.tenant.id"],
68
+ userId: attrs["enduser.id"],
69
+ timestamp: ""
70
+ };
71
+ }
72
+ function decodeRequestLogs(body) {
73
+ const msg = ExportTraceServiceRequest.decode(body);
74
+ const obj = ExportTraceServiceRequest.toObject(msg, { defaults: true });
75
+ const logs = [];
76
+ for (const rs of obj.resourceSpans ?? []) {
77
+ for (const ss of rs.scopeSpans ?? []) {
78
+ for (const span of ss.spans ?? []) {
79
+ const attrs = decodeAttributes(span.attributes ?? []);
80
+ const log = spanToRequestLog(attrs);
81
+ if (log) logs.push(log);
82
+ }
83
+ }
84
+ }
85
+ return logs;
86
+ }
87
+ function createStub() {
88
+ return new Promise((resolve) => {
89
+ const requestLogs = [];
90
+ const server = http.createServer((req, res) => {
91
+ if (req.method === "POST" && req.url === "/v1/traces") {
92
+ const chunks = [];
93
+ req.on("data", (chunk) => chunks.push(chunk));
94
+ req.on("end", () => {
95
+ const body = Buffer.concat(chunks);
96
+ const logs = decodeRequestLogs(body);
97
+ requestLogs.push(...logs);
98
+ res.writeHead(200);
99
+ res.end();
100
+ });
101
+ } else {
102
+ res.writeHead(404);
103
+ res.end();
104
+ }
105
+ });
106
+ server.listen(0, "127.0.0.1", () => {
107
+ const addr = server.address();
108
+ resolve({
109
+ url: `http://127.0.0.1:${addr.port}`,
110
+ requestLogs,
111
+ close() {
112
+ return new Promise((resolve2) => server.close(() => resolve2()));
113
+ }
114
+ });
115
+ });
116
+ });
117
+ }
118
+ export {
119
+ createStub
120
+ };
121
+ //# sourceMappingURL=stub.js.map