@stainlessdev/xray-emitter 0.3.1-dev.b4b7607 → 0.3.2
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.
- package/dist/next.cjs +36 -2
- package/dist/next.cjs.map +1 -1
- package/dist/next.js +35 -1
- package/dist/next.js.map +1 -1
- package/dist/stub.cjs +121 -0
- package/dist/stub.cjs.map +1 -0
- package/dist/stub.d.cts +12 -0
- package/dist/stub.d.ts +12 -0
- package/dist/stub.js +121 -0
- package/dist/stub.js.map +1 -0
- package/package.json +8 -2
package/dist/next.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
|
|
|
@@ -17,10 +17,44 @@ function createEmitter2(config, options) {
|
|
|
17
17
|
}
|
|
18
18
|
function wrapNextRoute(handler, xray, options) {
|
|
19
19
|
return async (request, context) => {
|
|
20
|
-
|
|
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
|
|
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;
|
|
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
|
@@ -17,10 +17,44 @@ function createEmitter2(config, options) {
|
|
|
17
17
|
}
|
|
18
18
|
function wrapNextRoute(handler, xray, options) {
|
|
19
19
|
return async (request, context) => {
|
|
20
|
-
|
|
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),
|
|
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/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"]}
|
package/dist/stub.d.cts
ADDED
|
@@ -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
|
package/dist/stub.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/stub/stub.ts"],"sourcesContent":["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"],"mappings":"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","names":["resolve"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stainlessdev/xray-emitter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -56,6 +56,11 @@
|
|
|
56
56
|
"types": "./dist/effect.d.ts",
|
|
57
57
|
"import": "./dist/effect.js",
|
|
58
58
|
"require": "./dist/effect.cjs"
|
|
59
|
+
},
|
|
60
|
+
"./stub": {
|
|
61
|
+
"types": "./dist/stub.d.ts",
|
|
62
|
+
"import": "./dist/stub.js",
|
|
63
|
+
"require": "./dist/stub.cjs"
|
|
59
64
|
}
|
|
60
65
|
},
|
|
61
66
|
"files": [
|
|
@@ -65,6 +70,7 @@
|
|
|
65
70
|
"@opentelemetry/api": "^1.9.0",
|
|
66
71
|
"@opentelemetry/core": "^2.2.0",
|
|
67
72
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.200.0",
|
|
73
|
+
"@opentelemetry/otlp-transformer": "^0.200.0",
|
|
68
74
|
"@opentelemetry/resources": "^2.2.0",
|
|
69
75
|
"@opentelemetry/sdk-trace-base": "^2.2.0",
|
|
70
76
|
"@opentelemetry/semantic-conventions": "^1.29.0"
|
|
@@ -73,8 +79,8 @@
|
|
|
73
79
|
"@effect/platform": "^0.94.0",
|
|
74
80
|
"@types/express": "^5.0.0",
|
|
75
81
|
"@types/node": "^20.19.29",
|
|
76
|
-
"esbuild": "^0.25.0",
|
|
77
82
|
"effect": "^3.19.0",
|
|
83
|
+
"esbuild": "^0.25.0",
|
|
78
84
|
"express": "^5.2.1",
|
|
79
85
|
"fastify": "^5.6.2",
|
|
80
86
|
"hono": "^4.11.4",
|