@stainlessdev/xray-node 0.1.0-branch.bg-publish-to-npm.18b1cb1
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/index.cjs +544 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +528 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
getXrayContext: () => getXrayContext,
|
|
24
|
+
wrapHttpHandler: () => wrapHttpHandler
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/adapter.ts
|
|
29
|
+
var import_node_tls = require("tls");
|
|
30
|
+
var import_internal = require("@stainlessdev/xray-core/internal");
|
|
31
|
+
function wrapHttpHandler(handler, xray, options) {
|
|
32
|
+
return (req, res) => {
|
|
33
|
+
const normalizedRequest = {
|
|
34
|
+
method: req.method ?? "GET",
|
|
35
|
+
url: fullUrl(req),
|
|
36
|
+
route: options?.route,
|
|
37
|
+
headers: (0, import_internal.headerValuesFromNodeHeaders)(
|
|
38
|
+
req.headers
|
|
39
|
+
),
|
|
40
|
+
requestId: resolveRequestId(options?.requestId, req, xray),
|
|
41
|
+
remoteAddress: req.socket?.remoteAddress,
|
|
42
|
+
startTimeMs: Date.now()
|
|
43
|
+
};
|
|
44
|
+
trackExpressParams(req);
|
|
45
|
+
const ctx = xray.startRequest(normalizedRequest);
|
|
46
|
+
(0, import_internal.bindContextToObject)(req, ctx);
|
|
47
|
+
(0, import_internal.bindContextToObject)(res, ctx);
|
|
48
|
+
if (options?.requestId) {
|
|
49
|
+
(0, import_internal.setContextRequestId)(ctx, options.requestId);
|
|
50
|
+
}
|
|
51
|
+
if (options?.route) {
|
|
52
|
+
(0, import_internal.setContextRoute)(ctx, options.route);
|
|
53
|
+
}
|
|
54
|
+
if (options?.capture) {
|
|
55
|
+
(0, import_internal.setCaptureOverride)(ctx, options.capture);
|
|
56
|
+
}
|
|
57
|
+
if (options?.redaction) {
|
|
58
|
+
(0, import_internal.setRedactionOverride)(ctx, options.redaction);
|
|
59
|
+
}
|
|
60
|
+
if (options?.onRequest) {
|
|
61
|
+
try {
|
|
62
|
+
options.onRequest(ctx);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
(0, import_internal.logWithLevel)(xray.config.logger, "warn", xray.config.logLevel, "xray: onRequest failed", {
|
|
65
|
+
error: err instanceof Error ? err.message : String(err)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const capture = options?.capture ? { ...xray.config.capture, ...options.capture } : xray.config.capture;
|
|
70
|
+
const requestCapture = capture.requestBody === "none" ? null : wrapRequestBody(req, capture.maxBodyBytes);
|
|
71
|
+
const recorder = new ResponseRecorder(capture.responseBody !== "none", capture.maxBodyBytes);
|
|
72
|
+
recorder.wrap(res);
|
|
73
|
+
let finished = false;
|
|
74
|
+
let capturedError;
|
|
75
|
+
let onErrorCalled = false;
|
|
76
|
+
const finish = () => {
|
|
77
|
+
if (finished) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
finished = true;
|
|
81
|
+
if (!normalizedRequest.route) {
|
|
82
|
+
const route = resolveExpressRoute(req);
|
|
83
|
+
if (route) {
|
|
84
|
+
normalizedRequest.route = route;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (requestCapture && requestCapture.read) {
|
|
88
|
+
normalizedRequest.body = (0, import_internal.makeCapturedBody)(
|
|
89
|
+
requestCapture.buffer.bytes(),
|
|
90
|
+
requestCapture.buffer.totalBytes(),
|
|
91
|
+
requestCapture.buffer.truncated(),
|
|
92
|
+
capture.requestBody === "text" ? "text" : "base64"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const responseHeaders = recorder.headersSnapshot(res.getHeaders());
|
|
96
|
+
const recordedStatus = recorder.statusCode() ?? res.statusCode;
|
|
97
|
+
const statusCode = capturedError && !recorder.hasWrittenHeader() ? 500 : recordedStatus;
|
|
98
|
+
const isUpgrade = (0, import_internal.isWebsocketUpgrade)(
|
|
99
|
+
statusCode ?? 0,
|
|
100
|
+
normalizedRequest.headers,
|
|
101
|
+
responseHeaders
|
|
102
|
+
);
|
|
103
|
+
const responseBody = recorder.bodyCaptured() && !isUpgrade ? (0, import_internal.makeCapturedBody)(
|
|
104
|
+
recorder.body(),
|
|
105
|
+
recorder.totalBytes(),
|
|
106
|
+
recorder.truncated(),
|
|
107
|
+
capture.responseBody === "text" ? "text" : "base64"
|
|
108
|
+
) : void 0;
|
|
109
|
+
const normalizedResponse = {
|
|
110
|
+
statusCode: statusCode ?? void 0,
|
|
111
|
+
headers: responseHeaders,
|
|
112
|
+
body: responseBody,
|
|
113
|
+
endTimeMs: Date.now()
|
|
114
|
+
};
|
|
115
|
+
const log = xray.endRequest(ctx, normalizedResponse, capturedError);
|
|
116
|
+
if (capturedError && options?.onError && !onErrorCalled) {
|
|
117
|
+
onErrorCalled = true;
|
|
118
|
+
try {
|
|
119
|
+
options.onError(ctx, capturedError);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
(0, import_internal.logWithLevel)(xray.config.logger, "warn", xray.config.logLevel, "xray: onError failed", {
|
|
122
|
+
error: err instanceof Error ? err.message : String(err)
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (options?.onResponse) {
|
|
127
|
+
try {
|
|
128
|
+
options.onResponse(ctx, log);
|
|
129
|
+
} catch (err) {
|
|
130
|
+
(0, import_internal.logWithLevel)(
|
|
131
|
+
xray.config.logger,
|
|
132
|
+
"warn",
|
|
133
|
+
xray.config.logLevel,
|
|
134
|
+
"xray: onResponse failed",
|
|
135
|
+
{
|
|
136
|
+
error: err instanceof Error ? err.message : String(err)
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
res.once("finish", finish);
|
|
143
|
+
res.once("close", finish);
|
|
144
|
+
try {
|
|
145
|
+
const result = handler(req, res);
|
|
146
|
+
if (result && typeof result.catch === "function") {
|
|
147
|
+
void result.catch((err) => {
|
|
148
|
+
capturedError = err;
|
|
149
|
+
if (options?.onError && !onErrorCalled) {
|
|
150
|
+
onErrorCalled = true;
|
|
151
|
+
try {
|
|
152
|
+
options.onError(ctx, err);
|
|
153
|
+
} catch (errInner) {
|
|
154
|
+
(0, import_internal.logWithLevel)(
|
|
155
|
+
xray.config.logger,
|
|
156
|
+
"warn",
|
|
157
|
+
xray.config.logLevel,
|
|
158
|
+
"xray: onError failed",
|
|
159
|
+
{
|
|
160
|
+
error: errInner instanceof Error ? errInner.message : String(errInner)
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
} catch (err) {
|
|
168
|
+
capturedError = err;
|
|
169
|
+
if (options?.onError && !onErrorCalled) {
|
|
170
|
+
onErrorCalled = true;
|
|
171
|
+
try {
|
|
172
|
+
options.onError(ctx, err);
|
|
173
|
+
} catch (errInner) {
|
|
174
|
+
(0, import_internal.logWithLevel)(xray.config.logger, "warn", xray.config.logLevel, "xray: onError failed", {
|
|
175
|
+
error: errInner instanceof Error ? errInner.message : String(errInner)
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
throw err;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function getXrayContext(req) {
|
|
184
|
+
return (0, import_internal.getXrayContextFromObject)(req);
|
|
185
|
+
}
|
|
186
|
+
function wrapRequestBody(req, limit) {
|
|
187
|
+
if (limit <= 0) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
if (!hasRequestBody(req)) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const capture = {
|
|
194
|
+
buffer: new import_internal.LimitedBuffer(limit),
|
|
195
|
+
read: false,
|
|
196
|
+
userConsuming: false
|
|
197
|
+
};
|
|
198
|
+
const originalPush = req.push;
|
|
199
|
+
req.push = function push(chunk, encoding) {
|
|
200
|
+
if (chunk != null) {
|
|
201
|
+
recordChunk(capture, chunk, encoding);
|
|
202
|
+
}
|
|
203
|
+
return originalPush.call(req, chunk, encoding);
|
|
204
|
+
};
|
|
205
|
+
const originalEmit = req.emit;
|
|
206
|
+
req.emit = function emit(event, ...args) {
|
|
207
|
+
if (event === "data" && capture.userConsuming && args[0] != null) {
|
|
208
|
+
capture.read = true;
|
|
209
|
+
}
|
|
210
|
+
if (event === "end" && capture.userConsuming) {
|
|
211
|
+
capture.read = true;
|
|
212
|
+
}
|
|
213
|
+
return originalEmit.call(req, event, ...args);
|
|
214
|
+
};
|
|
215
|
+
const originalOn = req.on;
|
|
216
|
+
req.on = function on(event, listener) {
|
|
217
|
+
if (event === "data" || event === "readable") {
|
|
218
|
+
capture.userConsuming = true;
|
|
219
|
+
}
|
|
220
|
+
return originalOn.call(req, event, listener);
|
|
221
|
+
};
|
|
222
|
+
const originalOnce = req.once;
|
|
223
|
+
req.once = function once(event, listener) {
|
|
224
|
+
if (event === "data" || event === "readable") {
|
|
225
|
+
capture.userConsuming = true;
|
|
226
|
+
}
|
|
227
|
+
return originalOnce.call(req, event, listener);
|
|
228
|
+
};
|
|
229
|
+
const originalAddListener = req.addListener;
|
|
230
|
+
req.addListener = function addListener(event, listener) {
|
|
231
|
+
if (event === "data" || event === "readable") {
|
|
232
|
+
capture.userConsuming = true;
|
|
233
|
+
}
|
|
234
|
+
return originalAddListener.call(req, event, listener);
|
|
235
|
+
};
|
|
236
|
+
const originalPipe = req.pipe;
|
|
237
|
+
req.pipe = function pipe(destination, options) {
|
|
238
|
+
capture.userConsuming = true;
|
|
239
|
+
return originalPipe.call(req, destination, options);
|
|
240
|
+
};
|
|
241
|
+
const originalRead = req.read;
|
|
242
|
+
req.read = function read(size) {
|
|
243
|
+
capture.userConsuming = true;
|
|
244
|
+
const chunk = originalRead.call(req, size);
|
|
245
|
+
const readableFlowing = req.readableFlowing;
|
|
246
|
+
const hasDataListeners = typeof req.listenerCount === "function" && req.listenerCount("data") > 0;
|
|
247
|
+
if (!hasDataListeners && readableFlowing !== true && chunk != null) {
|
|
248
|
+
capture.read = true;
|
|
249
|
+
}
|
|
250
|
+
return chunk;
|
|
251
|
+
};
|
|
252
|
+
return capture;
|
|
253
|
+
}
|
|
254
|
+
function hasRequestBody(req) {
|
|
255
|
+
if (req.headers["content-length"] != null) {
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
if (req.headers["transfer-encoding"] != null) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
function recordChunk(capture, chunk, encoding) {
|
|
264
|
+
const bytes = toBytes(chunk, encoding);
|
|
265
|
+
if (!bytes) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
capture.buffer.write(bytes);
|
|
269
|
+
}
|
|
270
|
+
function toBytes(chunk, encoding) {
|
|
271
|
+
if (chunk == null) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
if (typeof chunk === "string") {
|
|
275
|
+
return Buffer.from(chunk, encoding);
|
|
276
|
+
}
|
|
277
|
+
if (chunk instanceof Uint8Array) {
|
|
278
|
+
return chunk;
|
|
279
|
+
}
|
|
280
|
+
if (chunk instanceof ArrayBuffer) {
|
|
281
|
+
return new Uint8Array(chunk);
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
var ResponseRecorder = class {
|
|
286
|
+
constructor(captureBody, maxBodySize) {
|
|
287
|
+
this.wroteHeader = false;
|
|
288
|
+
this.bytes = 0;
|
|
289
|
+
this.buffer = captureBody ? new import_internal.LimitedBuffer(maxBodySize) : null;
|
|
290
|
+
}
|
|
291
|
+
body() {
|
|
292
|
+
return this.buffer?.bytes() ?? new Uint8Array();
|
|
293
|
+
}
|
|
294
|
+
totalBytes() {
|
|
295
|
+
return this.buffer?.totalBytes() ?? 0;
|
|
296
|
+
}
|
|
297
|
+
bodyCaptured() {
|
|
298
|
+
return !!this.buffer && this.buffer.totalBytes() > 0;
|
|
299
|
+
}
|
|
300
|
+
bytesWritten() {
|
|
301
|
+
return this.bytes;
|
|
302
|
+
}
|
|
303
|
+
hasWrittenHeader() {
|
|
304
|
+
return this.wroteHeader;
|
|
305
|
+
}
|
|
306
|
+
headersSnapshot(defaultHeaders) {
|
|
307
|
+
if (this.headerSnapshot) {
|
|
308
|
+
return (0, import_internal.headerValuesFromNodeHeaders)(this.headerSnapshot);
|
|
309
|
+
}
|
|
310
|
+
return (0, import_internal.headerValuesFromNodeHeaders)(defaultHeaders);
|
|
311
|
+
}
|
|
312
|
+
statusCode() {
|
|
313
|
+
return this.status;
|
|
314
|
+
}
|
|
315
|
+
truncated() {
|
|
316
|
+
return this.buffer?.truncated() ?? false;
|
|
317
|
+
}
|
|
318
|
+
wrap(res) {
|
|
319
|
+
const originalWriteHead = res.writeHead;
|
|
320
|
+
res.writeHead = ((statusCode, ...args) => {
|
|
321
|
+
this.recordHeader(res, statusCode);
|
|
322
|
+
return originalWriteHead.call(res, statusCode, ...args);
|
|
323
|
+
});
|
|
324
|
+
const originalWrite = res.write;
|
|
325
|
+
res.write = ((chunk, encoding, cb) => {
|
|
326
|
+
this.recordHeader(res, res.statusCode ?? 200);
|
|
327
|
+
this.recordWrite(chunk, encoding);
|
|
328
|
+
return originalWrite.call(res, chunk, encoding, cb);
|
|
329
|
+
});
|
|
330
|
+
const originalEnd = res.end;
|
|
331
|
+
res.end = ((chunk, encoding, cb) => {
|
|
332
|
+
this.recordHeader(res, res.statusCode ?? 200);
|
|
333
|
+
if (chunk) {
|
|
334
|
+
this.recordWrite(chunk, encoding);
|
|
335
|
+
}
|
|
336
|
+
return originalEnd.call(res, chunk, encoding, cb);
|
|
337
|
+
});
|
|
338
|
+
if (typeof res.flushHeaders === "function") {
|
|
339
|
+
const originalFlush = res.flushHeaders;
|
|
340
|
+
res.flushHeaders = (() => {
|
|
341
|
+
this.recordHeader(res, res.statusCode ?? 200);
|
|
342
|
+
return originalFlush.call(res);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
recordHeader(res, statusCode) {
|
|
347
|
+
if (this.wroteHeader) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
this.wroteHeader = true;
|
|
351
|
+
this.status = statusCode;
|
|
352
|
+
this.headerSnapshot = { ...res.getHeaders() };
|
|
353
|
+
}
|
|
354
|
+
recordWrite(chunk, encoding) {
|
|
355
|
+
const bytes = toBytes(chunk, encoding);
|
|
356
|
+
if (!bytes) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
this.bytes += bytes.length;
|
|
360
|
+
if (this.buffer) {
|
|
361
|
+
this.buffer.write(bytes);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
function resolveRequestId(explicit, req, xray) {
|
|
366
|
+
if (explicit) {
|
|
367
|
+
return explicit;
|
|
368
|
+
}
|
|
369
|
+
const headerName = xray.config.requestId.header.toLowerCase();
|
|
370
|
+
const value = req.headers[headerName];
|
|
371
|
+
if (!value) {
|
|
372
|
+
return void 0;
|
|
373
|
+
}
|
|
374
|
+
if (Array.isArray(value)) {
|
|
375
|
+
return value[0]?.trim() || void 0;
|
|
376
|
+
}
|
|
377
|
+
return `${value}`.trim() || void 0;
|
|
378
|
+
}
|
|
379
|
+
function fullUrl(req) {
|
|
380
|
+
if (!req.url) {
|
|
381
|
+
return "";
|
|
382
|
+
}
|
|
383
|
+
if (req.url.startsWith("http://") || req.url.startsWith("https://")) {
|
|
384
|
+
return req.url;
|
|
385
|
+
}
|
|
386
|
+
const host = req.headers["host"];
|
|
387
|
+
if (!host || typeof host !== "string") {
|
|
388
|
+
return req.url;
|
|
389
|
+
}
|
|
390
|
+
const scheme = req.socket instanceof import_node_tls.TLSSocket ? "https" : "http";
|
|
391
|
+
return `${scheme}://${host}${req.url}`;
|
|
392
|
+
}
|
|
393
|
+
var expressParamsHistory = /* @__PURE__ */ new WeakMap();
|
|
394
|
+
function trackExpressParams(req) {
|
|
395
|
+
if (expressParamsHistory.has(req)) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
const anyReq = req;
|
|
399
|
+
if (typeof anyReq.app !== "function") {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const history = [];
|
|
403
|
+
expressParamsHistory.set(req, history);
|
|
404
|
+
const descriptor = Object.getOwnPropertyDescriptor(req, "params");
|
|
405
|
+
if (descriptor && !descriptor.configurable) {
|
|
406
|
+
if (descriptor.value && typeof descriptor.value === "object") {
|
|
407
|
+
history.push({ ...descriptor.value });
|
|
408
|
+
}
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
let current = descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
412
|
+
if (current && typeof current === "object") {
|
|
413
|
+
history.push({ ...current });
|
|
414
|
+
}
|
|
415
|
+
Object.defineProperty(req, "params", {
|
|
416
|
+
configurable: true,
|
|
417
|
+
enumerable: descriptor?.enumerable ?? true,
|
|
418
|
+
get() {
|
|
419
|
+
return current;
|
|
420
|
+
},
|
|
421
|
+
set(value) {
|
|
422
|
+
current = value;
|
|
423
|
+
if (value && typeof value === "object") {
|
|
424
|
+
history.push({ ...value });
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
function resolveExpressRoute(req) {
|
|
430
|
+
const anyReq = req;
|
|
431
|
+
const routePath = extractExpressRoutePath(anyReq.route?.path);
|
|
432
|
+
const baseUrl = anyReq.baseUrl ?? "";
|
|
433
|
+
if (!routePath && !baseUrl) {
|
|
434
|
+
return void 0;
|
|
435
|
+
}
|
|
436
|
+
const params = collectExpressParams(req, anyReq.params);
|
|
437
|
+
const resolvedBaseUrl = replaceBaseUrlParams(baseUrl, params, routePath);
|
|
438
|
+
return joinExpressRoute(resolvedBaseUrl, routePath);
|
|
439
|
+
}
|
|
440
|
+
function extractExpressRoutePath(path) {
|
|
441
|
+
if (typeof path === "string") {
|
|
442
|
+
return path;
|
|
443
|
+
}
|
|
444
|
+
if (Array.isArray(path)) {
|
|
445
|
+
for (const entry of path) {
|
|
446
|
+
if (typeof entry === "string") {
|
|
447
|
+
return entry;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return void 0;
|
|
452
|
+
}
|
|
453
|
+
function collectExpressParams(req, fallback) {
|
|
454
|
+
const history = expressParamsHistory.get(req);
|
|
455
|
+
if (!history || history.length === 0) {
|
|
456
|
+
return fallback ?? {};
|
|
457
|
+
}
|
|
458
|
+
const merged = {};
|
|
459
|
+
for (const snapshot of history) {
|
|
460
|
+
for (const [key, value] of Object.entries(snapshot)) {
|
|
461
|
+
if (!(key in merged)) {
|
|
462
|
+
merged[key] = value;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (fallback) {
|
|
467
|
+
for (const [key, value] of Object.entries(fallback)) {
|
|
468
|
+
if (!(key in merged)) {
|
|
469
|
+
merged[key] = value;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return merged;
|
|
474
|
+
}
|
|
475
|
+
function replaceBaseUrlParams(baseUrl, params, routePath) {
|
|
476
|
+
if (!baseUrl) {
|
|
477
|
+
return baseUrl;
|
|
478
|
+
}
|
|
479
|
+
const entries = Object.entries(params);
|
|
480
|
+
if (entries.length === 0) {
|
|
481
|
+
return baseUrl;
|
|
482
|
+
}
|
|
483
|
+
const excluded = new Set(routePath ? extractExpressParamNames(routePath) : []);
|
|
484
|
+
const replacements = entries.filter(([name]) => !excluded.has(name)).map(([name, value]) => ({ name, value: Array.isArray(value) ? value[0] : value })).filter((entry) => !!entry.value);
|
|
485
|
+
if (replacements.length === 0) {
|
|
486
|
+
return baseUrl;
|
|
487
|
+
}
|
|
488
|
+
const used = /* @__PURE__ */ new Set();
|
|
489
|
+
const encodedCache = /* @__PURE__ */ new Map();
|
|
490
|
+
const segments = baseUrl.split("/");
|
|
491
|
+
const updated = segments.map((segment) => {
|
|
492
|
+
if (!segment) {
|
|
493
|
+
return segment;
|
|
494
|
+
}
|
|
495
|
+
for (const { name, value } of replacements) {
|
|
496
|
+
if (used.has(name)) {
|
|
497
|
+
continue;
|
|
498
|
+
}
|
|
499
|
+
const encodedValue = encodedCache.get(value) ?? encodeURIComponent(value);
|
|
500
|
+
encodedCache.set(value, encodedValue);
|
|
501
|
+
if (segment === value || segment === encodedValue) {
|
|
502
|
+
used.add(name);
|
|
503
|
+
return `:${name}`;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return segment;
|
|
507
|
+
});
|
|
508
|
+
return updated.join("/");
|
|
509
|
+
}
|
|
510
|
+
function extractExpressParamNames(path) {
|
|
511
|
+
const names = [];
|
|
512
|
+
const paramPattern = /:([A-Za-z0-9_]+)(?:\([^)]*\))?[?*+]?/g;
|
|
513
|
+
for (const match of path.matchAll(paramPattern)) {
|
|
514
|
+
const name = match[1];
|
|
515
|
+
if (name) {
|
|
516
|
+
names.push(name);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return names;
|
|
520
|
+
}
|
|
521
|
+
function joinExpressRoute(baseUrl, routePath) {
|
|
522
|
+
const base = baseUrl ? ensureLeadingSlash(baseUrl) : "";
|
|
523
|
+
const route = routePath ? ensureLeadingSlash(routePath) : "";
|
|
524
|
+
if (!base) {
|
|
525
|
+
return route || "/";
|
|
526
|
+
}
|
|
527
|
+
if (!route || route === "/") {
|
|
528
|
+
return base;
|
|
529
|
+
}
|
|
530
|
+
const trimmedBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
531
|
+
return `${trimmedBase}${route}`;
|
|
532
|
+
}
|
|
533
|
+
function ensureLeadingSlash(path) {
|
|
534
|
+
if (!path) {
|
|
535
|
+
return "/";
|
|
536
|
+
}
|
|
537
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
538
|
+
}
|
|
539
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
540
|
+
0 && (module.exports = {
|
|
541
|
+
getXrayContext,
|
|
542
|
+
wrapHttpHandler
|
|
543
|
+
});
|
|
544
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/adapter.ts"],"sourcesContent":["export { wrapHttpHandler, getXrayContext } from './adapter';\nexport type { WrapOptions, NodeHttpHandler } from './adapter';\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { TLSSocket } from 'node:tls';\nimport type {\n CaptureConfig,\n NormalizedRequest,\n NormalizedResponse,\n RedactionConfig,\n RequestLog,\n XrayContext,\n XrayEmitter,\n} from '@stainlessdev/xray-core';\nimport {\n LimitedBuffer,\n bindContextToObject,\n getXrayContextFromObject,\n headerValuesFromNodeHeaders,\n isWebsocketUpgrade,\n logWithLevel,\n makeCapturedBody,\n setCaptureOverride,\n setContextRequestId,\n setContextRoute,\n setRedactionOverride,\n} from '@stainlessdev/xray-core/internal';\n\nexport type NodeHttpHandler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;\n\nexport interface WrapOptions {\n route?: string;\n requestId?: string;\n capture?: Partial<CaptureConfig>;\n redaction?: Partial<RedactionConfig>;\n onRequest?: (ctx: XrayContext) => void;\n onResponse?: (ctx: XrayContext, log: RequestLog) => void;\n onError?: (ctx: XrayContext, err: unknown) => void;\n}\n\nexport function wrapHttpHandler(\n handler: NodeHttpHandler,\n xray: XrayEmitter,\n options?: WrapOptions,\n): NodeHttpHandler {\n return (req, res) => {\n const normalizedRequest: NormalizedRequest = {\n method: req.method ?? 'GET',\n url: fullUrl(req),\n route: options?.route,\n headers: headerValuesFromNodeHeaders(\n req.headers as Record<string, string | string[] | number | undefined>,\n ),\n requestId: resolveRequestId(options?.requestId, req, xray),\n remoteAddress: req.socket?.remoteAddress,\n startTimeMs: Date.now(),\n };\n\n trackExpressParams(req);\n\n const ctx = xray.startRequest(normalizedRequest);\n bindContextToObject(req, ctx);\n bindContextToObject(res, ctx);\n\n if (options?.requestId) {\n setContextRequestId(ctx, options.requestId);\n }\n if (options?.route) {\n setContextRoute(ctx, options.route);\n }\n if (options?.capture) {\n setCaptureOverride(ctx, options.capture);\n }\n if (options?.redaction) {\n setRedactionOverride(ctx, options.redaction);\n }\n\n if (options?.onRequest) {\n try {\n options.onRequest(ctx);\n } catch (err) {\n logWithLevel(xray.config.logger, 'warn', xray.config.logLevel, 'xray: onRequest failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const capture = options?.capture\n ? { ...xray.config.capture, ...options.capture }\n : xray.config.capture;\n\n const requestCapture =\n capture.requestBody === 'none' ? null : wrapRequestBody(req, capture.maxBodyBytes);\n const recorder = new ResponseRecorder(capture.responseBody !== 'none', capture.maxBodyBytes);\n recorder.wrap(res);\n\n let finished = false;\n let capturedError: unknown;\n let onErrorCalled = false;\n\n const finish = () => {\n if (finished) {\n return;\n }\n finished = true;\n if (!normalizedRequest.route) {\n const route = resolveExpressRoute(req);\n if (route) {\n normalizedRequest.route = route;\n }\n }\n\n if (requestCapture && requestCapture.read) {\n normalizedRequest.body = makeCapturedBody(\n requestCapture.buffer.bytes(),\n requestCapture.buffer.totalBytes(),\n requestCapture.buffer.truncated(),\n capture.requestBody === 'text' ? 'text' : 'base64',\n );\n }\n\n const responseHeaders = recorder.headersSnapshot(res.getHeaders());\n const recordedStatus = recorder.statusCode() ?? res.statusCode;\n const statusCode = capturedError && !recorder.hasWrittenHeader() ? 500 : recordedStatus;\n const isUpgrade = isWebsocketUpgrade(\n statusCode ?? 0,\n normalizedRequest.headers,\n responseHeaders,\n );\n\n const responseBody =\n recorder.bodyCaptured() && !isUpgrade\n ? makeCapturedBody(\n recorder.body(),\n recorder.totalBytes(),\n recorder.truncated(),\n capture.responseBody === 'text' ? 'text' : 'base64',\n )\n : undefined;\n\n const normalizedResponse: NormalizedResponse = {\n statusCode: statusCode ?? undefined,\n headers: responseHeaders,\n body: responseBody,\n endTimeMs: Date.now(),\n };\n\n const log = xray.endRequest(ctx, normalizedResponse, capturedError);\n\n if (capturedError && options?.onError && !onErrorCalled) {\n onErrorCalled = true;\n try {\n options.onError(ctx, capturedError);\n } catch (err) {\n logWithLevel(xray.config.logger, 'warn', xray.config.logLevel, 'xray: onError failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n if (options?.onResponse) {\n try {\n options.onResponse(ctx, log);\n } catch (err) {\n logWithLevel(\n xray.config.logger,\n 'warn',\n xray.config.logLevel,\n 'xray: onResponse failed',\n {\n error: err instanceof Error ? err.message : String(err),\n },\n );\n }\n }\n };\n\n res.once('finish', finish);\n res.once('close', finish);\n\n try {\n const result = handler(req, res);\n if (result && typeof (result as Promise<void>).catch === 'function') {\n void (result as Promise<void>).catch((err) => {\n capturedError = err;\n if (options?.onError && !onErrorCalled) {\n onErrorCalled = true;\n try {\n options.onError(ctx, err);\n } catch (errInner) {\n logWithLevel(\n xray.config.logger,\n 'warn',\n xray.config.logLevel,\n 'xray: onError failed',\n {\n error: errInner instanceof Error ? errInner.message : String(errInner),\n },\n );\n }\n }\n });\n }\n } catch (err) {\n capturedError = err;\n if (options?.onError && !onErrorCalled) {\n onErrorCalled = true;\n try {\n options.onError(ctx, err);\n } catch (errInner) {\n logWithLevel(xray.config.logger, 'warn', xray.config.logLevel, 'xray: onError failed', {\n error: errInner instanceof Error ? errInner.message : String(errInner),\n });\n }\n }\n throw err;\n }\n };\n}\n\nexport function getXrayContext(req: IncomingMessage): XrayContext | undefined {\n return getXrayContextFromObject(req);\n}\n\ntype RequestCapture = {\n buffer: LimitedBuffer;\n read: boolean;\n userConsuming: boolean;\n};\n\nfunction wrapRequestBody(req: IncomingMessage, limit: number): RequestCapture | null {\n if (limit <= 0) {\n return null;\n }\n if (!hasRequestBody(req)) {\n return null;\n }\n\n const capture: RequestCapture = {\n buffer: new LimitedBuffer(limit),\n read: false,\n userConsuming: false,\n };\n\n const originalPush = req.push;\n req.push = function push(chunk: unknown, encoding?: BufferEncoding): boolean {\n if (chunk != null) {\n recordChunk(capture, chunk, encoding);\n }\n return originalPush.call(req, chunk as any, encoding as any);\n } as typeof req.push;\n\n const originalEmit = req.emit;\n req.emit = function emit(event: string, ...args: unknown[]): boolean {\n if (event === 'data' && capture.userConsuming && args[0] != null) {\n capture.read = true;\n }\n if (event === 'end' && capture.userConsuming) {\n capture.read = true;\n }\n return originalEmit.call(req, event, ...args);\n } as typeof req.emit;\n\n const originalOn = req.on;\n req.on = function on(event: string, listener: (...args: any[]) => void): any {\n if (event === 'data' || event === 'readable') {\n capture.userConsuming = true;\n }\n return originalOn.call(req, event, listener);\n } as typeof req.on;\n\n const originalOnce = req.once;\n req.once = function once(event: string, listener: (...args: any[]) => void): any {\n if (event === 'data' || event === 'readable') {\n capture.userConsuming = true;\n }\n return originalOnce.call(req, event, listener);\n } as typeof req.once;\n\n const originalAddListener = req.addListener;\n req.addListener = function addListener(event: string, listener: (...args: any[]) => void): any {\n if (event === 'data' || event === 'readable') {\n capture.userConsuming = true;\n }\n return originalAddListener.call(req, event, listener);\n } as typeof req.addListener;\n\n const originalPipe = req.pipe;\n req.pipe = function pipe(destination: unknown, options?: unknown): unknown {\n capture.userConsuming = true;\n return originalPipe.call(req, destination as any, options as any);\n } as typeof req.pipe;\n\n const originalRead = req.read;\n req.read = function read(size?: number): any {\n capture.userConsuming = true;\n const chunk = originalRead.call(req, size as any) as unknown;\n const readableFlowing = (req as IncomingMessage & { readableFlowing?: boolean | null })\n .readableFlowing;\n const hasDataListeners =\n typeof req.listenerCount === 'function' && req.listenerCount('data') > 0;\n if (!hasDataListeners && readableFlowing !== true && chunk != null) {\n capture.read = true;\n }\n return chunk as any;\n } as typeof req.read;\n\n return capture;\n}\n\nfunction hasRequestBody(req: IncomingMessage): boolean {\n if (req.headers['content-length'] != null) {\n return true;\n }\n if (req.headers['transfer-encoding'] != null) {\n return true;\n }\n return false;\n}\n\nfunction recordChunk(capture: RequestCapture, chunk: unknown, encoding?: BufferEncoding): void {\n const bytes = toBytes(chunk, encoding);\n if (!bytes) {\n return;\n }\n capture.buffer.write(bytes);\n}\n\nfunction toBytes(chunk: unknown, encoding?: BufferEncoding): Uint8Array | null {\n if (chunk == null) {\n return null;\n }\n if (typeof chunk === 'string') {\n return Buffer.from(chunk, encoding);\n }\n if (chunk instanceof Uint8Array) {\n return chunk;\n }\n if (chunk instanceof ArrayBuffer) {\n return new Uint8Array(chunk);\n }\n return null;\n}\n\nclass ResponseRecorder {\n private readonly buffer: LimitedBuffer | null;\n private headerSnapshot?: Record<string, string | string[] | number | undefined>;\n private status?: number;\n private wroteHeader = false;\n private bytes = 0;\n\n constructor(captureBody: boolean, maxBodySize: number) {\n this.buffer = captureBody ? new LimitedBuffer(maxBodySize) : null;\n }\n\n body(): Uint8Array {\n return this.buffer?.bytes() ?? new Uint8Array();\n }\n\n totalBytes(): number {\n return this.buffer?.totalBytes() ?? 0;\n }\n\n bodyCaptured(): boolean {\n return !!this.buffer && this.buffer.totalBytes() > 0;\n }\n\n bytesWritten(): number {\n return this.bytes;\n }\n\n hasWrittenHeader(): boolean {\n return this.wroteHeader;\n }\n\n headersSnapshot(\n defaultHeaders: Record<string, string | string[] | number | undefined>,\n ): Record<string, string | string[]> {\n if (this.headerSnapshot) {\n return headerValuesFromNodeHeaders(this.headerSnapshot);\n }\n return headerValuesFromNodeHeaders(defaultHeaders);\n }\n\n statusCode(): number | undefined {\n return this.status;\n }\n\n truncated(): boolean {\n return this.buffer?.truncated() ?? false;\n }\n\n wrap(res: ServerResponse): void {\n const originalWriteHead = res.writeHead;\n res.writeHead = ((statusCode: number, ...args: any[]) => {\n this.recordHeader(res, statusCode);\n return (originalWriteHead as any).call(res, statusCode, ...args);\n }) as typeof res.writeHead;\n\n const originalWrite = res.write;\n res.write = ((chunk: unknown, encoding?: BufferEncoding, cb?: (err?: Error | null) => void) => {\n this.recordHeader(res, res.statusCode ?? 200);\n this.recordWrite(chunk, encoding);\n return originalWrite.call(res, chunk as any, encoding as any, cb as any);\n }) as typeof res.write;\n\n const originalEnd = res.end;\n res.end = ((chunk?: unknown, encoding?: BufferEncoding, cb?: () => void) => {\n this.recordHeader(res, res.statusCode ?? 200);\n if (chunk) {\n this.recordWrite(chunk, encoding);\n }\n return originalEnd.call(res, chunk as any, encoding as any, cb as any);\n }) as typeof res.end;\n\n if (typeof res.flushHeaders === 'function') {\n const originalFlush = res.flushHeaders;\n res.flushHeaders = (() => {\n this.recordHeader(res, res.statusCode ?? 200);\n return originalFlush.call(res);\n }) as typeof res.flushHeaders;\n }\n }\n\n private recordHeader(res: ServerResponse, statusCode: number): void {\n if (this.wroteHeader) {\n return;\n }\n this.wroteHeader = true;\n this.status = statusCode;\n this.headerSnapshot = { ...res.getHeaders() } as Record<\n string,\n string | string[] | number | undefined\n >;\n }\n\n private recordWrite(chunk: unknown, encoding?: BufferEncoding): void {\n const bytes = toBytes(chunk, encoding);\n if (!bytes) {\n return;\n }\n this.bytes += bytes.length;\n if (this.buffer) {\n this.buffer.write(bytes);\n }\n }\n}\n\nfunction resolveRequestId(\n explicit: string | undefined,\n req: IncomingMessage,\n xray: XrayEmitter,\n): string | undefined {\n if (explicit) {\n return explicit;\n }\n const headerName = xray.config.requestId.header.toLowerCase();\n const value = req.headers[headerName];\n if (!value) {\n return undefined;\n }\n if (Array.isArray(value)) {\n return value[0]?.trim() || undefined;\n }\n return `${value}`.trim() || undefined;\n}\n\nfunction fullUrl(req: IncomingMessage): string {\n if (!req.url) {\n return '';\n }\n if (req.url.startsWith('http://') || req.url.startsWith('https://')) {\n return req.url;\n }\n\n const host = req.headers['host'];\n if (!host || typeof host !== 'string') {\n return req.url;\n }\n const scheme = req.socket instanceof TLSSocket ? 'https' : 'http';\n return `${scheme}://${host}${req.url}`;\n}\n\ntype ExpressRoutePath = string | string[] | RegExp;\n\ntype ExpressRouteParams = Record<string, string | string[]>;\n\nconst expressParamsHistory = new WeakMap<IncomingMessage, ExpressRouteParams[]>();\n\nfunction trackExpressParams(req: IncomingMessage): void {\n if (expressParamsHistory.has(req)) {\n return;\n }\n const anyReq = req as IncomingMessage & { app?: unknown };\n if (typeof anyReq.app !== 'function') {\n return;\n }\n\n const history: ExpressRouteParams[] = [];\n expressParamsHistory.set(req, history);\n\n const descriptor = Object.getOwnPropertyDescriptor(req, 'params');\n if (descriptor && !descriptor.configurable) {\n if (descriptor.value && typeof descriptor.value === 'object') {\n history.push({ ...(descriptor.value as ExpressRouteParams) });\n }\n return;\n }\n\n let current = (\n descriptor && 'value' in descriptor\n ? (descriptor.value as ExpressRouteParams | undefined)\n : undefined\n ) as ExpressRouteParams | undefined;\n if (current && typeof current === 'object') {\n history.push({ ...current });\n }\n\n Object.defineProperty(req, 'params', {\n configurable: true,\n enumerable: descriptor?.enumerable ?? true,\n get() {\n return current;\n },\n set(value) {\n current = value as ExpressRouteParams | undefined;\n if (value && typeof value === 'object') {\n history.push({ ...(value as ExpressRouteParams) });\n }\n },\n });\n}\n\nfunction resolveExpressRoute(req: IncomingMessage): string | undefined {\n const anyReq = req as IncomingMessage & {\n baseUrl?: string;\n params?: ExpressRouteParams;\n route?: { path?: ExpressRoutePath };\n };\n const routePath = extractExpressRoutePath(anyReq.route?.path);\n const baseUrl = anyReq.baseUrl ?? '';\n if (!routePath && !baseUrl) {\n return undefined;\n }\n\n const params = collectExpressParams(req, anyReq.params);\n const resolvedBaseUrl = replaceBaseUrlParams(baseUrl, params, routePath);\n return joinExpressRoute(resolvedBaseUrl, routePath);\n}\n\nfunction extractExpressRoutePath(path?: ExpressRoutePath): string | undefined {\n if (typeof path === 'string') {\n return path;\n }\n if (Array.isArray(path)) {\n for (const entry of path) {\n if (typeof entry === 'string') {\n return entry;\n }\n }\n }\n return undefined;\n}\n\nfunction collectExpressParams(\n req: IncomingMessage,\n fallback?: ExpressRouteParams,\n): ExpressRouteParams {\n const history = expressParamsHistory.get(req);\n if (!history || history.length === 0) {\n return fallback ?? {};\n }\n\n const merged: ExpressRouteParams = {};\n for (const snapshot of history) {\n for (const [key, value] of Object.entries(snapshot)) {\n if (!(key in merged)) {\n merged[key] = value;\n }\n }\n }\n if (fallback) {\n for (const [key, value] of Object.entries(fallback)) {\n if (!(key in merged)) {\n merged[key] = value;\n }\n }\n }\n return merged;\n}\n\nfunction replaceBaseUrlParams(\n baseUrl: string,\n params: ExpressRouteParams,\n routePath?: string,\n): string {\n if (!baseUrl) {\n return baseUrl;\n }\n const entries = Object.entries(params);\n if (entries.length === 0) {\n return baseUrl;\n }\n\n const excluded = new Set(routePath ? extractExpressParamNames(routePath) : []);\n const replacements = entries\n .filter(([name]) => !excluded.has(name))\n .map(([name, value]) => ({ name, value: Array.isArray(value) ? value[0] : value }))\n .filter((entry): entry is { name: string; value: string } => !!entry.value);\n\n if (replacements.length === 0) {\n return baseUrl;\n }\n\n const used = new Set<string>();\n const encodedCache = new Map<string, string>();\n const segments = baseUrl.split('/');\n const updated = segments.map((segment) => {\n if (!segment) {\n return segment;\n }\n for (const { name, value } of replacements) {\n if (used.has(name)) {\n continue;\n }\n const encodedValue = encodedCache.get(value) ?? encodeURIComponent(value);\n encodedCache.set(value, encodedValue);\n if (segment === value || segment === encodedValue) {\n used.add(name);\n return `:${name}`;\n }\n }\n return segment;\n });\n\n return updated.join('/');\n}\n\nfunction extractExpressParamNames(path: string): string[] {\n const names: string[] = [];\n const paramPattern = /:([A-Za-z0-9_]+)(?:\\([^)]*\\))?[?*+]?/g;\n for (const match of path.matchAll(paramPattern)) {\n const name = match[1];\n if (name) {\n names.push(name);\n }\n }\n return names;\n}\n\nfunction joinExpressRoute(baseUrl: string, routePath?: string): string {\n const base = baseUrl ? ensureLeadingSlash(baseUrl) : '';\n const route = routePath ? ensureLeadingSlash(routePath) : '';\n if (!base) {\n return route || '/';\n }\n if (!route || route === '/') {\n return base;\n }\n const trimmedBase = base.endsWith('/') ? base.slice(0, -1) : base;\n return `${trimmedBase}${route}`;\n}\n\nfunction ensureLeadingSlash(path: string): string {\n if (!path) {\n return '/';\n }\n return path.startsWith('/') ? path : `/${path}`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { XrayEmitter, CaptureConfig, RedactionConfig, XrayContext, RequestLog } from '@stainlessdev/xray-core';
|
|
3
|
+
|
|
4
|
+
type NodeHttpHandler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
5
|
+
interface WrapOptions {
|
|
6
|
+
route?: string;
|
|
7
|
+
requestId?: string;
|
|
8
|
+
capture?: Partial<CaptureConfig>;
|
|
9
|
+
redaction?: Partial<RedactionConfig>;
|
|
10
|
+
onRequest?: (ctx: XrayContext) => void;
|
|
11
|
+
onResponse?: (ctx: XrayContext, log: RequestLog) => void;
|
|
12
|
+
onError?: (ctx: XrayContext, err: unknown) => void;
|
|
13
|
+
}
|
|
14
|
+
declare function wrapHttpHandler(handler: NodeHttpHandler, xray: XrayEmitter, options?: WrapOptions): NodeHttpHandler;
|
|
15
|
+
declare function getXrayContext(req: IncomingMessage): XrayContext | undefined;
|
|
16
|
+
|
|
17
|
+
export { type NodeHttpHandler, type WrapOptions, getXrayContext, wrapHttpHandler };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { XrayEmitter, CaptureConfig, RedactionConfig, XrayContext, RequestLog } from '@stainlessdev/xray-core';
|
|
3
|
+
|
|
4
|
+
type NodeHttpHandler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
5
|
+
interface WrapOptions {
|
|
6
|
+
route?: string;
|
|
7
|
+
requestId?: string;
|
|
8
|
+
capture?: Partial<CaptureConfig>;
|
|
9
|
+
redaction?: Partial<RedactionConfig>;
|
|
10
|
+
onRequest?: (ctx: XrayContext) => void;
|
|
11
|
+
onResponse?: (ctx: XrayContext, log: RequestLog) => void;
|
|
12
|
+
onError?: (ctx: XrayContext, err: unknown) => void;
|
|
13
|
+
}
|
|
14
|
+
declare function wrapHttpHandler(handler: NodeHttpHandler, xray: XrayEmitter, options?: WrapOptions): NodeHttpHandler;
|
|
15
|
+
declare function getXrayContext(req: IncomingMessage): XrayContext | undefined;
|
|
16
|
+
|
|
17
|
+
export { type NodeHttpHandler, type WrapOptions, getXrayContext, wrapHttpHandler };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
// src/adapter.ts
|
|
2
|
+
import { TLSSocket } from "tls";
|
|
3
|
+
import {
|
|
4
|
+
LimitedBuffer,
|
|
5
|
+
bindContextToObject,
|
|
6
|
+
getXrayContextFromObject,
|
|
7
|
+
headerValuesFromNodeHeaders,
|
|
8
|
+
isWebsocketUpgrade,
|
|
9
|
+
logWithLevel,
|
|
10
|
+
makeCapturedBody,
|
|
11
|
+
setCaptureOverride,
|
|
12
|
+
setContextRequestId,
|
|
13
|
+
setContextRoute,
|
|
14
|
+
setRedactionOverride
|
|
15
|
+
} from "@stainlessdev/xray-core/internal";
|
|
16
|
+
function wrapHttpHandler(handler, xray, options) {
|
|
17
|
+
return (req, res) => {
|
|
18
|
+
const normalizedRequest = {
|
|
19
|
+
method: req.method ?? "GET",
|
|
20
|
+
url: fullUrl(req),
|
|
21
|
+
route: options?.route,
|
|
22
|
+
headers: headerValuesFromNodeHeaders(
|
|
23
|
+
req.headers
|
|
24
|
+
),
|
|
25
|
+
requestId: resolveRequestId(options?.requestId, req, xray),
|
|
26
|
+
remoteAddress: req.socket?.remoteAddress,
|
|
27
|
+
startTimeMs: Date.now()
|
|
28
|
+
};
|
|
29
|
+
trackExpressParams(req);
|
|
30
|
+
const ctx = xray.startRequest(normalizedRequest);
|
|
31
|
+
bindContextToObject(req, ctx);
|
|
32
|
+
bindContextToObject(res, ctx);
|
|
33
|
+
if (options?.requestId) {
|
|
34
|
+
setContextRequestId(ctx, options.requestId);
|
|
35
|
+
}
|
|
36
|
+
if (options?.route) {
|
|
37
|
+
setContextRoute(ctx, options.route);
|
|
38
|
+
}
|
|
39
|
+
if (options?.capture) {
|
|
40
|
+
setCaptureOverride(ctx, options.capture);
|
|
41
|
+
}
|
|
42
|
+
if (options?.redaction) {
|
|
43
|
+
setRedactionOverride(ctx, options.redaction);
|
|
44
|
+
}
|
|
45
|
+
if (options?.onRequest) {
|
|
46
|
+
try {
|
|
47
|
+
options.onRequest(ctx);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
logWithLevel(xray.config.logger, "warn", xray.config.logLevel, "xray: onRequest failed", {
|
|
50
|
+
error: err instanceof Error ? err.message : String(err)
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const capture = options?.capture ? { ...xray.config.capture, ...options.capture } : xray.config.capture;
|
|
55
|
+
const requestCapture = capture.requestBody === "none" ? null : wrapRequestBody(req, capture.maxBodyBytes);
|
|
56
|
+
const recorder = new ResponseRecorder(capture.responseBody !== "none", capture.maxBodyBytes);
|
|
57
|
+
recorder.wrap(res);
|
|
58
|
+
let finished = false;
|
|
59
|
+
let capturedError;
|
|
60
|
+
let onErrorCalled = false;
|
|
61
|
+
const finish = () => {
|
|
62
|
+
if (finished) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
finished = true;
|
|
66
|
+
if (!normalizedRequest.route) {
|
|
67
|
+
const route = resolveExpressRoute(req);
|
|
68
|
+
if (route) {
|
|
69
|
+
normalizedRequest.route = route;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (requestCapture && requestCapture.read) {
|
|
73
|
+
normalizedRequest.body = makeCapturedBody(
|
|
74
|
+
requestCapture.buffer.bytes(),
|
|
75
|
+
requestCapture.buffer.totalBytes(),
|
|
76
|
+
requestCapture.buffer.truncated(),
|
|
77
|
+
capture.requestBody === "text" ? "text" : "base64"
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
const responseHeaders = recorder.headersSnapshot(res.getHeaders());
|
|
81
|
+
const recordedStatus = recorder.statusCode() ?? res.statusCode;
|
|
82
|
+
const statusCode = capturedError && !recorder.hasWrittenHeader() ? 500 : recordedStatus;
|
|
83
|
+
const isUpgrade = isWebsocketUpgrade(
|
|
84
|
+
statusCode ?? 0,
|
|
85
|
+
normalizedRequest.headers,
|
|
86
|
+
responseHeaders
|
|
87
|
+
);
|
|
88
|
+
const responseBody = recorder.bodyCaptured() && !isUpgrade ? makeCapturedBody(
|
|
89
|
+
recorder.body(),
|
|
90
|
+
recorder.totalBytes(),
|
|
91
|
+
recorder.truncated(),
|
|
92
|
+
capture.responseBody === "text" ? "text" : "base64"
|
|
93
|
+
) : void 0;
|
|
94
|
+
const normalizedResponse = {
|
|
95
|
+
statusCode: statusCode ?? void 0,
|
|
96
|
+
headers: responseHeaders,
|
|
97
|
+
body: responseBody,
|
|
98
|
+
endTimeMs: Date.now()
|
|
99
|
+
};
|
|
100
|
+
const log = xray.endRequest(ctx, normalizedResponse, capturedError);
|
|
101
|
+
if (capturedError && options?.onError && !onErrorCalled) {
|
|
102
|
+
onErrorCalled = true;
|
|
103
|
+
try {
|
|
104
|
+
options.onError(ctx, capturedError);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
logWithLevel(xray.config.logger, "warn", xray.config.logLevel, "xray: onError failed", {
|
|
107
|
+
error: err instanceof Error ? err.message : String(err)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (options?.onResponse) {
|
|
112
|
+
try {
|
|
113
|
+
options.onResponse(ctx, log);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
logWithLevel(
|
|
116
|
+
xray.config.logger,
|
|
117
|
+
"warn",
|
|
118
|
+
xray.config.logLevel,
|
|
119
|
+
"xray: onResponse failed",
|
|
120
|
+
{
|
|
121
|
+
error: err instanceof Error ? err.message : String(err)
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
res.once("finish", finish);
|
|
128
|
+
res.once("close", finish);
|
|
129
|
+
try {
|
|
130
|
+
const result = handler(req, res);
|
|
131
|
+
if (result && typeof result.catch === "function") {
|
|
132
|
+
void result.catch((err) => {
|
|
133
|
+
capturedError = err;
|
|
134
|
+
if (options?.onError && !onErrorCalled) {
|
|
135
|
+
onErrorCalled = true;
|
|
136
|
+
try {
|
|
137
|
+
options.onError(ctx, err);
|
|
138
|
+
} catch (errInner) {
|
|
139
|
+
logWithLevel(
|
|
140
|
+
xray.config.logger,
|
|
141
|
+
"warn",
|
|
142
|
+
xray.config.logLevel,
|
|
143
|
+
"xray: onError failed",
|
|
144
|
+
{
|
|
145
|
+
error: errInner instanceof Error ? errInner.message : String(errInner)
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
capturedError = err;
|
|
154
|
+
if (options?.onError && !onErrorCalled) {
|
|
155
|
+
onErrorCalled = true;
|
|
156
|
+
try {
|
|
157
|
+
options.onError(ctx, err);
|
|
158
|
+
} catch (errInner) {
|
|
159
|
+
logWithLevel(xray.config.logger, "warn", xray.config.logLevel, "xray: onError failed", {
|
|
160
|
+
error: errInner instanceof Error ? errInner.message : String(errInner)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
throw err;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function getXrayContext(req) {
|
|
169
|
+
return getXrayContextFromObject(req);
|
|
170
|
+
}
|
|
171
|
+
function wrapRequestBody(req, limit) {
|
|
172
|
+
if (limit <= 0) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
if (!hasRequestBody(req)) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
const capture = {
|
|
179
|
+
buffer: new LimitedBuffer(limit),
|
|
180
|
+
read: false,
|
|
181
|
+
userConsuming: false
|
|
182
|
+
};
|
|
183
|
+
const originalPush = req.push;
|
|
184
|
+
req.push = function push(chunk, encoding) {
|
|
185
|
+
if (chunk != null) {
|
|
186
|
+
recordChunk(capture, chunk, encoding);
|
|
187
|
+
}
|
|
188
|
+
return originalPush.call(req, chunk, encoding);
|
|
189
|
+
};
|
|
190
|
+
const originalEmit = req.emit;
|
|
191
|
+
req.emit = function emit(event, ...args) {
|
|
192
|
+
if (event === "data" && capture.userConsuming && args[0] != null) {
|
|
193
|
+
capture.read = true;
|
|
194
|
+
}
|
|
195
|
+
if (event === "end" && capture.userConsuming) {
|
|
196
|
+
capture.read = true;
|
|
197
|
+
}
|
|
198
|
+
return originalEmit.call(req, event, ...args);
|
|
199
|
+
};
|
|
200
|
+
const originalOn = req.on;
|
|
201
|
+
req.on = function on(event, listener) {
|
|
202
|
+
if (event === "data" || event === "readable") {
|
|
203
|
+
capture.userConsuming = true;
|
|
204
|
+
}
|
|
205
|
+
return originalOn.call(req, event, listener);
|
|
206
|
+
};
|
|
207
|
+
const originalOnce = req.once;
|
|
208
|
+
req.once = function once(event, listener) {
|
|
209
|
+
if (event === "data" || event === "readable") {
|
|
210
|
+
capture.userConsuming = true;
|
|
211
|
+
}
|
|
212
|
+
return originalOnce.call(req, event, listener);
|
|
213
|
+
};
|
|
214
|
+
const originalAddListener = req.addListener;
|
|
215
|
+
req.addListener = function addListener(event, listener) {
|
|
216
|
+
if (event === "data" || event === "readable") {
|
|
217
|
+
capture.userConsuming = true;
|
|
218
|
+
}
|
|
219
|
+
return originalAddListener.call(req, event, listener);
|
|
220
|
+
};
|
|
221
|
+
const originalPipe = req.pipe;
|
|
222
|
+
req.pipe = function pipe(destination, options) {
|
|
223
|
+
capture.userConsuming = true;
|
|
224
|
+
return originalPipe.call(req, destination, options);
|
|
225
|
+
};
|
|
226
|
+
const originalRead = req.read;
|
|
227
|
+
req.read = function read(size) {
|
|
228
|
+
capture.userConsuming = true;
|
|
229
|
+
const chunk = originalRead.call(req, size);
|
|
230
|
+
const readableFlowing = req.readableFlowing;
|
|
231
|
+
const hasDataListeners = typeof req.listenerCount === "function" && req.listenerCount("data") > 0;
|
|
232
|
+
if (!hasDataListeners && readableFlowing !== true && chunk != null) {
|
|
233
|
+
capture.read = true;
|
|
234
|
+
}
|
|
235
|
+
return chunk;
|
|
236
|
+
};
|
|
237
|
+
return capture;
|
|
238
|
+
}
|
|
239
|
+
function hasRequestBody(req) {
|
|
240
|
+
if (req.headers["content-length"] != null) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
if (req.headers["transfer-encoding"] != null) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
function recordChunk(capture, chunk, encoding) {
|
|
249
|
+
const bytes = toBytes(chunk, encoding);
|
|
250
|
+
if (!bytes) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
capture.buffer.write(bytes);
|
|
254
|
+
}
|
|
255
|
+
function toBytes(chunk, encoding) {
|
|
256
|
+
if (chunk == null) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
if (typeof chunk === "string") {
|
|
260
|
+
return Buffer.from(chunk, encoding);
|
|
261
|
+
}
|
|
262
|
+
if (chunk instanceof Uint8Array) {
|
|
263
|
+
return chunk;
|
|
264
|
+
}
|
|
265
|
+
if (chunk instanceof ArrayBuffer) {
|
|
266
|
+
return new Uint8Array(chunk);
|
|
267
|
+
}
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
var ResponseRecorder = class {
|
|
271
|
+
constructor(captureBody, maxBodySize) {
|
|
272
|
+
this.wroteHeader = false;
|
|
273
|
+
this.bytes = 0;
|
|
274
|
+
this.buffer = captureBody ? new LimitedBuffer(maxBodySize) : null;
|
|
275
|
+
}
|
|
276
|
+
body() {
|
|
277
|
+
return this.buffer?.bytes() ?? new Uint8Array();
|
|
278
|
+
}
|
|
279
|
+
totalBytes() {
|
|
280
|
+
return this.buffer?.totalBytes() ?? 0;
|
|
281
|
+
}
|
|
282
|
+
bodyCaptured() {
|
|
283
|
+
return !!this.buffer && this.buffer.totalBytes() > 0;
|
|
284
|
+
}
|
|
285
|
+
bytesWritten() {
|
|
286
|
+
return this.bytes;
|
|
287
|
+
}
|
|
288
|
+
hasWrittenHeader() {
|
|
289
|
+
return this.wroteHeader;
|
|
290
|
+
}
|
|
291
|
+
headersSnapshot(defaultHeaders) {
|
|
292
|
+
if (this.headerSnapshot) {
|
|
293
|
+
return headerValuesFromNodeHeaders(this.headerSnapshot);
|
|
294
|
+
}
|
|
295
|
+
return headerValuesFromNodeHeaders(defaultHeaders);
|
|
296
|
+
}
|
|
297
|
+
statusCode() {
|
|
298
|
+
return this.status;
|
|
299
|
+
}
|
|
300
|
+
truncated() {
|
|
301
|
+
return this.buffer?.truncated() ?? false;
|
|
302
|
+
}
|
|
303
|
+
wrap(res) {
|
|
304
|
+
const originalWriteHead = res.writeHead;
|
|
305
|
+
res.writeHead = ((statusCode, ...args) => {
|
|
306
|
+
this.recordHeader(res, statusCode);
|
|
307
|
+
return originalWriteHead.call(res, statusCode, ...args);
|
|
308
|
+
});
|
|
309
|
+
const originalWrite = res.write;
|
|
310
|
+
res.write = ((chunk, encoding, cb) => {
|
|
311
|
+
this.recordHeader(res, res.statusCode ?? 200);
|
|
312
|
+
this.recordWrite(chunk, encoding);
|
|
313
|
+
return originalWrite.call(res, chunk, encoding, cb);
|
|
314
|
+
});
|
|
315
|
+
const originalEnd = res.end;
|
|
316
|
+
res.end = ((chunk, encoding, cb) => {
|
|
317
|
+
this.recordHeader(res, res.statusCode ?? 200);
|
|
318
|
+
if (chunk) {
|
|
319
|
+
this.recordWrite(chunk, encoding);
|
|
320
|
+
}
|
|
321
|
+
return originalEnd.call(res, chunk, encoding, cb);
|
|
322
|
+
});
|
|
323
|
+
if (typeof res.flushHeaders === "function") {
|
|
324
|
+
const originalFlush = res.flushHeaders;
|
|
325
|
+
res.flushHeaders = (() => {
|
|
326
|
+
this.recordHeader(res, res.statusCode ?? 200);
|
|
327
|
+
return originalFlush.call(res);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
recordHeader(res, statusCode) {
|
|
332
|
+
if (this.wroteHeader) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
this.wroteHeader = true;
|
|
336
|
+
this.status = statusCode;
|
|
337
|
+
this.headerSnapshot = { ...res.getHeaders() };
|
|
338
|
+
}
|
|
339
|
+
recordWrite(chunk, encoding) {
|
|
340
|
+
const bytes = toBytes(chunk, encoding);
|
|
341
|
+
if (!bytes) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
this.bytes += bytes.length;
|
|
345
|
+
if (this.buffer) {
|
|
346
|
+
this.buffer.write(bytes);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
function resolveRequestId(explicit, req, xray) {
|
|
351
|
+
if (explicit) {
|
|
352
|
+
return explicit;
|
|
353
|
+
}
|
|
354
|
+
const headerName = xray.config.requestId.header.toLowerCase();
|
|
355
|
+
const value = req.headers[headerName];
|
|
356
|
+
if (!value) {
|
|
357
|
+
return void 0;
|
|
358
|
+
}
|
|
359
|
+
if (Array.isArray(value)) {
|
|
360
|
+
return value[0]?.trim() || void 0;
|
|
361
|
+
}
|
|
362
|
+
return `${value}`.trim() || void 0;
|
|
363
|
+
}
|
|
364
|
+
function fullUrl(req) {
|
|
365
|
+
if (!req.url) {
|
|
366
|
+
return "";
|
|
367
|
+
}
|
|
368
|
+
if (req.url.startsWith("http://") || req.url.startsWith("https://")) {
|
|
369
|
+
return req.url;
|
|
370
|
+
}
|
|
371
|
+
const host = req.headers["host"];
|
|
372
|
+
if (!host || typeof host !== "string") {
|
|
373
|
+
return req.url;
|
|
374
|
+
}
|
|
375
|
+
const scheme = req.socket instanceof TLSSocket ? "https" : "http";
|
|
376
|
+
return `${scheme}://${host}${req.url}`;
|
|
377
|
+
}
|
|
378
|
+
var expressParamsHistory = /* @__PURE__ */ new WeakMap();
|
|
379
|
+
function trackExpressParams(req) {
|
|
380
|
+
if (expressParamsHistory.has(req)) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const anyReq = req;
|
|
384
|
+
if (typeof anyReq.app !== "function") {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const history = [];
|
|
388
|
+
expressParamsHistory.set(req, history);
|
|
389
|
+
const descriptor = Object.getOwnPropertyDescriptor(req, "params");
|
|
390
|
+
if (descriptor && !descriptor.configurable) {
|
|
391
|
+
if (descriptor.value && typeof descriptor.value === "object") {
|
|
392
|
+
history.push({ ...descriptor.value });
|
|
393
|
+
}
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
let current = descriptor && "value" in descriptor ? descriptor.value : void 0;
|
|
397
|
+
if (current && typeof current === "object") {
|
|
398
|
+
history.push({ ...current });
|
|
399
|
+
}
|
|
400
|
+
Object.defineProperty(req, "params", {
|
|
401
|
+
configurable: true,
|
|
402
|
+
enumerable: descriptor?.enumerable ?? true,
|
|
403
|
+
get() {
|
|
404
|
+
return current;
|
|
405
|
+
},
|
|
406
|
+
set(value) {
|
|
407
|
+
current = value;
|
|
408
|
+
if (value && typeof value === "object") {
|
|
409
|
+
history.push({ ...value });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
function resolveExpressRoute(req) {
|
|
415
|
+
const anyReq = req;
|
|
416
|
+
const routePath = extractExpressRoutePath(anyReq.route?.path);
|
|
417
|
+
const baseUrl = anyReq.baseUrl ?? "";
|
|
418
|
+
if (!routePath && !baseUrl) {
|
|
419
|
+
return void 0;
|
|
420
|
+
}
|
|
421
|
+
const params = collectExpressParams(req, anyReq.params);
|
|
422
|
+
const resolvedBaseUrl = replaceBaseUrlParams(baseUrl, params, routePath);
|
|
423
|
+
return joinExpressRoute(resolvedBaseUrl, routePath);
|
|
424
|
+
}
|
|
425
|
+
function extractExpressRoutePath(path) {
|
|
426
|
+
if (typeof path === "string") {
|
|
427
|
+
return path;
|
|
428
|
+
}
|
|
429
|
+
if (Array.isArray(path)) {
|
|
430
|
+
for (const entry of path) {
|
|
431
|
+
if (typeof entry === "string") {
|
|
432
|
+
return entry;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return void 0;
|
|
437
|
+
}
|
|
438
|
+
function collectExpressParams(req, fallback) {
|
|
439
|
+
const history = expressParamsHistory.get(req);
|
|
440
|
+
if (!history || history.length === 0) {
|
|
441
|
+
return fallback ?? {};
|
|
442
|
+
}
|
|
443
|
+
const merged = {};
|
|
444
|
+
for (const snapshot of history) {
|
|
445
|
+
for (const [key, value] of Object.entries(snapshot)) {
|
|
446
|
+
if (!(key in merged)) {
|
|
447
|
+
merged[key] = value;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (fallback) {
|
|
452
|
+
for (const [key, value] of Object.entries(fallback)) {
|
|
453
|
+
if (!(key in merged)) {
|
|
454
|
+
merged[key] = value;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return merged;
|
|
459
|
+
}
|
|
460
|
+
function replaceBaseUrlParams(baseUrl, params, routePath) {
|
|
461
|
+
if (!baseUrl) {
|
|
462
|
+
return baseUrl;
|
|
463
|
+
}
|
|
464
|
+
const entries = Object.entries(params);
|
|
465
|
+
if (entries.length === 0) {
|
|
466
|
+
return baseUrl;
|
|
467
|
+
}
|
|
468
|
+
const excluded = new Set(routePath ? extractExpressParamNames(routePath) : []);
|
|
469
|
+
const replacements = entries.filter(([name]) => !excluded.has(name)).map(([name, value]) => ({ name, value: Array.isArray(value) ? value[0] : value })).filter((entry) => !!entry.value);
|
|
470
|
+
if (replacements.length === 0) {
|
|
471
|
+
return baseUrl;
|
|
472
|
+
}
|
|
473
|
+
const used = /* @__PURE__ */ new Set();
|
|
474
|
+
const encodedCache = /* @__PURE__ */ new Map();
|
|
475
|
+
const segments = baseUrl.split("/");
|
|
476
|
+
const updated = segments.map((segment) => {
|
|
477
|
+
if (!segment) {
|
|
478
|
+
return segment;
|
|
479
|
+
}
|
|
480
|
+
for (const { name, value } of replacements) {
|
|
481
|
+
if (used.has(name)) {
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
const encodedValue = encodedCache.get(value) ?? encodeURIComponent(value);
|
|
485
|
+
encodedCache.set(value, encodedValue);
|
|
486
|
+
if (segment === value || segment === encodedValue) {
|
|
487
|
+
used.add(name);
|
|
488
|
+
return `:${name}`;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return segment;
|
|
492
|
+
});
|
|
493
|
+
return updated.join("/");
|
|
494
|
+
}
|
|
495
|
+
function extractExpressParamNames(path) {
|
|
496
|
+
const names = [];
|
|
497
|
+
const paramPattern = /:([A-Za-z0-9_]+)(?:\([^)]*\))?[?*+]?/g;
|
|
498
|
+
for (const match of path.matchAll(paramPattern)) {
|
|
499
|
+
const name = match[1];
|
|
500
|
+
if (name) {
|
|
501
|
+
names.push(name);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return names;
|
|
505
|
+
}
|
|
506
|
+
function joinExpressRoute(baseUrl, routePath) {
|
|
507
|
+
const base = baseUrl ? ensureLeadingSlash(baseUrl) : "";
|
|
508
|
+
const route = routePath ? ensureLeadingSlash(routePath) : "";
|
|
509
|
+
if (!base) {
|
|
510
|
+
return route || "/";
|
|
511
|
+
}
|
|
512
|
+
if (!route || route === "/") {
|
|
513
|
+
return base;
|
|
514
|
+
}
|
|
515
|
+
const trimmedBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
516
|
+
return `${trimmedBase}${route}`;
|
|
517
|
+
}
|
|
518
|
+
function ensureLeadingSlash(path) {
|
|
519
|
+
if (!path) {
|
|
520
|
+
return "/";
|
|
521
|
+
}
|
|
522
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
523
|
+
}
|
|
524
|
+
export {
|
|
525
|
+
getXrayContext,
|
|
526
|
+
wrapHttpHandler
|
|
527
|
+
};
|
|
528
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapter.ts"],"sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http';\nimport { TLSSocket } from 'node:tls';\nimport type {\n CaptureConfig,\n NormalizedRequest,\n NormalizedResponse,\n RedactionConfig,\n RequestLog,\n XrayContext,\n XrayEmitter,\n} from '@stainlessdev/xray-core';\nimport {\n LimitedBuffer,\n bindContextToObject,\n getXrayContextFromObject,\n headerValuesFromNodeHeaders,\n isWebsocketUpgrade,\n logWithLevel,\n makeCapturedBody,\n setCaptureOverride,\n setContextRequestId,\n setContextRoute,\n setRedactionOverride,\n} from '@stainlessdev/xray-core/internal';\n\nexport type NodeHttpHandler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;\n\nexport interface WrapOptions {\n route?: string;\n requestId?: string;\n capture?: Partial<CaptureConfig>;\n redaction?: Partial<RedactionConfig>;\n onRequest?: (ctx: XrayContext) => void;\n onResponse?: (ctx: XrayContext, log: RequestLog) => void;\n onError?: (ctx: XrayContext, err: unknown) => void;\n}\n\nexport function wrapHttpHandler(\n handler: NodeHttpHandler,\n xray: XrayEmitter,\n options?: WrapOptions,\n): NodeHttpHandler {\n return (req, res) => {\n const normalizedRequest: NormalizedRequest = {\n method: req.method ?? 'GET',\n url: fullUrl(req),\n route: options?.route,\n headers: headerValuesFromNodeHeaders(\n req.headers as Record<string, string | string[] | number | undefined>,\n ),\n requestId: resolveRequestId(options?.requestId, req, xray),\n remoteAddress: req.socket?.remoteAddress,\n startTimeMs: Date.now(),\n };\n\n trackExpressParams(req);\n\n const ctx = xray.startRequest(normalizedRequest);\n bindContextToObject(req, ctx);\n bindContextToObject(res, ctx);\n\n if (options?.requestId) {\n setContextRequestId(ctx, options.requestId);\n }\n if (options?.route) {\n setContextRoute(ctx, options.route);\n }\n if (options?.capture) {\n setCaptureOverride(ctx, options.capture);\n }\n if (options?.redaction) {\n setRedactionOverride(ctx, options.redaction);\n }\n\n if (options?.onRequest) {\n try {\n options.onRequest(ctx);\n } catch (err) {\n logWithLevel(xray.config.logger, 'warn', xray.config.logLevel, 'xray: onRequest failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const capture = options?.capture\n ? { ...xray.config.capture, ...options.capture }\n : xray.config.capture;\n\n const requestCapture =\n capture.requestBody === 'none' ? null : wrapRequestBody(req, capture.maxBodyBytes);\n const recorder = new ResponseRecorder(capture.responseBody !== 'none', capture.maxBodyBytes);\n recorder.wrap(res);\n\n let finished = false;\n let capturedError: unknown;\n let onErrorCalled = false;\n\n const finish = () => {\n if (finished) {\n return;\n }\n finished = true;\n if (!normalizedRequest.route) {\n const route = resolveExpressRoute(req);\n if (route) {\n normalizedRequest.route = route;\n }\n }\n\n if (requestCapture && requestCapture.read) {\n normalizedRequest.body = makeCapturedBody(\n requestCapture.buffer.bytes(),\n requestCapture.buffer.totalBytes(),\n requestCapture.buffer.truncated(),\n capture.requestBody === 'text' ? 'text' : 'base64',\n );\n }\n\n const responseHeaders = recorder.headersSnapshot(res.getHeaders());\n const recordedStatus = recorder.statusCode() ?? res.statusCode;\n const statusCode = capturedError && !recorder.hasWrittenHeader() ? 500 : recordedStatus;\n const isUpgrade = isWebsocketUpgrade(\n statusCode ?? 0,\n normalizedRequest.headers,\n responseHeaders,\n );\n\n const responseBody =\n recorder.bodyCaptured() && !isUpgrade\n ? makeCapturedBody(\n recorder.body(),\n recorder.totalBytes(),\n recorder.truncated(),\n capture.responseBody === 'text' ? 'text' : 'base64',\n )\n : undefined;\n\n const normalizedResponse: NormalizedResponse = {\n statusCode: statusCode ?? undefined,\n headers: responseHeaders,\n body: responseBody,\n endTimeMs: Date.now(),\n };\n\n const log = xray.endRequest(ctx, normalizedResponse, capturedError);\n\n if (capturedError && options?.onError && !onErrorCalled) {\n onErrorCalled = true;\n try {\n options.onError(ctx, capturedError);\n } catch (err) {\n logWithLevel(xray.config.logger, 'warn', xray.config.logLevel, 'xray: onError failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n if (options?.onResponse) {\n try {\n options.onResponse(ctx, log);\n } catch (err) {\n logWithLevel(\n xray.config.logger,\n 'warn',\n xray.config.logLevel,\n 'xray: onResponse failed',\n {\n error: err instanceof Error ? err.message : String(err),\n },\n );\n }\n }\n };\n\n res.once('finish', finish);\n res.once('close', finish);\n\n try {\n const result = handler(req, res);\n if (result && typeof (result as Promise<void>).catch === 'function') {\n void (result as Promise<void>).catch((err) => {\n capturedError = err;\n if (options?.onError && !onErrorCalled) {\n onErrorCalled = true;\n try {\n options.onError(ctx, err);\n } catch (errInner) {\n logWithLevel(\n xray.config.logger,\n 'warn',\n xray.config.logLevel,\n 'xray: onError failed',\n {\n error: errInner instanceof Error ? errInner.message : String(errInner),\n },\n );\n }\n }\n });\n }\n } catch (err) {\n capturedError = err;\n if (options?.onError && !onErrorCalled) {\n onErrorCalled = true;\n try {\n options.onError(ctx, err);\n } catch (errInner) {\n logWithLevel(xray.config.logger, 'warn', xray.config.logLevel, 'xray: onError failed', {\n error: errInner instanceof Error ? errInner.message : String(errInner),\n });\n }\n }\n throw err;\n }\n };\n}\n\nexport function getXrayContext(req: IncomingMessage): XrayContext | undefined {\n return getXrayContextFromObject(req);\n}\n\ntype RequestCapture = {\n buffer: LimitedBuffer;\n read: boolean;\n userConsuming: boolean;\n};\n\nfunction wrapRequestBody(req: IncomingMessage, limit: number): RequestCapture | null {\n if (limit <= 0) {\n return null;\n }\n if (!hasRequestBody(req)) {\n return null;\n }\n\n const capture: RequestCapture = {\n buffer: new LimitedBuffer(limit),\n read: false,\n userConsuming: false,\n };\n\n const originalPush = req.push;\n req.push = function push(chunk: unknown, encoding?: BufferEncoding): boolean {\n if (chunk != null) {\n recordChunk(capture, chunk, encoding);\n }\n return originalPush.call(req, chunk as any, encoding as any);\n } as typeof req.push;\n\n const originalEmit = req.emit;\n req.emit = function emit(event: string, ...args: unknown[]): boolean {\n if (event === 'data' && capture.userConsuming && args[0] != null) {\n capture.read = true;\n }\n if (event === 'end' && capture.userConsuming) {\n capture.read = true;\n }\n return originalEmit.call(req, event, ...args);\n } as typeof req.emit;\n\n const originalOn = req.on;\n req.on = function on(event: string, listener: (...args: any[]) => void): any {\n if (event === 'data' || event === 'readable') {\n capture.userConsuming = true;\n }\n return originalOn.call(req, event, listener);\n } as typeof req.on;\n\n const originalOnce = req.once;\n req.once = function once(event: string, listener: (...args: any[]) => void): any {\n if (event === 'data' || event === 'readable') {\n capture.userConsuming = true;\n }\n return originalOnce.call(req, event, listener);\n } as typeof req.once;\n\n const originalAddListener = req.addListener;\n req.addListener = function addListener(event: string, listener: (...args: any[]) => void): any {\n if (event === 'data' || event === 'readable') {\n capture.userConsuming = true;\n }\n return originalAddListener.call(req, event, listener);\n } as typeof req.addListener;\n\n const originalPipe = req.pipe;\n req.pipe = function pipe(destination: unknown, options?: unknown): unknown {\n capture.userConsuming = true;\n return originalPipe.call(req, destination as any, options as any);\n } as typeof req.pipe;\n\n const originalRead = req.read;\n req.read = function read(size?: number): any {\n capture.userConsuming = true;\n const chunk = originalRead.call(req, size as any) as unknown;\n const readableFlowing = (req as IncomingMessage & { readableFlowing?: boolean | null })\n .readableFlowing;\n const hasDataListeners =\n typeof req.listenerCount === 'function' && req.listenerCount('data') > 0;\n if (!hasDataListeners && readableFlowing !== true && chunk != null) {\n capture.read = true;\n }\n return chunk as any;\n } as typeof req.read;\n\n return capture;\n}\n\nfunction hasRequestBody(req: IncomingMessage): boolean {\n if (req.headers['content-length'] != null) {\n return true;\n }\n if (req.headers['transfer-encoding'] != null) {\n return true;\n }\n return false;\n}\n\nfunction recordChunk(capture: RequestCapture, chunk: unknown, encoding?: BufferEncoding): void {\n const bytes = toBytes(chunk, encoding);\n if (!bytes) {\n return;\n }\n capture.buffer.write(bytes);\n}\n\nfunction toBytes(chunk: unknown, encoding?: BufferEncoding): Uint8Array | null {\n if (chunk == null) {\n return null;\n }\n if (typeof chunk === 'string') {\n return Buffer.from(chunk, encoding);\n }\n if (chunk instanceof Uint8Array) {\n return chunk;\n }\n if (chunk instanceof ArrayBuffer) {\n return new Uint8Array(chunk);\n }\n return null;\n}\n\nclass ResponseRecorder {\n private readonly buffer: LimitedBuffer | null;\n private headerSnapshot?: Record<string, string | string[] | number | undefined>;\n private status?: number;\n private wroteHeader = false;\n private bytes = 0;\n\n constructor(captureBody: boolean, maxBodySize: number) {\n this.buffer = captureBody ? new LimitedBuffer(maxBodySize) : null;\n }\n\n body(): Uint8Array {\n return this.buffer?.bytes() ?? new Uint8Array();\n }\n\n totalBytes(): number {\n return this.buffer?.totalBytes() ?? 0;\n }\n\n bodyCaptured(): boolean {\n return !!this.buffer && this.buffer.totalBytes() > 0;\n }\n\n bytesWritten(): number {\n return this.bytes;\n }\n\n hasWrittenHeader(): boolean {\n return this.wroteHeader;\n }\n\n headersSnapshot(\n defaultHeaders: Record<string, string | string[] | number | undefined>,\n ): Record<string, string | string[]> {\n if (this.headerSnapshot) {\n return headerValuesFromNodeHeaders(this.headerSnapshot);\n }\n return headerValuesFromNodeHeaders(defaultHeaders);\n }\n\n statusCode(): number | undefined {\n return this.status;\n }\n\n truncated(): boolean {\n return this.buffer?.truncated() ?? false;\n }\n\n wrap(res: ServerResponse): void {\n const originalWriteHead = res.writeHead;\n res.writeHead = ((statusCode: number, ...args: any[]) => {\n this.recordHeader(res, statusCode);\n return (originalWriteHead as any).call(res, statusCode, ...args);\n }) as typeof res.writeHead;\n\n const originalWrite = res.write;\n res.write = ((chunk: unknown, encoding?: BufferEncoding, cb?: (err?: Error | null) => void) => {\n this.recordHeader(res, res.statusCode ?? 200);\n this.recordWrite(chunk, encoding);\n return originalWrite.call(res, chunk as any, encoding as any, cb as any);\n }) as typeof res.write;\n\n const originalEnd = res.end;\n res.end = ((chunk?: unknown, encoding?: BufferEncoding, cb?: () => void) => {\n this.recordHeader(res, res.statusCode ?? 200);\n if (chunk) {\n this.recordWrite(chunk, encoding);\n }\n return originalEnd.call(res, chunk as any, encoding as any, cb as any);\n }) as typeof res.end;\n\n if (typeof res.flushHeaders === 'function') {\n const originalFlush = res.flushHeaders;\n res.flushHeaders = (() => {\n this.recordHeader(res, res.statusCode ?? 200);\n return originalFlush.call(res);\n }) as typeof res.flushHeaders;\n }\n }\n\n private recordHeader(res: ServerResponse, statusCode: number): void {\n if (this.wroteHeader) {\n return;\n }\n this.wroteHeader = true;\n this.status = statusCode;\n this.headerSnapshot = { ...res.getHeaders() } as Record<\n string,\n string | string[] | number | undefined\n >;\n }\n\n private recordWrite(chunk: unknown, encoding?: BufferEncoding): void {\n const bytes = toBytes(chunk, encoding);\n if (!bytes) {\n return;\n }\n this.bytes += bytes.length;\n if (this.buffer) {\n this.buffer.write(bytes);\n }\n }\n}\n\nfunction resolveRequestId(\n explicit: string | undefined,\n req: IncomingMessage,\n xray: XrayEmitter,\n): string | undefined {\n if (explicit) {\n return explicit;\n }\n const headerName = xray.config.requestId.header.toLowerCase();\n const value = req.headers[headerName];\n if (!value) {\n return undefined;\n }\n if (Array.isArray(value)) {\n return value[0]?.trim() || undefined;\n }\n return `${value}`.trim() || undefined;\n}\n\nfunction fullUrl(req: IncomingMessage): string {\n if (!req.url) {\n return '';\n }\n if (req.url.startsWith('http://') || req.url.startsWith('https://')) {\n return req.url;\n }\n\n const host = req.headers['host'];\n if (!host || typeof host !== 'string') {\n return req.url;\n }\n const scheme = req.socket instanceof TLSSocket ? 'https' : 'http';\n return `${scheme}://${host}${req.url}`;\n}\n\ntype ExpressRoutePath = string | string[] | RegExp;\n\ntype ExpressRouteParams = Record<string, string | string[]>;\n\nconst expressParamsHistory = new WeakMap<IncomingMessage, ExpressRouteParams[]>();\n\nfunction trackExpressParams(req: IncomingMessage): void {\n if (expressParamsHistory.has(req)) {\n return;\n }\n const anyReq = req as IncomingMessage & { app?: unknown };\n if (typeof anyReq.app !== 'function') {\n return;\n }\n\n const history: ExpressRouteParams[] = [];\n expressParamsHistory.set(req, history);\n\n const descriptor = Object.getOwnPropertyDescriptor(req, 'params');\n if (descriptor && !descriptor.configurable) {\n if (descriptor.value && typeof descriptor.value === 'object') {\n history.push({ ...(descriptor.value as ExpressRouteParams) });\n }\n return;\n }\n\n let current = (\n descriptor && 'value' in descriptor\n ? (descriptor.value as ExpressRouteParams | undefined)\n : undefined\n ) as ExpressRouteParams | undefined;\n if (current && typeof current === 'object') {\n history.push({ ...current });\n }\n\n Object.defineProperty(req, 'params', {\n configurable: true,\n enumerable: descriptor?.enumerable ?? true,\n get() {\n return current;\n },\n set(value) {\n current = value as ExpressRouteParams | undefined;\n if (value && typeof value === 'object') {\n history.push({ ...(value as ExpressRouteParams) });\n }\n },\n });\n}\n\nfunction resolveExpressRoute(req: IncomingMessage): string | undefined {\n const anyReq = req as IncomingMessage & {\n baseUrl?: string;\n params?: ExpressRouteParams;\n route?: { path?: ExpressRoutePath };\n };\n const routePath = extractExpressRoutePath(anyReq.route?.path);\n const baseUrl = anyReq.baseUrl ?? '';\n if (!routePath && !baseUrl) {\n return undefined;\n }\n\n const params = collectExpressParams(req, anyReq.params);\n const resolvedBaseUrl = replaceBaseUrlParams(baseUrl, params, routePath);\n return joinExpressRoute(resolvedBaseUrl, routePath);\n}\n\nfunction extractExpressRoutePath(path?: ExpressRoutePath): string | undefined {\n if (typeof path === 'string') {\n return path;\n }\n if (Array.isArray(path)) {\n for (const entry of path) {\n if (typeof entry === 'string') {\n return entry;\n }\n }\n }\n return undefined;\n}\n\nfunction collectExpressParams(\n req: IncomingMessage,\n fallback?: ExpressRouteParams,\n): ExpressRouteParams {\n const history = expressParamsHistory.get(req);\n if (!history || history.length === 0) {\n return fallback ?? {};\n }\n\n const merged: ExpressRouteParams = {};\n for (const snapshot of history) {\n for (const [key, value] of Object.entries(snapshot)) {\n if (!(key in merged)) {\n merged[key] = value;\n }\n }\n }\n if (fallback) {\n for (const [key, value] of Object.entries(fallback)) {\n if (!(key in merged)) {\n merged[key] = value;\n }\n }\n }\n return merged;\n}\n\nfunction replaceBaseUrlParams(\n baseUrl: string,\n params: ExpressRouteParams,\n routePath?: string,\n): string {\n if (!baseUrl) {\n return baseUrl;\n }\n const entries = Object.entries(params);\n if (entries.length === 0) {\n return baseUrl;\n }\n\n const excluded = new Set(routePath ? extractExpressParamNames(routePath) : []);\n const replacements = entries\n .filter(([name]) => !excluded.has(name))\n .map(([name, value]) => ({ name, value: Array.isArray(value) ? value[0] : value }))\n .filter((entry): entry is { name: string; value: string } => !!entry.value);\n\n if (replacements.length === 0) {\n return baseUrl;\n }\n\n const used = new Set<string>();\n const encodedCache = new Map<string, string>();\n const segments = baseUrl.split('/');\n const updated = segments.map((segment) => {\n if (!segment) {\n return segment;\n }\n for (const { name, value } of replacements) {\n if (used.has(name)) {\n continue;\n }\n const encodedValue = encodedCache.get(value) ?? encodeURIComponent(value);\n encodedCache.set(value, encodedValue);\n if (segment === value || segment === encodedValue) {\n used.add(name);\n return `:${name}`;\n }\n }\n return segment;\n });\n\n return updated.join('/');\n}\n\nfunction extractExpressParamNames(path: string): string[] {\n const names: string[] = [];\n const paramPattern = /:([A-Za-z0-9_]+)(?:\\([^)]*\\))?[?*+]?/g;\n for (const match of path.matchAll(paramPattern)) {\n const name = match[1];\n if (name) {\n names.push(name);\n }\n }\n return names;\n}\n\nfunction joinExpressRoute(baseUrl: string, routePath?: string): string {\n const base = baseUrl ? ensureLeadingSlash(baseUrl) : '';\n const route = routePath ? ensureLeadingSlash(routePath) : '';\n if (!base) {\n return route || '/';\n }\n if (!route || route === '/') {\n return base;\n }\n const trimmedBase = base.endsWith('/') ? base.slice(0, -1) : base;\n return `${trimmedBase}${route}`;\n}\n\nfunction ensureLeadingSlash(path: string): string {\n if (!path) {\n return '/';\n }\n return path.startsWith('/') ? path : `/${path}`;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stainlessdev/xray-node",
|
|
3
|
+
"version": "0.1.0-branch.bg-publish-to-npm.18b1cb1",
|
|
4
|
+
"description": "Node.js HTTP adapter for Stainless X-ray request logging",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@stainlessdev/xray-core": "0.1.0-branch.bg-publish-to-npm.18b1cb1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@opentelemetry/api": "^1.9.0",
|
|
27
|
+
"@opentelemetry/core": "^2.2.0",
|
|
28
|
+
"@opentelemetry/otlp-transformer": "^0.208.0",
|
|
29
|
+
"@opentelemetry/resources": "^2.2.0",
|
|
30
|
+
"@opentelemetry/sdk-trace-base": "^2.2.0",
|
|
31
|
+
"@opentelemetry/semantic-conventions": "^1.29.0",
|
|
32
|
+
"@types/node": "^20.11.0",
|
|
33
|
+
"oxlint": "^1.39.0",
|
|
34
|
+
"tsup": "^8.0.0",
|
|
35
|
+
"tsx": "^4.19.0",
|
|
36
|
+
"typescript": "^5.4.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@opentelemetry/api": "^1.9.0",
|
|
40
|
+
"@opentelemetry/core": "^2.2.0",
|
|
41
|
+
"@opentelemetry/otlp-transformer": "^0.208.0",
|
|
42
|
+
"@opentelemetry/resources": "^2.2.0",
|
|
43
|
+
"@opentelemetry/sdk-trace-base": "^2.2.0",
|
|
44
|
+
"@opentelemetry/semantic-conventions": "^1.29.0"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=20"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"test": "tsx --test test/*.test.ts",
|
|
52
|
+
"typecheck": "tsc --noEmit",
|
|
53
|
+
"lint": "oxlint",
|
|
54
|
+
"clean": "rm -rf dist"
|
|
55
|
+
}
|
|
56
|
+
}
|