@tracepanel/js 0.3.4 → 0.4.1
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/README.md +50 -4
- package/dist/agent.d.ts +23 -1
- package/dist/agent.js +72 -22
- package/dist/agent.js.map +1 -1
- package/dist/body.d.ts +32 -0
- package/dist/body.js +314 -0
- package/dist/body.js.map +1 -0
- package/dist/bullmq.d.ts +76 -1
- package/dist/bullmq.js +215 -6
- package/dist/bullmq.js.map +1 -1
- package/dist/bun.js +81 -11
- package/dist/bun.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/console.d.ts +5 -0
- package/dist/console.js +16 -0
- package/dist/console.js.map +1 -1
- package/dist/express.js +94 -23
- package/dist/express.js.map +1 -1
- package/dist/headers.js +54 -8
- package/dist/headers.js.map +1 -1
- package/dist/inspector.d.ts +9 -0
- package/dist/inspector.js +47 -0
- package/dist/inspector.js.map +1 -0
- package/dist/locals.d.ts +51 -0
- package/dist/locals.js +269 -0
- package/dist/locals.js.map +1 -0
- package/dist/loggers.d.ts +50 -0
- package/dist/loggers.js +201 -0
- package/dist/loggers.js.map +1 -0
- package/dist/model.d.ts +23 -2
- package/dist/model.js.map +1 -1
- package/dist/next.js +6 -0
- package/dist/next.js.map +1 -1
- package/dist/nuxt-plugin.d.ts +1 -0
- package/dist/nuxt-plugin.js +6 -0
- package/dist/nuxt-plugin.js.map +1 -1
- package/dist/processor.d.ts +23 -2
- package/dist/processor.js +61 -14
- package/dist/processor.js.map +1 -1
- package/dist/profile.d.ts +63 -0
- package/dist/profile.js +300 -0
- package/dist/profile.js.map +1 -0
- package/dist/request.d.ts +61 -0
- package/dist/request.js +244 -0
- package/dist/request.js.map +1 -0
- package/dist/session.d.ts +10 -0
- package/dist/session.js +45 -0
- package/dist/session.js.map +1 -0
- package/dist/setup.js +10 -1
- package/dist/setup.js.map +1 -1
- package/dist/stack.d.ts +27 -3
- package/dist/stack.js +106 -9
- package/dist/stack.js.map +1 -1
- package/dist/widget.d.ts +24 -0
- package/dist/widget.js +62 -1
- package/dist/widget.js.map +1 -1
- package/package.json +16 -4
package/dist/profile.js
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// Where a trace's time goes in code: V8's sampling profiler, through Node's inspector (the trace's `profile`, a flame
|
|
2
|
+
// graph in the console). Nothing runs until a trace is profiled: the setting profiles every one, a request asks with
|
|
3
|
+
// the X-Tracepanel-Profile: 1 header or the panel's tracepanel_profile=1 cookie.
|
|
4
|
+
//
|
|
5
|
+
// The profiler samples the whole thread, and one event loop runs every request of the process at once: a sample
|
|
6
|
+
// can't tell which request a frame belongs to. So a profiled trace keeps the samples taken while it was the only trace
|
|
7
|
+
// running here, as the Python SDK keeps a thread's samples only while it runs one trace; those taken while another
|
|
8
|
+
// ran too are dropped and counted (`tracepanel.dropped_samples`). What the process did meanwhile outside any request
|
|
9
|
+
// (a timer, the garbage collector) is in the profile too. Samples of an idle loop, the request waiting on I/O, are
|
|
10
|
+
// left out: the profile is where the time went in code, on the CPU.
|
|
11
|
+
//
|
|
12
|
+
// One profile runs for as long as traces are profiled, so starting the next one costs next to nothing (the first
|
|
13
|
+
// start reads every function V8 has compiled: tens of milliseconds); each trace's own profile is a console.profile()
|
|
14
|
+
// under it, from its start to its end. It stops IDLE_MS after the last one.
|
|
15
|
+
import { relative } from "node:path";
|
|
16
|
+
import { createContextKey } from "@opentelemetry/api";
|
|
17
|
+
import { call, connect, inspector } from "./inspector.js";
|
|
18
|
+
import { headerValue, parseCookies } from "./request.js";
|
|
19
|
+
import { inApp, libraryPath, ownFile, place } from "./stack.js";
|
|
20
|
+
export const HEADER = "x-tracepanel-profile";
|
|
21
|
+
export const COOKIE = "tracepanel_profile";
|
|
22
|
+
/** On a request's root span: the request asked to be profiled. */
|
|
23
|
+
export const ATTRIBUTE = "tracepanel.profile";
|
|
24
|
+
/** In the context a framework starts the request's root span in (Next.js's): the request asked to be profiled. */
|
|
25
|
+
export const ASKED = createContextKey("tracepanel.profile");
|
|
26
|
+
// How deep a stack is kept: a recursion beyond it is cut, outermost frames kept.
|
|
27
|
+
const MAX_DEPTH = 128;
|
|
28
|
+
// Distinct stacks one trace keeps; the rest are counted as one "(other)" frame, so a profile stays small.
|
|
29
|
+
const MAX_STACKS = 2000;
|
|
30
|
+
// How long the profiler runs on with no trace profiled, ready for the next one.
|
|
31
|
+
const IDLE_MS = 30_000;
|
|
32
|
+
// A profiler running this long is started anew once no trace is profiled: its own samples pile up meanwhile.
|
|
33
|
+
const RENEW_MS = 60_000;
|
|
34
|
+
// V8's own entries: the loop waiting (no work to profile), and the root every stack starts from.
|
|
35
|
+
const IDLE = "(idle)";
|
|
36
|
+
const ROOT = "(root)";
|
|
37
|
+
const OTHER = { function: "(other)", module: null, file: "", line: 0, in_app: false };
|
|
38
|
+
/** Whether a request asks to be profiled: the X-Tracepanel-Profile header, or the cookie the panel's toggle sets. */
|
|
39
|
+
export function requested(headers) {
|
|
40
|
+
if (headerValue(headers[HEADER])?.trim() === "1")
|
|
41
|
+
return true;
|
|
42
|
+
const cookies = headerValue(headers.cookie);
|
|
43
|
+
return (cookies?.includes(COOKIE) === true &&
|
|
44
|
+
parseCookies(cookies).some(([name, value]) => name === COOKIE && value === "1"));
|
|
45
|
+
}
|
|
46
|
+
/** Whether to profile a trace: the setting profiles every one, a request may ask; nothing when profiling is off. */
|
|
47
|
+
export function wanted(config, asked) {
|
|
48
|
+
return config.profileEnabled && (config.profile || asked) && available();
|
|
49
|
+
}
|
|
50
|
+
/** Whether this runtime can profile: Node, with its inspector. */
|
|
51
|
+
export function available() {
|
|
52
|
+
return inspector() !== null;
|
|
53
|
+
}
|
|
54
|
+
let next = 0;
|
|
55
|
+
/** The app's profiler: the profile that runs while traces are profiled, and when each trace of the process ran. */
|
|
56
|
+
export class Profiler {
|
|
57
|
+
root;
|
|
58
|
+
intervalMs;
|
|
59
|
+
session;
|
|
60
|
+
running = false;
|
|
61
|
+
runningSince = 0;
|
|
62
|
+
idle;
|
|
63
|
+
recordings = new Set();
|
|
64
|
+
/** Every trace of the process running now, and when it started. */
|
|
65
|
+
open = new Map();
|
|
66
|
+
/** Traces that ended while one was profiled: when each started and ended. */
|
|
67
|
+
ended = [];
|
|
68
|
+
/** The console profiles stopped, by title, as the inspector hands them over. */
|
|
69
|
+
finished = new Map();
|
|
70
|
+
constructor(root, intervalMs) {
|
|
71
|
+
this.root = root;
|
|
72
|
+
this.intervalMs = intervalMs;
|
|
73
|
+
}
|
|
74
|
+
/** A trace started (each one, profiled or not): a sample taken while it runs may be its. */
|
|
75
|
+
enter(trace) {
|
|
76
|
+
this.open.set(trace, performance.now());
|
|
77
|
+
}
|
|
78
|
+
/** A trace ended. */
|
|
79
|
+
leave(trace) {
|
|
80
|
+
const started = this.open.get(trace);
|
|
81
|
+
if (started === undefined)
|
|
82
|
+
return;
|
|
83
|
+
this.open.delete(trace);
|
|
84
|
+
if (this.recordings.size > 0)
|
|
85
|
+
this.ended.push([started, performance.now()]);
|
|
86
|
+
}
|
|
87
|
+
/** Begins profiling a trace that started (enter() first); undefined when the inspector can't. */
|
|
88
|
+
start(trace) {
|
|
89
|
+
const console = inspector()?.console;
|
|
90
|
+
if (!console || !this.ensure())
|
|
91
|
+
return undefined;
|
|
92
|
+
clearTimeout(this.idle);
|
|
93
|
+
next += 1;
|
|
94
|
+
const recording = { title: `tracepanel:${next}`, startedMs: performance.now(), trace };
|
|
95
|
+
console.profile(recording.title);
|
|
96
|
+
this.recordings.add(recording);
|
|
97
|
+
return recording;
|
|
98
|
+
}
|
|
99
|
+
/** Ends a trace's profile, before it leaves: what was sampled while it alone ran. */
|
|
100
|
+
stop(recording) {
|
|
101
|
+
if (!this.recordings.has(recording))
|
|
102
|
+
return { profile: undefined, dropped: 0 };
|
|
103
|
+
inspector()?.console.profileEnd(recording.title);
|
|
104
|
+
this.recordings.delete(recording);
|
|
105
|
+
const profile = this.finished.get(recording.title);
|
|
106
|
+
this.finished.delete(recording.title);
|
|
107
|
+
const result = profile ? this.document(recording, profile) : { profile: undefined, dropped: 0 };
|
|
108
|
+
if (this.recordings.size === 0)
|
|
109
|
+
this.rest();
|
|
110
|
+
else {
|
|
111
|
+
const oldest = Math.min(...[...this.recordings].map((other) => other.startedMs));
|
|
112
|
+
this.ended = this.ended.filter(([, end]) => end >= oldest);
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
/** The profile that runs under the traces' own: started with the first profiled trace. */
|
|
117
|
+
ensure() {
|
|
118
|
+
if (!this.session) {
|
|
119
|
+
const session = connect();
|
|
120
|
+
if (!session)
|
|
121
|
+
return false;
|
|
122
|
+
try {
|
|
123
|
+
call(session, "Profiler.enable");
|
|
124
|
+
call(session, "Profiler.setSamplingInterval", { interval: Math.round(this.intervalMs * 1000) });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
session.disconnect();
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
session.on("Profiler.consoleProfileFinished", (message) => {
|
|
131
|
+
const { title, profile } = message.params;
|
|
132
|
+
// Only this profiler's: another session's console.profile() reaches every session.
|
|
133
|
+
if ([...this.recordings].some((recording) => recording.title === title))
|
|
134
|
+
this.finished.set(title ?? "", profile);
|
|
135
|
+
});
|
|
136
|
+
this.session = session;
|
|
137
|
+
}
|
|
138
|
+
if (!this.running) {
|
|
139
|
+
try {
|
|
140
|
+
call(this.session, "Profiler.start");
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
this.running = true;
|
|
146
|
+
this.runningSince = performance.now();
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
/** No trace is profiled: the profile under them stops after a while, or now when it ran long. */
|
|
151
|
+
rest() {
|
|
152
|
+
this.ended = [];
|
|
153
|
+
if (performance.now() - this.runningSince > RENEW_MS) {
|
|
154
|
+
this.halt();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
clearTimeout(this.idle);
|
|
158
|
+
this.idle = setTimeout(() => this.halt(), IDLE_MS);
|
|
159
|
+
this.idle.unref();
|
|
160
|
+
}
|
|
161
|
+
halt() {
|
|
162
|
+
if (!this.session || !this.running || this.recordings.size > 0)
|
|
163
|
+
return;
|
|
164
|
+
this.running = false;
|
|
165
|
+
try {
|
|
166
|
+
call(this.session, "Profiler.stop");
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// Stopped already.
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Whether another trace than the recording's ran at `at` (performance.now()). */
|
|
173
|
+
shared(recording, at) {
|
|
174
|
+
for (const [trace, started] of this.open) {
|
|
175
|
+
if (trace !== recording.trace && started <= at)
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
return this.ended.some(([started, end]) => started <= at && at <= end);
|
|
179
|
+
}
|
|
180
|
+
/** The trace's `profile`: the functions its stacks name, each once, and each stack as indexes into them. */
|
|
181
|
+
document(recording, profile) {
|
|
182
|
+
const nodes = new Map(profile.nodes.map((node) => [node.id, node]));
|
|
183
|
+
const parents = new Map();
|
|
184
|
+
for (const node of profile.nodes)
|
|
185
|
+
for (const child of node.children ?? [])
|
|
186
|
+
parents.set(child, node.id);
|
|
187
|
+
const index = new Map();
|
|
188
|
+
const frames = [];
|
|
189
|
+
/** A node's stack as indexes into frames, outermost first; null for the idle loop. */
|
|
190
|
+
const stackOf = new Map();
|
|
191
|
+
const frameIndex = (callFrame) => {
|
|
192
|
+
const key = `${callFrame.url}:${callFrame.lineNumber}:${callFrame.columnNumber}:${callFrame.functionName}`;
|
|
193
|
+
const known = index.get(key);
|
|
194
|
+
if (known !== undefined)
|
|
195
|
+
return known;
|
|
196
|
+
const frame = this.frame(callFrame);
|
|
197
|
+
if (!frame)
|
|
198
|
+
return null;
|
|
199
|
+
index.set(key, frames.length);
|
|
200
|
+
frames.push(frame);
|
|
201
|
+
return frames.length - 1;
|
|
202
|
+
};
|
|
203
|
+
const stack = (id) => {
|
|
204
|
+
const known = stackOf.get(id);
|
|
205
|
+
if (known !== undefined)
|
|
206
|
+
return known;
|
|
207
|
+
const chain = [];
|
|
208
|
+
for (let at = id; at !== undefined; at = parents.get(at)) {
|
|
209
|
+
const node = nodes.get(at);
|
|
210
|
+
if (node && node.callFrame.functionName !== ROOT)
|
|
211
|
+
chain.push(node.callFrame);
|
|
212
|
+
}
|
|
213
|
+
let found = null;
|
|
214
|
+
if (chain[0]?.functionName !== IDLE) {
|
|
215
|
+
found = [];
|
|
216
|
+
for (const callFrame of chain.reverse()) {
|
|
217
|
+
if (found.length >= MAX_DEPTH)
|
|
218
|
+
break;
|
|
219
|
+
const at = frameIndex(callFrame);
|
|
220
|
+
if (at !== null)
|
|
221
|
+
found.push(at);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
stackOf.set(id, found);
|
|
225
|
+
return found;
|
|
226
|
+
};
|
|
227
|
+
const counts = new Map();
|
|
228
|
+
let samples = 0;
|
|
229
|
+
let dropped = 0;
|
|
230
|
+
let time = profile.startTime;
|
|
231
|
+
const deltas = profile.timeDeltas ?? [];
|
|
232
|
+
(profile.samples ?? []).forEach((id, at) => {
|
|
233
|
+
time += deltas[at] ?? 0;
|
|
234
|
+
let keys = stack(id);
|
|
235
|
+
if (keys === null || keys.length === 0)
|
|
236
|
+
return;
|
|
237
|
+
// The profile's clock is V8's; it started as the recording did.
|
|
238
|
+
if (this.shared(recording, recording.startedMs + (time - profile.startTime) / 1000)) {
|
|
239
|
+
dropped += 1;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
let key = keys.join(",");
|
|
243
|
+
if (!counts.has(key) && counts.size >= MAX_STACKS) {
|
|
244
|
+
let other = index.get(OTHER.function);
|
|
245
|
+
if (other === undefined) {
|
|
246
|
+
other = frames.length;
|
|
247
|
+
index.set(OTHER.function, other);
|
|
248
|
+
frames.push(OTHER);
|
|
249
|
+
}
|
|
250
|
+
keys = [other];
|
|
251
|
+
key = String(other);
|
|
252
|
+
}
|
|
253
|
+
const counted = counts.get(key);
|
|
254
|
+
if (counted)
|
|
255
|
+
counted.count += 1;
|
|
256
|
+
else
|
|
257
|
+
counts.set(key, { frames: keys, count: 1 });
|
|
258
|
+
samples += 1;
|
|
259
|
+
});
|
|
260
|
+
if (samples === 0)
|
|
261
|
+
return { profile: undefined, dropped };
|
|
262
|
+
// Only the frames the kept stacks name, in the order the most frequent stacks name them.
|
|
263
|
+
const stacks = [...counts.values()].sort((a, b) => b.count - a.count);
|
|
264
|
+
const kept = [];
|
|
265
|
+
const renumber = new Map();
|
|
266
|
+
for (const counted of stacks) {
|
|
267
|
+
counted.frames = counted.frames.map((frame) => {
|
|
268
|
+
let to = renumber.get(frame);
|
|
269
|
+
if (to === undefined) {
|
|
270
|
+
to = kept.length;
|
|
271
|
+
renumber.set(frame, to);
|
|
272
|
+
kept.push(frames[frame]);
|
|
273
|
+
}
|
|
274
|
+
return to;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
profile: { interval_us: Math.round(this.intervalMs * 1000), samples, frames: kept, stacks },
|
|
279
|
+
dropped,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
/** A function as the profile names it; null for this package's own. */
|
|
283
|
+
frame(callFrame) {
|
|
284
|
+
const name = callFrame.functionName || "(anonymous)";
|
|
285
|
+
if (!callFrame.url)
|
|
286
|
+
return { function: name, module: null, file: "", line: 0, in_app: false };
|
|
287
|
+
const found = place(callFrame.url, callFrame.lineNumber + 1, callFrame.columnNumber + 1);
|
|
288
|
+
if (ownFile(found.file))
|
|
289
|
+
return null;
|
|
290
|
+
const own = inApp(found.file, this.root);
|
|
291
|
+
return {
|
|
292
|
+
function: name,
|
|
293
|
+
module: null,
|
|
294
|
+
file: own ? relative(this.root, found.file) : libraryPath(found.file),
|
|
295
|
+
line: found.line,
|
|
296
|
+
in_app: own,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../src/profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Attrs } from "./model.js";
|
|
2
|
+
/** How much of a body is kept, in characters. */
|
|
3
|
+
export declare const MAX_BODY = 16384;
|
|
4
|
+
export declare const MASK = "********";
|
|
5
|
+
/** A name as one segment of an attribute's key (content-type -> content_type), as the trace format has keys. */
|
|
6
|
+
export declare function key(name: string): string;
|
|
7
|
+
/** Whether a secret goes under the name: x-api-key, csrftoken, sessionid, password. */
|
|
8
|
+
export declare function sensitive(name: string): boolean;
|
|
9
|
+
/** A header's value as one string: several values joined, as Node joins them. */
|
|
10
|
+
export declare function headerValue(value: unknown): string | undefined;
|
|
11
|
+
/** http.request.header.<name>, the name as a key; Cookie is read as cookies instead. */
|
|
12
|
+
export declare function requestHeaders(entries: Iterable<[string, unknown]>): Attrs;
|
|
13
|
+
/** http.response.header.<name>: several values joined, Set-Cookie masked. */
|
|
14
|
+
export declare function responseHeaders(entries: Iterable<[string, unknown]>): Attrs;
|
|
15
|
+
/** url.query: the query string, the values of sensitive parameters masked. */
|
|
16
|
+
export declare function query(search: string): Attrs;
|
|
17
|
+
/** The Cookie header's cookies by name, as they came. */
|
|
18
|
+
export declare function parseCookies(header: string): [string, string][];
|
|
19
|
+
/** http.request.cookie.<name>, from the Cookie header; a session id or a CSRF token masked. */
|
|
20
|
+
export declare function cookies(header: string): Attrs;
|
|
21
|
+
/** The request's headers by lower-case name, from Node's IncomingMessage or a fetch Request. */
|
|
22
|
+
export type RequestHeaders = Record<string, string | string[] | undefined>;
|
|
23
|
+
/** What the request carried before the app read it: its headers, query and cookies. */
|
|
24
|
+
export declare function requestAttrs(requested: RequestHeaders, search: string): Attrs;
|
|
25
|
+
/** The query string of a request's URL (/books?page=2 -> ?page=2). */
|
|
26
|
+
export declare function searchOf(url: string): string;
|
|
27
|
+
export declare function cut(text: string): Attrs;
|
|
28
|
+
/** A JSON value with the values under sensitive keys masked, at any depth. */
|
|
29
|
+
export declare function masked(value: unknown): unknown;
|
|
30
|
+
/** A form's fields as they would have been sent, sensitive values masked, then its files by name and size. */
|
|
31
|
+
export declare function formText(fields: Iterable<[string, unknown]>, files?: [string, string, number][]): string;
|
|
32
|
+
export declare function kindOf(contentType: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* http.request.body from the bytes the app read, as far as it read them: JSON and forms with secrets masked, text as
|
|
35
|
+
* it is, binary not. `complete` is false when only the start of the body is at hand: JSON or a form can't be read
|
|
36
|
+
* (nor its secrets masked) from a part of it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function readBody(contentType: string, data: Uint8Array, complete: boolean): Attrs;
|
|
39
|
+
/** What a request's body parser left on it: `req.body`, and `req.file`/`req.files` of an upload. */
|
|
40
|
+
export interface ParsedBody {
|
|
41
|
+
contentType: string;
|
|
42
|
+
body: unknown;
|
|
43
|
+
file?: unknown;
|
|
44
|
+
files?: unknown;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* http.request.body from what the app's body parser read: JSON and forms with secrets masked, text as it is, an
|
|
48
|
+
* upload's files by name and size. Nothing when no parser read it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function parsedBody({ contentType, body, file, files }: ParsedBody): Attrs;
|
|
51
|
+
/** Whether a request came with a body: one declared by its size, or sent in chunks. */
|
|
52
|
+
export declare function hasBody(requested: RequestHeaders): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The requests that answered a page's navigation with a redirect, by id, on the way to the page the widget will see:
|
|
55
|
+
* its panel lists them before that page (a form's POST, then the page it redirected to).
|
|
56
|
+
*/
|
|
57
|
+
export declare const REDIRECTS = "tracepanel_redirect";
|
|
58
|
+
/** Whether the browser asked for a page to show (a link, a form): not fetch() or an image. */
|
|
59
|
+
export declare function navigated(requested: RequestHeaders): boolean;
|
|
60
|
+
/** The Set-Cookie naming this request too, for a redirect that answers a page's navigation; undefined otherwise. */
|
|
61
|
+
export declare function redirectCookie(id: string, status: number, requested: RequestHeaders): string | undefined;
|
package/dist/request.js
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// What a request carried, as attributes of its trace: headers, query, cookies, the body the app read, the response's
|
|
2
|
+
// headers; and the cookie that tells the widget which requests redirected to the page it is on.
|
|
3
|
+
//
|
|
4
|
+
// They stay on this machine (the agent keeps them out of what it sends anywhere), and the values under a sensitive
|
|
5
|
+
// name are masked before they are recorded. A body is only what the app read itself, up to MAX_BODY characters: a
|
|
6
|
+
// body parser's `req.body`, or the bytes the app's own reads took from the request's stream (body.ts). Tracepanel
|
|
7
|
+
// never reads a request's stream for the app.
|
|
8
|
+
/** How much of a body is kept, in characters. */
|
|
9
|
+
export const MAX_BODY = 16_384;
|
|
10
|
+
export const MASK = "********";
|
|
11
|
+
const SENSITIVE = /pass(word|wd)?|secret|token|api_?key|auth|cookie|session|csrf|signature|private/i;
|
|
12
|
+
/** A response's cookies are a session's keys, whatever their name. */
|
|
13
|
+
const ALWAYS_MASKED = new Set(["set-cookie"]);
|
|
14
|
+
/** A form as people read it: encoded, but its spaces, masks and file notes as they are. */
|
|
15
|
+
const READABLE = /^[A-Za-z0-9_.~*<>,. /:@-]$/;
|
|
16
|
+
/** A query's values: encoded as a form's, `+` for a space, masks and paths as they are. */
|
|
17
|
+
const QUERY_SAFE = /^[A-Za-z0-9_.~*/:-]$/;
|
|
18
|
+
/** A name as one segment of an attribute's key (content-type -> content_type), as the trace format has keys. */
|
|
19
|
+
export function key(name) {
|
|
20
|
+
return name.toLowerCase().replace(/[^a-z0-9_]/g, "_") || "_";
|
|
21
|
+
}
|
|
22
|
+
/** Whether a secret goes under the name: x-api-key, csrftoken, sessionid, password. */
|
|
23
|
+
export function sensitive(name) {
|
|
24
|
+
return SENSITIVE.test(name.replaceAll("-", "_"));
|
|
25
|
+
}
|
|
26
|
+
/** A header's value as one string: several values joined, as Node joins them. */
|
|
27
|
+
export function headerValue(value) {
|
|
28
|
+
if (value === undefined || value === null)
|
|
29
|
+
return undefined;
|
|
30
|
+
return Array.isArray(value) ? value.map(String).join(", ") : String(value);
|
|
31
|
+
}
|
|
32
|
+
function headers(prefix, entries) {
|
|
33
|
+
const found = {};
|
|
34
|
+
for (const [name, raw] of entries) {
|
|
35
|
+
const value = headerValue(raw);
|
|
36
|
+
if (!value)
|
|
37
|
+
continue;
|
|
38
|
+
const lowered = name.toLowerCase();
|
|
39
|
+
const attr = `${prefix}${key(lowered)}`;
|
|
40
|
+
if (ALWAYS_MASKED.has(lowered) || sensitive(lowered))
|
|
41
|
+
found[attr] = MASK;
|
|
42
|
+
else
|
|
43
|
+
found[attr] = attr in found ? `${found[attr]}, ${value}` : value;
|
|
44
|
+
}
|
|
45
|
+
return found;
|
|
46
|
+
}
|
|
47
|
+
/** http.request.header.<name>, the name as a key; Cookie is read as cookies instead. */
|
|
48
|
+
export function requestHeaders(entries) {
|
|
49
|
+
return headers("http.request.header.", [...entries].filter(([name]) => name.toLowerCase() !== "cookie"));
|
|
50
|
+
}
|
|
51
|
+
/** http.response.header.<name>: several values joined, Set-Cookie masked. */
|
|
52
|
+
export function responseHeaders(entries) {
|
|
53
|
+
return headers("http.response.header.", entries);
|
|
54
|
+
}
|
|
55
|
+
/** Percent-encoded but for the characters `safe` keeps; a space as `+` when `plus`. */
|
|
56
|
+
function quote(text, safe, plus = false) {
|
|
57
|
+
let out = "";
|
|
58
|
+
for (const char of text) {
|
|
59
|
+
if (plus && char === " ")
|
|
60
|
+
out += "+";
|
|
61
|
+
else if (safe.test(char))
|
|
62
|
+
out += char;
|
|
63
|
+
else
|
|
64
|
+
for (const byte of Buffer.from(char))
|
|
65
|
+
out += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`;
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/** url.query: the query string, the values of sensitive parameters masked. */
|
|
70
|
+
export function query(search) {
|
|
71
|
+
const raw = search.startsWith("?") ? search.slice(1) : search;
|
|
72
|
+
if (!raw)
|
|
73
|
+
return {};
|
|
74
|
+
const pairs = [...new URLSearchParams(raw)].map(([name, value]) => `${quote(name, QUERY_SAFE, true)}=${quote(sensitive(name) ? MASK : value, QUERY_SAFE, true)}`);
|
|
75
|
+
return { "url.query": pairs.join("&") };
|
|
76
|
+
}
|
|
77
|
+
/** The Cookie header's cookies by name, as they came. */
|
|
78
|
+
export function parseCookies(header) {
|
|
79
|
+
const found = [];
|
|
80
|
+
for (const part of header.split(";")) {
|
|
81
|
+
const at = part.indexOf("=");
|
|
82
|
+
const name = part.slice(0, at).trim();
|
|
83
|
+
if (at >= 0 && name)
|
|
84
|
+
found.push([name, part.slice(at + 1).trim()]);
|
|
85
|
+
}
|
|
86
|
+
return found;
|
|
87
|
+
}
|
|
88
|
+
/** http.request.cookie.<name>, from the Cookie header; a session id or a CSRF token masked. */
|
|
89
|
+
export function cookies(header) {
|
|
90
|
+
return Object.fromEntries(parseCookies(header).map(([name, value]) => [`http.request.cookie.${key(name)}`, sensitive(name) ? MASK : value]));
|
|
91
|
+
}
|
|
92
|
+
/** What the request carried before the app read it: its headers, query and cookies. */
|
|
93
|
+
export function requestAttrs(requested, search) {
|
|
94
|
+
return {
|
|
95
|
+
...requestHeaders(Object.entries(requested)),
|
|
96
|
+
...query(search),
|
|
97
|
+
...cookies(headerValue(requested.cookie) ?? ""),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** The query string of a request's URL (/books?page=2 -> ?page=2). */
|
|
101
|
+
export function searchOf(url) {
|
|
102
|
+
const at = url.indexOf("?");
|
|
103
|
+
return at < 0 ? "" : url.slice(at);
|
|
104
|
+
}
|
|
105
|
+
export function cut(text) {
|
|
106
|
+
if (text.length <= MAX_BODY)
|
|
107
|
+
return { "http.request.body": text };
|
|
108
|
+
return { "http.request.body": text.slice(0, MAX_BODY), "http.request.body.truncated": true };
|
|
109
|
+
}
|
|
110
|
+
/** A JSON value with the values under sensitive keys masked, at any depth. */
|
|
111
|
+
export function masked(value) {
|
|
112
|
+
if (Array.isArray(value))
|
|
113
|
+
return value.map(masked);
|
|
114
|
+
if (value !== null && typeof value === "object") {
|
|
115
|
+
return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, sensitive(name) ? MASK : masked(item)]));
|
|
116
|
+
}
|
|
117
|
+
return value;
|
|
118
|
+
}
|
|
119
|
+
/** A form's fields as they would have been sent, sensitive values masked, then its files by name and size. */
|
|
120
|
+
export function formText(fields, files = []) {
|
|
121
|
+
const pairs = [];
|
|
122
|
+
for (const [name, value] of fields) {
|
|
123
|
+
if (sensitive(name))
|
|
124
|
+
pairs.push([name, MASK]);
|
|
125
|
+
else if (Array.isArray(value))
|
|
126
|
+
for (const item of value)
|
|
127
|
+
pairs.push([name, plain(item)]);
|
|
128
|
+
else
|
|
129
|
+
pairs.push([name, plain(value)]);
|
|
130
|
+
}
|
|
131
|
+
for (const [field, name, size] of files)
|
|
132
|
+
pairs.push([field, `<file ${name}, ${size} bytes>`]);
|
|
133
|
+
return pairs.map(([name, value]) => `${quote(name, READABLE)}=${quote(value, READABLE)}`).join("&");
|
|
134
|
+
}
|
|
135
|
+
/** A form's value as text: a nested one (qs's `a[b]=c`) as JSON, its secrets masked. */
|
|
136
|
+
function plain(value) {
|
|
137
|
+
return value !== null && typeof value === "object" ? JSON.stringify(masked(value)) : String(value ?? "");
|
|
138
|
+
}
|
|
139
|
+
export function kindOf(contentType) {
|
|
140
|
+
return (contentType.split(";", 1)[0] ?? "").trim().toLowerCase();
|
|
141
|
+
}
|
|
142
|
+
function isJson(kind) {
|
|
143
|
+
return kind === "application/json" || kind.endsWith("+json");
|
|
144
|
+
}
|
|
145
|
+
function isForm(kind) {
|
|
146
|
+
return kind === "application/x-www-form-urlencoded" || kind === "multipart/form-data";
|
|
147
|
+
}
|
|
148
|
+
/** A body read as text (a text or raw parser's): JSON and forms with secrets masked, text as it is, binary not. */
|
|
149
|
+
function textBody(contentType, text) {
|
|
150
|
+
const kind = kindOf(contentType);
|
|
151
|
+
if (!text)
|
|
152
|
+
return {};
|
|
153
|
+
if (isJson(kind)) {
|
|
154
|
+
try {
|
|
155
|
+
return cut(JSON.stringify(masked(JSON.parse(text))));
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return cut(text);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (kind === "application/x-www-form-urlencoded")
|
|
162
|
+
return cut(formText(new URLSearchParams(text)));
|
|
163
|
+
if (kind.startsWith("text/") || kind === "application/xml" || kind === "application/graphql")
|
|
164
|
+
return cut(text);
|
|
165
|
+
return {};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* http.request.body from the bytes the app read, as far as it read them: JSON and forms with secrets masked, text as
|
|
169
|
+
* it is, binary not. `complete` is false when only the start of the body is at hand: JSON or a form can't be read
|
|
170
|
+
* (nor its secrets masked) from a part of it.
|
|
171
|
+
*/
|
|
172
|
+
export function readBody(contentType, data, complete) {
|
|
173
|
+
const kind = kindOf(contentType);
|
|
174
|
+
if (data.length === 0 || (!complete && (isJson(kind) || isForm(kind))))
|
|
175
|
+
return {};
|
|
176
|
+
return textBody(contentType, Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("utf8"));
|
|
177
|
+
}
|
|
178
|
+
function uploads(file, files) {
|
|
179
|
+
const all = [];
|
|
180
|
+
if (file)
|
|
181
|
+
all.push(file);
|
|
182
|
+
if (Array.isArray(files))
|
|
183
|
+
all.push(...files);
|
|
184
|
+
else if (files && typeof files === "object")
|
|
185
|
+
for (const list of Object.values(files))
|
|
186
|
+
all.push(...[list].flat());
|
|
187
|
+
return all
|
|
188
|
+
.filter((item) => item !== null && typeof item === "object")
|
|
189
|
+
.map((item) => [String(item.fieldname ?? ""), String(item.originalname ?? ""), Number(item.size ?? 0)]);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* http.request.body from what the app's body parser read: JSON and forms with secrets masked, text as it is, an
|
|
193
|
+
* upload's files by name and size. Nothing when no parser read it.
|
|
194
|
+
*/
|
|
195
|
+
export function parsedBody({ contentType, body, file, files }) {
|
|
196
|
+
const kind = kindOf(contentType);
|
|
197
|
+
const sent = uploads(file, files);
|
|
198
|
+
if (typeof body === "string")
|
|
199
|
+
return textBody(contentType, body);
|
|
200
|
+
if (body instanceof Uint8Array)
|
|
201
|
+
return textBody(contentType, Buffer.from(body).toString("utf8"));
|
|
202
|
+
if (body === undefined || body === null)
|
|
203
|
+
return sent.length > 0 ? cut(formText([], sent)) : {};
|
|
204
|
+
if (typeof body !== "object")
|
|
205
|
+
return cut(JSON.stringify(body));
|
|
206
|
+
if (isForm(kind)) {
|
|
207
|
+
const text = formText(Object.entries(body), sent);
|
|
208
|
+
return text ? cut(text) : {};
|
|
209
|
+
}
|
|
210
|
+
return cut(JSON.stringify(masked(body)));
|
|
211
|
+
}
|
|
212
|
+
/** Whether a request came with a body: one declared by its size, or sent in chunks. */
|
|
213
|
+
export function hasBody(requested) {
|
|
214
|
+
const length = Number(headerValue(requested["content-length"]) ?? 0);
|
|
215
|
+
return length > 0 || (headerValue(requested["transfer-encoding"]) ?? "").toLowerCase().includes("chunked");
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The requests that answered a page's navigation with a redirect, by id, on the way to the page the widget will see:
|
|
219
|
+
* its panel lists them before that page (a form's POST, then the page it redirected to).
|
|
220
|
+
*/
|
|
221
|
+
export const REDIRECTS = "tracepanel_redirect";
|
|
222
|
+
/** How many redirects in a row are kept: a loop of them doesn't grow the cookie without end. */
|
|
223
|
+
const MAX_REDIRECTS = 5;
|
|
224
|
+
/** Whether the browser asked for a page to show (a link, a form): not fetch() or an image. */
|
|
225
|
+
export function navigated(requested) {
|
|
226
|
+
const mode = headerValue(requested["sec-fetch-mode"]);
|
|
227
|
+
return mode !== undefined ? mode === "navigate" : (headerValue(requested.accept) ?? "").includes("text/html");
|
|
228
|
+
}
|
|
229
|
+
/** The Set-Cookie naming this request too, for a redirect that answers a page's navigation; undefined otherwise. */
|
|
230
|
+
export function redirectCookie(id, status, requested) {
|
|
231
|
+
if (status < 300 || status >= 400 || !navigated(requested))
|
|
232
|
+
return undefined;
|
|
233
|
+
const sent = parseCookies(headerValue(requested.cookie) ?? "").find(([name]) => name === REDIRECTS)?.[1] ?? "";
|
|
234
|
+
let before;
|
|
235
|
+
try {
|
|
236
|
+
before = decodeURIComponent(sent).split(",").filter(Boolean);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
before = [];
|
|
240
|
+
}
|
|
241
|
+
const value = encodeURIComponent([...before, id].slice(-MAX_REDIRECTS).join(","));
|
|
242
|
+
return `${REDIRECTS}=${value}; Max-Age=30; Path=/; SameSite=Lax`;
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.js","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Attrs } from "./model.js";
|
|
2
|
+
/** session.<key> of a session's entries, under a prefix of its own when there are several (session.<name>.<key>). */
|
|
3
|
+
export declare function sessionAttrs(entries: Iterable<[string, unknown]>, prefix?: string): Attrs;
|
|
4
|
+
/**
|
|
5
|
+
* The session express-session or cookie-session put on an Express request, as the handler left it; none without one.
|
|
6
|
+
* express-session's `cookie` is the session cookie's settings, not what the app keeps in it.
|
|
7
|
+
*/
|
|
8
|
+
export declare function expressSession(session: unknown): Attrs;
|
|
9
|
+
/** h3's sessions as the request left them (`event.context.sessions`), by name: those `useSession()` read. */
|
|
10
|
+
export declare function h3Sessions(sessions: unknown): Attrs;
|