@stainlessdev/xray-core 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/chunk-SQHI5JZH.js +172 -0
- package/dist/chunk-SQHI5JZH.js.map +1 -0
- package/dist/index.cjs +1191 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1131 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.cjs +453 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.cts +42 -0
- package/dist/internal.d.ts +42 -0
- package/dist/internal.js +284 -0
- package/dist/internal.js.map +1 -0
- package/dist/types-Bk-yp9Tw.d.cts +135 -0
- package/dist/types-Bk-yp9Tw.d.ts +135 -0
- package/package.json +58 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { C as CapturedBody, b as Logger, L as LogLevel, d as XrayContext, e as CaptureConfig, f as RedactionConfig } from './types-Bk-yp9Tw.cjs';
|
|
2
|
+
|
|
3
|
+
declare function makeCapturedBody(bytes: Uint8Array | undefined, totalBytes: number, truncated: boolean, mode: 'text' | 'base64'): CapturedBody | undefined;
|
|
4
|
+
|
|
5
|
+
declare class LimitedBuffer {
|
|
6
|
+
private buffer;
|
|
7
|
+
private length;
|
|
8
|
+
private readonly limit;
|
|
9
|
+
private truncatedFlag;
|
|
10
|
+
private total;
|
|
11
|
+
constructor(limit: number);
|
|
12
|
+
bytes(): Uint8Array;
|
|
13
|
+
capturedBytes(): number;
|
|
14
|
+
totalBytes(): number;
|
|
15
|
+
truncated(): boolean;
|
|
16
|
+
write(chunk: Uint8Array): void;
|
|
17
|
+
private ensureCapacity;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type HeaderCapture = {
|
|
21
|
+
headers: Record<string, string | string[]>;
|
|
22
|
+
truncated: boolean;
|
|
23
|
+
};
|
|
24
|
+
declare function headerValuesFromNodeHeaders(headers: Record<string, string | string[] | number | undefined>): Record<string, string | string[]>;
|
|
25
|
+
declare function headerValuesFromFetchHeaders(headers: Headers): Record<string, string | string[]>;
|
|
26
|
+
declare function headerValuesFromFetchHeadersWithLimit(headers: Headers, maxBytes: number): HeaderCapture;
|
|
27
|
+
declare function headerTokenList(values: string[] | string | undefined): string[];
|
|
28
|
+
|
|
29
|
+
type HeaderValues = Record<string, string | string[]>;
|
|
30
|
+
declare function isWebsocketUpgrade(statusCode: number, requestHeaders: HeaderValues | undefined, responseHeaders: HeaderValues | undefined): boolean;
|
|
31
|
+
declare function isWebsocketUpgradeFetch(statusCode: number, requestHeaders: Headers, responseHeaders: Headers): boolean;
|
|
32
|
+
|
|
33
|
+
declare function logWithLevel(logger: Logger, level: LogLevel, threshold: LogLevel, message: string, fields?: Record<string, unknown>): void;
|
|
34
|
+
|
|
35
|
+
declare function bindContextToObject(target: object, ctx: XrayContext): void;
|
|
36
|
+
declare function getXrayContextFromObject(target: unknown): XrayContext | undefined;
|
|
37
|
+
declare function setContextRoute(ctx: XrayContext, route: string): void;
|
|
38
|
+
declare function setContextRequestId(ctx: XrayContext, requestId: string): void;
|
|
39
|
+
declare function setCaptureOverride(ctx: XrayContext, capture: Partial<CaptureConfig> | undefined): void;
|
|
40
|
+
declare function setRedactionOverride(ctx: XrayContext, redaction: Partial<RedactionConfig> | undefined): void;
|
|
41
|
+
|
|
42
|
+
export { LimitedBuffer, bindContextToObject, getXrayContextFromObject, headerTokenList, headerValuesFromFetchHeaders, headerValuesFromFetchHeadersWithLimit, headerValuesFromNodeHeaders, isWebsocketUpgrade, isWebsocketUpgradeFetch, logWithLevel, makeCapturedBody, setCaptureOverride, setContextRequestId, setContextRoute, setRedactionOverride };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { C as CapturedBody, b as Logger, L as LogLevel, d as XrayContext, e as CaptureConfig, f as RedactionConfig } from './types-Bk-yp9Tw.js';
|
|
2
|
+
|
|
3
|
+
declare function makeCapturedBody(bytes: Uint8Array | undefined, totalBytes: number, truncated: boolean, mode: 'text' | 'base64'): CapturedBody | undefined;
|
|
4
|
+
|
|
5
|
+
declare class LimitedBuffer {
|
|
6
|
+
private buffer;
|
|
7
|
+
private length;
|
|
8
|
+
private readonly limit;
|
|
9
|
+
private truncatedFlag;
|
|
10
|
+
private total;
|
|
11
|
+
constructor(limit: number);
|
|
12
|
+
bytes(): Uint8Array;
|
|
13
|
+
capturedBytes(): number;
|
|
14
|
+
totalBytes(): number;
|
|
15
|
+
truncated(): boolean;
|
|
16
|
+
write(chunk: Uint8Array): void;
|
|
17
|
+
private ensureCapacity;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type HeaderCapture = {
|
|
21
|
+
headers: Record<string, string | string[]>;
|
|
22
|
+
truncated: boolean;
|
|
23
|
+
};
|
|
24
|
+
declare function headerValuesFromNodeHeaders(headers: Record<string, string | string[] | number | undefined>): Record<string, string | string[]>;
|
|
25
|
+
declare function headerValuesFromFetchHeaders(headers: Headers): Record<string, string | string[]>;
|
|
26
|
+
declare function headerValuesFromFetchHeadersWithLimit(headers: Headers, maxBytes: number): HeaderCapture;
|
|
27
|
+
declare function headerTokenList(values: string[] | string | undefined): string[];
|
|
28
|
+
|
|
29
|
+
type HeaderValues = Record<string, string | string[]>;
|
|
30
|
+
declare function isWebsocketUpgrade(statusCode: number, requestHeaders: HeaderValues | undefined, responseHeaders: HeaderValues | undefined): boolean;
|
|
31
|
+
declare function isWebsocketUpgradeFetch(statusCode: number, requestHeaders: Headers, responseHeaders: Headers): boolean;
|
|
32
|
+
|
|
33
|
+
declare function logWithLevel(logger: Logger, level: LogLevel, threshold: LogLevel, message: string, fields?: Record<string, unknown>): void;
|
|
34
|
+
|
|
35
|
+
declare function bindContextToObject(target: object, ctx: XrayContext): void;
|
|
36
|
+
declare function getXrayContextFromObject(target: unknown): XrayContext | undefined;
|
|
37
|
+
declare function setContextRoute(ctx: XrayContext, route: string): void;
|
|
38
|
+
declare function setContextRequestId(ctx: XrayContext, requestId: string): void;
|
|
39
|
+
declare function setCaptureOverride(ctx: XrayContext, capture: Partial<CaptureConfig> | undefined): void;
|
|
40
|
+
declare function setRedactionOverride(ctx: XrayContext, redaction: Partial<RedactionConfig> | undefined): void;
|
|
41
|
+
|
|
42
|
+
export { LimitedBuffer, bindContextToObject, getXrayContextFromObject, headerTokenList, headerValuesFromFetchHeaders, headerValuesFromFetchHeadersWithLimit, headerValuesFromNodeHeaders, isWebsocketUpgrade, isWebsocketUpgradeFetch, logWithLevel, makeCapturedBody, setCaptureOverride, setContextRequestId, setContextRoute, setRedactionOverride };
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bindObject,
|
|
3
|
+
getContextFromObject,
|
|
4
|
+
getContextState,
|
|
5
|
+
logWithLevel,
|
|
6
|
+
makeCapturedBody
|
|
7
|
+
} from "./chunk-SQHI5JZH.js";
|
|
8
|
+
|
|
9
|
+
// src/limited_buffer.ts
|
|
10
|
+
var LimitedBuffer = class {
|
|
11
|
+
constructor(limit) {
|
|
12
|
+
const normalized = Number.isFinite(limit) ? Math.max(0, limit) : 0;
|
|
13
|
+
const initialCap = Math.min(normalized, 32 * 1024);
|
|
14
|
+
this.buffer = new Uint8Array(initialCap);
|
|
15
|
+
this.length = 0;
|
|
16
|
+
this.limit = normalized;
|
|
17
|
+
this.truncatedFlag = false;
|
|
18
|
+
this.total = 0;
|
|
19
|
+
}
|
|
20
|
+
bytes() {
|
|
21
|
+
return this.buffer.slice(0, this.length);
|
|
22
|
+
}
|
|
23
|
+
capturedBytes() {
|
|
24
|
+
return this.length;
|
|
25
|
+
}
|
|
26
|
+
totalBytes() {
|
|
27
|
+
return this.total;
|
|
28
|
+
}
|
|
29
|
+
truncated() {
|
|
30
|
+
return this.truncatedFlag;
|
|
31
|
+
}
|
|
32
|
+
write(chunk) {
|
|
33
|
+
if (!chunk || chunk.length === 0) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.total += chunk.length;
|
|
37
|
+
if (this.limit <= 0) {
|
|
38
|
+
this.truncatedFlag = true;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const remaining = this.limit - this.length;
|
|
42
|
+
if (remaining <= 0) {
|
|
43
|
+
this.truncatedFlag = true;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const toCopy = Math.min(remaining, chunk.length);
|
|
47
|
+
this.ensureCapacity(this.length + toCopy);
|
|
48
|
+
this.buffer.set(chunk.subarray(0, toCopy), this.length);
|
|
49
|
+
this.length += toCopy;
|
|
50
|
+
if (toCopy < chunk.length) {
|
|
51
|
+
this.truncatedFlag = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
ensureCapacity(size) {
|
|
55
|
+
if (this.buffer.length >= size) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let nextSize = this.buffer.length;
|
|
59
|
+
if (nextSize === 0) {
|
|
60
|
+
nextSize = 1;
|
|
61
|
+
}
|
|
62
|
+
while (nextSize < size) {
|
|
63
|
+
nextSize *= 2;
|
|
64
|
+
}
|
|
65
|
+
if (nextSize > this.limit) {
|
|
66
|
+
nextSize = this.limit;
|
|
67
|
+
}
|
|
68
|
+
const next = new Uint8Array(nextSize);
|
|
69
|
+
next.set(this.buffer.subarray(0, this.length));
|
|
70
|
+
this.buffer = next;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// src/headers.ts
|
|
75
|
+
function headerValuesFromNodeHeaders(headers) {
|
|
76
|
+
const result = {};
|
|
77
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
78
|
+
if (value == null) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const name = key.trim();
|
|
82
|
+
if (!name) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(value)) {
|
|
86
|
+
const entries = value.map((item) => `${item}`);
|
|
87
|
+
if (entries.length > 0) {
|
|
88
|
+
result[name] = entries.length === 1 ? entries[0] : entries;
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
result[name] = `${value}`;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return Object.keys(result).length === 0 ? {} : result;
|
|
95
|
+
}
|
|
96
|
+
function headerValuesFromFetchHeaders(headers) {
|
|
97
|
+
return headerValuesFromFetchHeadersWithLimit(headers, Number.POSITIVE_INFINITY).headers;
|
|
98
|
+
}
|
|
99
|
+
function headerValuesFromFetchHeadersWithLimit(headers, maxBytes) {
|
|
100
|
+
const result = {};
|
|
101
|
+
let truncated = false;
|
|
102
|
+
let remaining = Number.isFinite(maxBytes) ? Math.max(0, maxBytes) : Number.POSITIVE_INFINITY;
|
|
103
|
+
const setCookie = getSetCookie(headers);
|
|
104
|
+
if (setCookie) {
|
|
105
|
+
const values = takeHeaderValues("set-cookie", setCookie, remaining);
|
|
106
|
+
remaining = values.remaining;
|
|
107
|
+
if (values.truncated) {
|
|
108
|
+
truncated = true;
|
|
109
|
+
}
|
|
110
|
+
if (values.values.length > 0) {
|
|
111
|
+
result["set-cookie"] = values.values.length === 1 ? values.values[0] : values.values;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
headers.forEach((value, key) => {
|
|
115
|
+
const name = key.trim();
|
|
116
|
+
if (!name) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (name.toLowerCase() === "set-cookie" && setCookie) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const values = takeHeaderValues(name, [value], remaining);
|
|
123
|
+
remaining = values.remaining;
|
|
124
|
+
if (values.truncated) {
|
|
125
|
+
truncated = true;
|
|
126
|
+
}
|
|
127
|
+
if (values.values.length > 0) {
|
|
128
|
+
result[name] = values.values.length === 1 ? values.values[0] : values.values;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return {
|
|
132
|
+
headers: Object.keys(result).length === 0 ? {} : result,
|
|
133
|
+
truncated
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function headerTokenList(values) {
|
|
137
|
+
if (!values) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
if (Array.isArray(values)) {
|
|
141
|
+
return splitTokens(values);
|
|
142
|
+
}
|
|
143
|
+
return splitTokens([values]);
|
|
144
|
+
}
|
|
145
|
+
function splitTokens(values) {
|
|
146
|
+
const tokens = [];
|
|
147
|
+
for (const value of values) {
|
|
148
|
+
if (!value) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
for (const part of value.split(",")) {
|
|
152
|
+
const trimmed = part.trim();
|
|
153
|
+
if (trimmed) {
|
|
154
|
+
tokens.push(trimmed);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return tokens;
|
|
159
|
+
}
|
|
160
|
+
function getSetCookie(headers) {
|
|
161
|
+
const maybe = headers;
|
|
162
|
+
if (typeof maybe.getSetCookie === "function") {
|
|
163
|
+
const values = maybe.getSetCookie();
|
|
164
|
+
return values.length > 0 ? values : null;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function takeHeaderValues(name, values, remaining) {
|
|
169
|
+
if (remaining <= 0) {
|
|
170
|
+
return { remaining: 0, truncated: true, values: [] };
|
|
171
|
+
}
|
|
172
|
+
const taken = [];
|
|
173
|
+
let used = 0;
|
|
174
|
+
for (const value of values) {
|
|
175
|
+
if (!value) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const size = name.length + value.length;
|
|
179
|
+
if (used + size > remaining) {
|
|
180
|
+
return { remaining: Math.max(0, remaining - used), truncated: true, values: taken };
|
|
181
|
+
}
|
|
182
|
+
used += size;
|
|
183
|
+
taken.push(value);
|
|
184
|
+
}
|
|
185
|
+
return { remaining: Math.max(0, remaining - used), truncated: false, values: taken };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/websocket.ts
|
|
189
|
+
function isWebsocketUpgrade(statusCode, requestHeaders, responseHeaders) {
|
|
190
|
+
if (statusCode !== 101) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
if (headerHasToken(responseHeaders, "upgrade", "websocket")) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
return headerHasToken(requestHeaders, "upgrade", "websocket");
|
|
197
|
+
}
|
|
198
|
+
function isWebsocketUpgradeFetch(statusCode, requestHeaders, responseHeaders) {
|
|
199
|
+
if (statusCode !== 101) {
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
if (headerHasTokenFetch(responseHeaders, "upgrade", "websocket")) {
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
return headerHasTokenFetch(requestHeaders, "upgrade", "websocket");
|
|
206
|
+
}
|
|
207
|
+
function headerHasToken(headers, name, token) {
|
|
208
|
+
if (!headers) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
const values = headers[name] ?? headers[name.toLowerCase()] ?? headers[name.toUpperCase()];
|
|
212
|
+
if (!values) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
const tokens = headerTokenList(values);
|
|
216
|
+
return tokens.some((value) => value.toLowerCase() === token.toLowerCase());
|
|
217
|
+
}
|
|
218
|
+
function headerHasTokenFetch(headers, name, token) {
|
|
219
|
+
const value = headers.get(name);
|
|
220
|
+
if (!value) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
return value.split(",").some((part) => part.trim().toLowerCase() === token.toLowerCase());
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// src/internal.ts
|
|
227
|
+
function bindContextToObject(target, ctx) {
|
|
228
|
+
const state = getContextState(ctx);
|
|
229
|
+
if (!state) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
bindObject(target, state);
|
|
233
|
+
}
|
|
234
|
+
function getXrayContextFromObject(target) {
|
|
235
|
+
return getContextFromObject(target);
|
|
236
|
+
}
|
|
237
|
+
function setContextRoute(ctx, route) {
|
|
238
|
+
const state = getContextState(ctx);
|
|
239
|
+
if (!state) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const normalized = state.config.route.normalize && state.config.route.normalizer ? state.config.route.normalizer(route) : route;
|
|
243
|
+
state.request.route = normalized;
|
|
244
|
+
}
|
|
245
|
+
function setContextRequestId(ctx, requestId) {
|
|
246
|
+
const state = getContextState(ctx);
|
|
247
|
+
if (!state) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
state.request.requestId = requestId;
|
|
251
|
+
state.context.requestId = requestId;
|
|
252
|
+
}
|
|
253
|
+
function setCaptureOverride(ctx, capture) {
|
|
254
|
+
const state = getContextState(ctx);
|
|
255
|
+
if (!state || !capture) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
state.captureOverride = capture;
|
|
259
|
+
}
|
|
260
|
+
function setRedactionOverride(ctx, redaction) {
|
|
261
|
+
const state = getContextState(ctx);
|
|
262
|
+
if (!state || !redaction) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
state.redactionOverride = redaction;
|
|
266
|
+
}
|
|
267
|
+
export {
|
|
268
|
+
LimitedBuffer,
|
|
269
|
+
bindContextToObject,
|
|
270
|
+
getXrayContextFromObject,
|
|
271
|
+
headerTokenList,
|
|
272
|
+
headerValuesFromFetchHeaders,
|
|
273
|
+
headerValuesFromFetchHeadersWithLimit,
|
|
274
|
+
headerValuesFromNodeHeaders,
|
|
275
|
+
isWebsocketUpgrade,
|
|
276
|
+
isWebsocketUpgradeFetch,
|
|
277
|
+
logWithLevel,
|
|
278
|
+
makeCapturedBody,
|
|
279
|
+
setCaptureOverride,
|
|
280
|
+
setContextRequestId,
|
|
281
|
+
setContextRoute,
|
|
282
|
+
setRedactionOverride
|
|
283
|
+
};
|
|
284
|
+
//# sourceMappingURL=internal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/limited_buffer.ts","../src/headers.ts","../src/websocket.ts","../src/internal.ts"],"sourcesContent":["export class LimitedBuffer {\n private buffer: Uint8Array;\n private length: number;\n private readonly limit: number;\n private truncatedFlag: boolean;\n private total: number;\n\n constructor(limit: number) {\n const normalized = Number.isFinite(limit) ? Math.max(0, limit) : 0;\n const initialCap = Math.min(normalized, 32 * 1024);\n this.buffer = new Uint8Array(initialCap);\n this.length = 0;\n this.limit = normalized;\n this.truncatedFlag = false;\n this.total = 0;\n }\n\n bytes(): Uint8Array {\n return this.buffer.slice(0, this.length);\n }\n\n capturedBytes(): number {\n return this.length;\n }\n\n totalBytes(): number {\n return this.total;\n }\n\n truncated(): boolean {\n return this.truncatedFlag;\n }\n\n write(chunk: Uint8Array): void {\n if (!chunk || chunk.length === 0) {\n return;\n }\n\n this.total += chunk.length;\n if (this.limit <= 0) {\n this.truncatedFlag = true;\n return;\n }\n\n const remaining = this.limit - this.length;\n if (remaining <= 0) {\n this.truncatedFlag = true;\n return;\n }\n\n const toCopy = Math.min(remaining, chunk.length);\n this.ensureCapacity(this.length + toCopy);\n this.buffer.set(chunk.subarray(0, toCopy), this.length);\n this.length += toCopy;\n if (toCopy < chunk.length) {\n this.truncatedFlag = true;\n }\n }\n\n private ensureCapacity(size: number): void {\n if (this.buffer.length >= size) {\n return;\n }\n\n let nextSize = this.buffer.length;\n if (nextSize === 0) {\n nextSize = 1;\n }\n while (nextSize < size) {\n nextSize *= 2;\n }\n if (nextSize > this.limit) {\n nextSize = this.limit;\n }\n const next = new Uint8Array(nextSize);\n next.set(this.buffer.subarray(0, this.length));\n this.buffer = next;\n }\n}\n","export type HeaderCapture = {\n headers: Record<string, string | string[]>;\n truncated: boolean;\n};\n\nexport function headerValuesFromNodeHeaders(\n headers: Record<string, string | string[] | number | undefined>,\n): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (value == null) {\n continue;\n }\n const name = key.trim();\n if (!name) {\n continue;\n }\n if (Array.isArray(value)) {\n const entries = value.map((item) => `${item}`);\n if (entries.length > 0) {\n result[name] = entries.length === 1 ? entries[0]! : entries;\n }\n } else {\n result[name] = `${value}`;\n }\n }\n return Object.keys(result).length === 0 ? {} : result;\n}\n\nexport function headerValuesFromFetchHeaders(headers: Headers): Record<string, string | string[]> {\n return headerValuesFromFetchHeadersWithLimit(headers, Number.POSITIVE_INFINITY).headers;\n}\n\nexport function headerValuesFromFetchHeadersWithLimit(\n headers: Headers,\n maxBytes: number,\n): HeaderCapture {\n const result: Record<string, string | string[]> = {};\n let truncated = false;\n let remaining = Number.isFinite(maxBytes) ? Math.max(0, maxBytes) : Number.POSITIVE_INFINITY;\n const setCookie = getSetCookie(headers);\n if (setCookie) {\n const values = takeHeaderValues('set-cookie', setCookie, remaining);\n remaining = values.remaining;\n if (values.truncated) {\n truncated = true;\n }\n if (values.values.length > 0) {\n result['set-cookie'] = values.values.length === 1 ? values.values[0]! : values.values;\n }\n }\n\n headers.forEach((value, key) => {\n const name = key.trim();\n if (!name) {\n return;\n }\n if (name.toLowerCase() === 'set-cookie' && setCookie) {\n return;\n }\n const values = takeHeaderValues(name, [value], remaining);\n remaining = values.remaining;\n if (values.truncated) {\n truncated = true;\n }\n if (values.values.length > 0) {\n result[name] = values.values.length === 1 ? values.values[0]! : values.values;\n }\n });\n\n return {\n headers: Object.keys(result).length === 0 ? {} : result,\n truncated,\n };\n}\n\nexport function headerTokenList(values: string[] | string | undefined): string[] {\n if (!values) {\n return [];\n }\n if (Array.isArray(values)) {\n return splitTokens(values);\n }\n return splitTokens([values]);\n}\n\nfunction splitTokens(values: string[]): string[] {\n const tokens: string[] = [];\n for (const value of values) {\n if (!value) {\n continue;\n }\n for (const part of value.split(',')) {\n const trimmed = part.trim();\n if (trimmed) {\n tokens.push(trimmed);\n }\n }\n }\n return tokens;\n}\n\nfunction getSetCookie(headers: Headers): string[] | null {\n const maybe = headers as Headers & { getSetCookie?: () => string[] };\n if (typeof maybe.getSetCookie === 'function') {\n const values = maybe.getSetCookie();\n return values.length > 0 ? values : null;\n }\n return null;\n}\n\nfunction takeHeaderValues(\n name: string,\n values: string[],\n remaining: number,\n): { values: string[]; remaining: number; truncated: boolean } {\n if (remaining <= 0) {\n return { remaining: 0, truncated: true, values: [] };\n }\n\n const taken: string[] = [];\n let used = 0;\n for (const value of values) {\n if (!value) {\n continue;\n }\n const size = name.length + value.length;\n if (used + size > remaining) {\n return { remaining: Math.max(0, remaining - used), truncated: true, values: taken };\n }\n used += size;\n taken.push(value);\n }\n\n return { remaining: Math.max(0, remaining - used), truncated: false, values: taken };\n}\n","import { headerTokenList } from './headers';\n\ntype HeaderValues = Record<string, string | string[]>;\n\nexport function isWebsocketUpgrade(\n statusCode: number,\n requestHeaders: HeaderValues | undefined,\n responseHeaders: HeaderValues | undefined,\n): boolean {\n if (statusCode !== 101) {\n return false;\n }\n\n if (headerHasToken(responseHeaders, 'upgrade', 'websocket')) {\n return true;\n }\n return headerHasToken(requestHeaders, 'upgrade', 'websocket');\n}\n\nexport function isWebsocketUpgradeFetch(\n statusCode: number,\n requestHeaders: Headers,\n responseHeaders: Headers,\n): boolean {\n if (statusCode !== 101) {\n return false;\n }\n\n if (headerHasTokenFetch(responseHeaders, 'upgrade', 'websocket')) {\n return true;\n }\n return headerHasTokenFetch(requestHeaders, 'upgrade', 'websocket');\n}\n\nfunction headerHasToken(headers: HeaderValues | undefined, name: string, token: string): boolean {\n if (!headers) {\n return false;\n }\n const values = headers[name] ?? headers[name.toLowerCase()] ?? headers[name.toUpperCase()];\n if (!values) {\n return false;\n }\n const tokens = headerTokenList(values);\n return tokens.some((value) => value.toLowerCase() === token.toLowerCase());\n}\n\nfunction headerHasTokenFetch(headers: Headers, name: string, token: string): boolean {\n const value = headers.get(name);\n if (!value) {\n return false;\n }\n return value.split(',').some((part) => part.trim().toLowerCase() === token.toLowerCase());\n}\n","import type { CaptureConfig, RedactionConfig } from './config';\nimport type { XrayContext } from './types';\nimport { bindObject, getContextFromObject, getContextState } from './state';\n\nexport { LimitedBuffer } from './limited_buffer';\nexport {\n headerValuesFromFetchHeaders,\n headerValuesFromFetchHeadersWithLimit,\n headerValuesFromNodeHeaders,\n headerTokenList,\n} from './headers';\nexport { isWebsocketUpgrade, isWebsocketUpgradeFetch } from './websocket';\nexport { makeCapturedBody } from './request_log';\nexport { logWithLevel } from './logger';\n\nexport function bindContextToObject(target: object, ctx: XrayContext): void {\n const state = getContextState(ctx);\n if (!state) {\n return;\n }\n bindObject(target, state);\n}\n\nexport function getXrayContextFromObject(target: unknown): XrayContext | undefined {\n return getContextFromObject(target);\n}\n\nexport function setContextRoute(ctx: XrayContext, route: string): void {\n const state = getContextState(ctx);\n if (!state) {\n return;\n }\n const normalized =\n state.config.route.normalize && state.config.route.normalizer\n ? state.config.route.normalizer(route)\n : route;\n state.request.route = normalized;\n}\n\nexport function setContextRequestId(ctx: XrayContext, requestId: string): void {\n const state = getContextState(ctx);\n if (!state) {\n return;\n }\n state.request.requestId = requestId;\n state.context.requestId = requestId;\n}\n\nexport function setCaptureOverride(\n ctx: XrayContext,\n capture: Partial<CaptureConfig> | undefined,\n): void {\n const state = getContextState(ctx);\n if (!state || !capture) {\n return;\n }\n state.captureOverride = capture;\n}\n\nexport function setRedactionOverride(\n ctx: XrayContext,\n redaction: Partial<RedactionConfig> | undefined,\n): void {\n const state = getContextState(ctx);\n if (!state || !redaction) {\n return;\n }\n state.redactionOverride = redaction;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
interface OtelConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
endpointUrl?: string;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
spanProcessor: 'simple' | 'batch';
|
|
7
|
+
sampler: {
|
|
8
|
+
type: 'always_on' | 'always_off' | 'ratio';
|
|
9
|
+
ratio?: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
interface CaptureConfig {
|
|
13
|
+
requestHeaders: boolean;
|
|
14
|
+
responseHeaders: boolean;
|
|
15
|
+
requestBody: 'none' | 'text' | 'base64';
|
|
16
|
+
responseBody: 'none' | 'text' | 'base64';
|
|
17
|
+
maxBodyBytes: number;
|
|
18
|
+
}
|
|
19
|
+
interface RedactionConfig {
|
|
20
|
+
headers: string[];
|
|
21
|
+
queryParams: string[];
|
|
22
|
+
bodyJsonPaths: string[];
|
|
23
|
+
replacement: string;
|
|
24
|
+
}
|
|
25
|
+
interface RequestIdConfig {
|
|
26
|
+
header: string;
|
|
27
|
+
generate: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface RouteConfig {
|
|
30
|
+
normalize: boolean;
|
|
31
|
+
normalizer?: (path: string) => string;
|
|
32
|
+
}
|
|
33
|
+
interface XrayConfig {
|
|
34
|
+
serviceName: string;
|
|
35
|
+
environment?: string;
|
|
36
|
+
version?: string;
|
|
37
|
+
logger?: Logger;
|
|
38
|
+
logLevel?: LogLevel;
|
|
39
|
+
otel?: Partial<OtelConfig>;
|
|
40
|
+
capture?: Partial<CaptureConfig>;
|
|
41
|
+
redaction?: Partial<RedactionConfig>;
|
|
42
|
+
requestId?: Partial<RequestIdConfig>;
|
|
43
|
+
route?: Partial<RouteConfig>;
|
|
44
|
+
}
|
|
45
|
+
interface ResolvedXrayConfig {
|
|
46
|
+
serviceName: string;
|
|
47
|
+
environment?: string;
|
|
48
|
+
version?: string;
|
|
49
|
+
logger: Logger;
|
|
50
|
+
logLevel: LogLevel;
|
|
51
|
+
otel: OtelConfig;
|
|
52
|
+
capture: CaptureConfig;
|
|
53
|
+
redaction: RedactionConfig;
|
|
54
|
+
requestId: RequestIdConfig;
|
|
55
|
+
route: RouteConfig;
|
|
56
|
+
}
|
|
57
|
+
declare class XrayConfigError extends Error {
|
|
58
|
+
code: 'INVALID_CONFIG' | 'INVALID_OTEL' | 'INVALID_REDACTION';
|
|
59
|
+
constructor(code: XrayConfigError['code'], message: string);
|
|
60
|
+
}
|
|
61
|
+
declare function normalizeConfig(config: XrayConfig): ResolvedXrayConfig;
|
|
62
|
+
|
|
63
|
+
type AttributeValue = string | number | boolean | string[] | number[] | boolean[];
|
|
64
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
65
|
+
interface Logger {
|
|
66
|
+
debug(msg: string, fields?: Record<string, unknown>): void;
|
|
67
|
+
info(msg: string, fields?: Record<string, unknown>): void;
|
|
68
|
+
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
69
|
+
error(msg: string, fields?: Record<string, unknown>): void;
|
|
70
|
+
}
|
|
71
|
+
interface CapturedBody {
|
|
72
|
+
bytes: number;
|
|
73
|
+
encoding: 'utf8' | 'base64';
|
|
74
|
+
truncated: boolean;
|
|
75
|
+
value?: string;
|
|
76
|
+
}
|
|
77
|
+
interface RequestLog {
|
|
78
|
+
requestId: string;
|
|
79
|
+
traceId?: string;
|
|
80
|
+
spanId?: string;
|
|
81
|
+
serviceName: string;
|
|
82
|
+
method: string;
|
|
83
|
+
url: string;
|
|
84
|
+
route?: string;
|
|
85
|
+
statusCode?: number;
|
|
86
|
+
durationMs: number;
|
|
87
|
+
requestHeaders?: Record<string, string | string[]>;
|
|
88
|
+
responseHeaders?: Record<string, string | string[]>;
|
|
89
|
+
requestBody?: CapturedBody;
|
|
90
|
+
responseBody?: CapturedBody;
|
|
91
|
+
userId?: string;
|
|
92
|
+
sessionId?: string;
|
|
93
|
+
error?: {
|
|
94
|
+
message: string;
|
|
95
|
+
type?: string;
|
|
96
|
+
stack?: string;
|
|
97
|
+
};
|
|
98
|
+
attributes?: Record<string, AttributeValue>;
|
|
99
|
+
timestamp: string;
|
|
100
|
+
}
|
|
101
|
+
interface XrayContext {
|
|
102
|
+
requestId: string;
|
|
103
|
+
traceId?: string;
|
|
104
|
+
spanId?: string;
|
|
105
|
+
setUserId(id: string): void;
|
|
106
|
+
setSessionId(id: string): void;
|
|
107
|
+
setAttribute(key: string, value: AttributeValue): void;
|
|
108
|
+
addEvent(name: string, attributes?: Record<string, AttributeValue>): void;
|
|
109
|
+
setError(err: unknown): void;
|
|
110
|
+
}
|
|
111
|
+
interface NormalizedRequest {
|
|
112
|
+
method: string;
|
|
113
|
+
url: string;
|
|
114
|
+
route?: string;
|
|
115
|
+
headers: Record<string, string | string[]>;
|
|
116
|
+
body?: CapturedBody;
|
|
117
|
+
requestId?: string;
|
|
118
|
+
remoteAddress?: string;
|
|
119
|
+
startTimeMs: number;
|
|
120
|
+
}
|
|
121
|
+
interface NormalizedResponse {
|
|
122
|
+
statusCode?: number;
|
|
123
|
+
headers?: Record<string, string | string[]>;
|
|
124
|
+
body?: CapturedBody;
|
|
125
|
+
endTimeMs: number;
|
|
126
|
+
}
|
|
127
|
+
interface XrayEmitter {
|
|
128
|
+
config: ResolvedXrayConfig;
|
|
129
|
+
startRequest(req: NormalizedRequest): XrayContext;
|
|
130
|
+
endRequest(ctx: XrayContext, res: NormalizedResponse, err?: unknown): RequestLog;
|
|
131
|
+
flush(): Promise<void>;
|
|
132
|
+
shutdown(): Promise<void>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { type AttributeValue as A, type CapturedBody as C, type LogLevel as L, type NormalizedRequest as N, type OtelConfig as O, type RequestLog as R, type XrayConfig as X, type XrayEmitter as a, type Logger as b, type NormalizedResponse as c, type XrayContext as d, type CaptureConfig as e, type RedactionConfig as f, type RequestIdConfig as g, type ResolvedXrayConfig as h, type RouteConfig as i, XrayConfigError as j, normalizeConfig as n };
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
interface OtelConfig {
|
|
2
|
+
enabled: boolean;
|
|
3
|
+
endpointUrl?: string;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
spanProcessor: 'simple' | 'batch';
|
|
7
|
+
sampler: {
|
|
8
|
+
type: 'always_on' | 'always_off' | 'ratio';
|
|
9
|
+
ratio?: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
interface CaptureConfig {
|
|
13
|
+
requestHeaders: boolean;
|
|
14
|
+
responseHeaders: boolean;
|
|
15
|
+
requestBody: 'none' | 'text' | 'base64';
|
|
16
|
+
responseBody: 'none' | 'text' | 'base64';
|
|
17
|
+
maxBodyBytes: number;
|
|
18
|
+
}
|
|
19
|
+
interface RedactionConfig {
|
|
20
|
+
headers: string[];
|
|
21
|
+
queryParams: string[];
|
|
22
|
+
bodyJsonPaths: string[];
|
|
23
|
+
replacement: string;
|
|
24
|
+
}
|
|
25
|
+
interface RequestIdConfig {
|
|
26
|
+
header: string;
|
|
27
|
+
generate: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface RouteConfig {
|
|
30
|
+
normalize: boolean;
|
|
31
|
+
normalizer?: (path: string) => string;
|
|
32
|
+
}
|
|
33
|
+
interface XrayConfig {
|
|
34
|
+
serviceName: string;
|
|
35
|
+
environment?: string;
|
|
36
|
+
version?: string;
|
|
37
|
+
logger?: Logger;
|
|
38
|
+
logLevel?: LogLevel;
|
|
39
|
+
otel?: Partial<OtelConfig>;
|
|
40
|
+
capture?: Partial<CaptureConfig>;
|
|
41
|
+
redaction?: Partial<RedactionConfig>;
|
|
42
|
+
requestId?: Partial<RequestIdConfig>;
|
|
43
|
+
route?: Partial<RouteConfig>;
|
|
44
|
+
}
|
|
45
|
+
interface ResolvedXrayConfig {
|
|
46
|
+
serviceName: string;
|
|
47
|
+
environment?: string;
|
|
48
|
+
version?: string;
|
|
49
|
+
logger: Logger;
|
|
50
|
+
logLevel: LogLevel;
|
|
51
|
+
otel: OtelConfig;
|
|
52
|
+
capture: CaptureConfig;
|
|
53
|
+
redaction: RedactionConfig;
|
|
54
|
+
requestId: RequestIdConfig;
|
|
55
|
+
route: RouteConfig;
|
|
56
|
+
}
|
|
57
|
+
declare class XrayConfigError extends Error {
|
|
58
|
+
code: 'INVALID_CONFIG' | 'INVALID_OTEL' | 'INVALID_REDACTION';
|
|
59
|
+
constructor(code: XrayConfigError['code'], message: string);
|
|
60
|
+
}
|
|
61
|
+
declare function normalizeConfig(config: XrayConfig): ResolvedXrayConfig;
|
|
62
|
+
|
|
63
|
+
type AttributeValue = string | number | boolean | string[] | number[] | boolean[];
|
|
64
|
+
type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
65
|
+
interface Logger {
|
|
66
|
+
debug(msg: string, fields?: Record<string, unknown>): void;
|
|
67
|
+
info(msg: string, fields?: Record<string, unknown>): void;
|
|
68
|
+
warn(msg: string, fields?: Record<string, unknown>): void;
|
|
69
|
+
error(msg: string, fields?: Record<string, unknown>): void;
|
|
70
|
+
}
|
|
71
|
+
interface CapturedBody {
|
|
72
|
+
bytes: number;
|
|
73
|
+
encoding: 'utf8' | 'base64';
|
|
74
|
+
truncated: boolean;
|
|
75
|
+
value?: string;
|
|
76
|
+
}
|
|
77
|
+
interface RequestLog {
|
|
78
|
+
requestId: string;
|
|
79
|
+
traceId?: string;
|
|
80
|
+
spanId?: string;
|
|
81
|
+
serviceName: string;
|
|
82
|
+
method: string;
|
|
83
|
+
url: string;
|
|
84
|
+
route?: string;
|
|
85
|
+
statusCode?: number;
|
|
86
|
+
durationMs: number;
|
|
87
|
+
requestHeaders?: Record<string, string | string[]>;
|
|
88
|
+
responseHeaders?: Record<string, string | string[]>;
|
|
89
|
+
requestBody?: CapturedBody;
|
|
90
|
+
responseBody?: CapturedBody;
|
|
91
|
+
userId?: string;
|
|
92
|
+
sessionId?: string;
|
|
93
|
+
error?: {
|
|
94
|
+
message: string;
|
|
95
|
+
type?: string;
|
|
96
|
+
stack?: string;
|
|
97
|
+
};
|
|
98
|
+
attributes?: Record<string, AttributeValue>;
|
|
99
|
+
timestamp: string;
|
|
100
|
+
}
|
|
101
|
+
interface XrayContext {
|
|
102
|
+
requestId: string;
|
|
103
|
+
traceId?: string;
|
|
104
|
+
spanId?: string;
|
|
105
|
+
setUserId(id: string): void;
|
|
106
|
+
setSessionId(id: string): void;
|
|
107
|
+
setAttribute(key: string, value: AttributeValue): void;
|
|
108
|
+
addEvent(name: string, attributes?: Record<string, AttributeValue>): void;
|
|
109
|
+
setError(err: unknown): void;
|
|
110
|
+
}
|
|
111
|
+
interface NormalizedRequest {
|
|
112
|
+
method: string;
|
|
113
|
+
url: string;
|
|
114
|
+
route?: string;
|
|
115
|
+
headers: Record<string, string | string[]>;
|
|
116
|
+
body?: CapturedBody;
|
|
117
|
+
requestId?: string;
|
|
118
|
+
remoteAddress?: string;
|
|
119
|
+
startTimeMs: number;
|
|
120
|
+
}
|
|
121
|
+
interface NormalizedResponse {
|
|
122
|
+
statusCode?: number;
|
|
123
|
+
headers?: Record<string, string | string[]>;
|
|
124
|
+
body?: CapturedBody;
|
|
125
|
+
endTimeMs: number;
|
|
126
|
+
}
|
|
127
|
+
interface XrayEmitter {
|
|
128
|
+
config: ResolvedXrayConfig;
|
|
129
|
+
startRequest(req: NormalizedRequest): XrayContext;
|
|
130
|
+
endRequest(ctx: XrayContext, res: NormalizedResponse, err?: unknown): RequestLog;
|
|
131
|
+
flush(): Promise<void>;
|
|
132
|
+
shutdown(): Promise<void>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export { type AttributeValue as A, type CapturedBody as C, type LogLevel as L, type NormalizedRequest as N, type OtelConfig as O, type RequestLog as R, type XrayConfig as X, type XrayEmitter as a, type Logger as b, type NormalizedResponse as c, type XrayContext as d, type CaptureConfig as e, type RedactionConfig as f, type RequestIdConfig as g, type ResolvedXrayConfig as h, type RouteConfig as i, XrayConfigError as j, normalizeConfig as n };
|