@tracepanel/js 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +71 -4
  2. package/dist/agent.d.ts +25 -2
  3. package/dist/agent.js +75 -24
  4. package/dist/agent.js.map +1 -1
  5. package/dist/body.d.ts +32 -0
  6. package/dist/body.js +314 -0
  7. package/dist/body.js.map +1 -0
  8. package/dist/browser.d.ts +2 -2
  9. package/dist/browser.js +15 -7
  10. package/dist/browser.js.map +1 -1
  11. package/dist/bullmq.d.ts +76 -1
  12. package/dist/bullmq.js +215 -6
  13. package/dist/bullmq.js.map +1 -1
  14. package/dist/bun.js +81 -11
  15. package/dist/bun.js.map +1 -1
  16. package/dist/config.d.ts +20 -0
  17. package/dist/config.js +13 -0
  18. package/dist/config.js.map +1 -1
  19. package/dist/console.d.ts +5 -0
  20. package/dist/console.js +16 -0
  21. package/dist/console.js.map +1 -1
  22. package/dist/express.js +94 -23
  23. package/dist/express.js.map +1 -1
  24. package/dist/headers.js +54 -8
  25. package/dist/headers.js.map +1 -1
  26. package/dist/inspector.d.ts +9 -0
  27. package/dist/inspector.js +47 -0
  28. package/dist/inspector.js.map +1 -0
  29. package/dist/locals.d.ts +51 -0
  30. package/dist/locals.js +269 -0
  31. package/dist/locals.js.map +1 -0
  32. package/dist/loggers.d.ts +50 -0
  33. package/dist/loggers.js +201 -0
  34. package/dist/loggers.js.map +1 -0
  35. package/dist/model.d.ts +23 -2
  36. package/dist/model.js.map +1 -1
  37. package/dist/next-widget.d.ts +13 -2
  38. package/dist/next-widget.js +16 -6
  39. package/dist/next-widget.js.map +1 -1
  40. package/dist/next.d.ts +6 -0
  41. package/dist/next.js +63 -2
  42. package/dist/next.js.map +1 -1
  43. package/dist/nuxt-plugin.d.ts +1 -0
  44. package/dist/nuxt-plugin.js +6 -0
  45. package/dist/nuxt-plugin.js.map +1 -1
  46. package/dist/processor.d.ts +23 -2
  47. package/dist/processor.js +65 -17
  48. package/dist/processor.js.map +1 -1
  49. package/dist/profile.d.ts +63 -0
  50. package/dist/profile.js +300 -0
  51. package/dist/profile.js.map +1 -0
  52. package/dist/proxy.d.ts +22 -0
  53. package/dist/proxy.js +72 -0
  54. package/dist/proxy.js.map +1 -0
  55. package/dist/request.d.ts +61 -0
  56. package/dist/request.js +244 -0
  57. package/dist/request.js.map +1 -0
  58. package/dist/runtime.d.ts +9 -0
  59. package/dist/runtime.js.map +1 -1
  60. package/dist/session.d.ts +10 -0
  61. package/dist/session.js +45 -0
  62. package/dist/session.js.map +1 -0
  63. package/dist/setup.js +10 -1
  64. package/dist/setup.js.map +1 -1
  65. package/dist/stack.d.ts +27 -3
  66. package/dist/stack.js +106 -9
  67. package/dist/stack.js.map +1 -1
  68. package/dist/vite.d.ts +1 -1
  69. package/dist/vite.js +2 -45
  70. package/dist/vite.js.map +1 -1
  71. package/dist/widget.d.ts +24 -0
  72. package/dist/widget.js +66 -3
  73. package/dist/widget.js.map +1 -1
  74. package/package.json +17 -5
package/dist/express.js CHANGED
@@ -1,7 +1,13 @@
1
1
  // `app.use(tracepanel())`: every response gets what the badge reads (Tracepanel-Id, Server-Timing), and HTML pages
2
- // get widget.min.js. The response is held until the handler ends it: a page or a JSON answer, not a stream.
2
+ // get widget.min.js. A response the handler ends at once (a page, a JSON answer) is held until then; one written in
3
+ // pieces without a Content-Length is a stream, and goes out as it comes, an HTML page with the script put in as it
4
+ // passes. What the request carried goes into its trace as the response goes out: its headers, query, cookies, the
5
+ // body a body parser read (`req.body`, an upload's files), the session (`req.session`), and the response's headers. A redirect that answers a
6
+ // page's navigation (a form's POST) sets the cookie that shows it in the next page's panel.
7
+ import { hasBody, parsedBody, redirectCookie, requestAttrs, responseHeaders, searchOf } from "./request.js";
3
8
  import { runtime } from "./runtime.js";
4
- import { badge, exposedHeaders, inject } from "./widget.js";
9
+ import { expressSession } from "./session.js";
10
+ import { badge, exposedHeaders, inject, Stream, streamablePage } from "./widget.js";
5
11
  function toBuffer(chunk, encoding) {
6
12
  if (Buffer.isBuffer(chunk))
7
13
  return chunk;
@@ -9,6 +15,27 @@ function toBuffer(chunk, encoding) {
9
15
  return Buffer.from(chunk);
10
16
  return Buffer.from(String(chunk), encoding);
11
17
  }
18
+ /**
19
+ * What the request carried, the body as far as the app's body parser read it, the session as the handler left it
20
+ * (express-session's, cookie-session's), and the response's headers so far.
21
+ */
22
+ function carried(req, res) {
23
+ const upload = req;
24
+ const body = hasBody(req.headers)
25
+ ? parsedBody({
26
+ contentType: req.headers["content-type"] ?? "",
27
+ body: req.body,
28
+ file: upload.file,
29
+ files: upload.files,
30
+ })
31
+ : {};
32
+ return {
33
+ ...requestAttrs(req.headers, searchOf(req.originalUrl ?? req.url)),
34
+ ...body,
35
+ ...expressSession(upload.session),
36
+ ...responseHeaders(Object.entries(res.getHeaders())),
37
+ };
38
+ }
12
39
  export function tracepanel() {
13
40
  const tp = runtime();
14
41
  return function tracepanelMiddleware(req, res, next) {
@@ -22,15 +49,60 @@ export function tracepanel() {
22
49
  const write = res.write.bind(res);
23
50
  const end = res.end.bind(res);
24
51
  let streaming = false;
52
+ // A streamed HTML page: what puts the script into it.
53
+ let script;
25
54
  const flushHeld = () => {
26
55
  if (chunks.length > 0)
27
56
  write(Buffer.concat(chunks.splice(0)));
28
57
  };
58
+ let recorded = false;
59
+ /** What the request carried, into its trace once, before the badge's headers join the response's. */
60
+ const record = () => {
61
+ if (recorded || !tp.config.captureRequest)
62
+ return;
63
+ recorded = true;
64
+ tp.processor.setTraceAttrs(carried(req, res));
65
+ };
66
+ /** The badge's headers on the response; its script tag when it is a page that gets one. */
67
+ const mark = (page) => {
68
+ record();
69
+ const framework = tp.processor.framework() ?? "Express";
70
+ const marks = badge(tp, { method: req.method, status: res.statusCode, startedMs, page, framework });
71
+ if (!marks)
72
+ return undefined;
73
+ for (const [name, value] of Object.entries(marks.headers))
74
+ res.setHeader(name, value);
75
+ const redirect = redirectCookie(marks.headers["Tracepanel-Id"] ?? "", res.statusCode, req.headers);
76
+ if (redirect)
77
+ res.appendHeader("Set-Cookie", redirect);
78
+ const expose = exposedHeaders(res.getHeader("access-control-allow-origin"), res.getHeader("access-control-expose-headers"));
79
+ if (expose)
80
+ res.setHeader("Access-Control-Expose-Headers", expose);
81
+ return marks.script;
82
+ };
83
+ /** A stream: the badge's headers now, with the time so far, and the script for an HTML page as it is. */
84
+ const startStream = () => {
85
+ streaming = true;
86
+ if (res.headersSent) {
87
+ record();
88
+ return;
89
+ }
90
+ const page = streamablePage((name) => res.getHeader(name));
91
+ const tag = mark(page);
92
+ if (page && tag)
93
+ script = new Stream(tag);
94
+ };
29
95
  res.write = ((chunk, encoding, callback) => {
30
- if (streaming || String(res.getHeader("content-type")).includes("text/event-stream")) {
31
- streaming = true;
96
+ // Its size declared, a body in pieces is held whole like a page ended at once; without one it is a stream.
97
+ if (!streaming && res.getHeader("content-length") === undefined)
98
+ startStream();
99
+ if (streaming) {
32
100
  flushHeld();
33
- return write(chunk, encoding, callback);
101
+ if (!script)
102
+ return write(chunk, encoding, callback);
103
+ const done = (typeof encoding === "function" ? encoding : callback);
104
+ const piece = toBuffer(chunk, typeof encoding === "string" ? encoding : undefined);
105
+ return done ? write(script.feed(piece), done) : write(script.feed(piece));
34
106
  }
35
107
  chunks.push(toBuffer(chunk, typeof encoding === "string" ? encoding : undefined));
36
108
  if (typeof encoding === "function")
@@ -43,30 +115,29 @@ export function tracepanel() {
43
115
  res.write = write;
44
116
  res.end = end;
45
117
  if (typeof chunk === "function")
46
- return end(chunk);
47
- if (chunk !== undefined && chunk !== null && !streaming) {
48
- chunks.push(toBuffer(chunk, typeof encoding === "string" ? encoding : undefined));
49
- }
50
- else if (streaming && chunk !== undefined && chunk !== null) {
51
- return end(chunk, encoding, callback);
118
+ [chunk, encoding, callback] = [undefined, undefined, chunk];
119
+ else if (typeof encoding === "function")
120
+ [encoding, callback] = [undefined, encoding];
121
+ const last = chunk === undefined || chunk === null
122
+ ? undefined
123
+ : toBuffer(chunk, typeof encoding === "string" ? encoding : undefined);
124
+ if (streaming) {
125
+ flushHeld();
126
+ const rest = script ? Buffer.concat([script.feed(last ?? Buffer.alloc(0)), script.end()]) : last;
127
+ return rest && rest.length > 0 ? end(rest, callback) : end(callback);
52
128
  }
53
- if (streaming || res.headersSent) {
129
+ if (last)
130
+ chunks.push(last);
131
+ if (res.headersSent) {
132
+ record();
54
133
  flushHeld();
55
134
  return end(callback);
56
135
  }
57
136
  let body = Buffer.concat(chunks);
58
137
  const page = String(res.getHeader("content-type") ?? "").includes("text/html");
59
- const framework = tp.processor.framework() ?? "Express";
60
- const marks = badge(tp, { method: req.method, status: res.statusCode, startedMs, page, framework });
61
- if (marks) {
62
- for (const [name, value] of Object.entries(marks.headers))
63
- res.setHeader(name, value);
64
- const expose = exposedHeaders(res.getHeader("access-control-allow-origin"), res.getHeader("access-control-expose-headers"));
65
- if (expose)
66
- res.setHeader("Access-Control-Expose-Headers", expose);
67
- if (marks.script)
68
- body = Buffer.from(inject(body.toString("utf8"), marks.script));
69
- }
138
+ const tag = mark(page);
139
+ if (tag)
140
+ body = Buffer.from(inject(body.toString("utf8"), tag));
70
141
  if (!res.getHeader("transfer-encoding"))
71
142
  res.setHeader("Content-Length", body.length);
72
143
  return end(body, callback);
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,oHAAoH;AACpH,mHAAmH;AACnH,kHAAkH;AAClH,8IAA8I;AAC9I,4FAA4F;AAI5F,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC5G,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAMpF,SAAS,QAAQ,CAAC,KAAc,EAAE,QAAyB;IACzD,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,KAAK,YAAY,UAAU;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3D,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAS,OAAO,CAAC,GAAY,EAAE,GAAa;IAC1C,MAAM,MAAM,GAAG,GAAuE,CAAC;IACvF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAC/B,CAAC,CAAC,UAAU,CAAC;YACT,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE;YAC9C,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC;QACJ,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;QACL,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAClE,GAAG,IAAI;QACP,GAAG,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC;QACjC,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IACrB,OAAO,SAAS,oBAAoB,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;QAClF,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,EAAE,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAU,CAAC;QAC3C,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAQ,CAAC;QACrC,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,sDAAsD;QACtD,IAAI,MAA0B,CAAC;QAE/B,MAAM,SAAS,GAAG,GAAG,EAAE;YACrB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC,CAAC;QAEF,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,qGAAqG;QACrG,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc;gBAAE,OAAO;YAClD,QAAQ,GAAG,IAAI,CAAC;YAChB,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC;QAEF,2FAA2F;QAC3F,MAAM,IAAI,GAAG,CAAC,IAAa,EAAsB,EAAE;YACjD,MAAM,EAAE,CAAC;YACT,MAAM,SAAS,GAAG,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,SAAS,CAAC;YACxD,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;YACpG,IAAI,CAAC,KAAK;gBAAE,OAAO,SAAS,CAAC;YAC7B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;gBAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACtF,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YACnG,IAAI,QAAQ;gBAAE,GAAG,CAAC,YAAY,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;YACvD,MAAM,MAAM,GAAG,cAAc,CAC3B,GAAG,CAAC,SAAS,CAAC,6BAA6B,CAAC,EAC5C,GAAG,CAAC,SAAS,CAAC,+BAA+B,CAAC,CAC/C,CAAC;YACF,IAAI,MAAM;gBAAE,GAAG,CAAC,SAAS,CAAC,+BAA+B,EAAE,MAAM,CAAC,CAAC;YACnE,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC,CAAC;QAEF,yGAAyG;QACzG,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,SAAS,GAAG,IAAI,CAAC;YACjB,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,MAAM,EAAE,CAAC;gBACT,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAG,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC3D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,IAAI,IAAI,GAAG;gBAAE,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5C,CAAC,CAAC;QAEF,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,KAAc,EAAE,QAAkB,EAAE,QAAkB,EAAE,EAAE;YACtE,2GAA2G;YAC3G,IAAI,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,SAAS;gBAAE,WAAW,EAAE,CAAC;YAC/E,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,EAAE,CAAC;gBACZ,IAAI,CAAC,MAAM;oBAAE,OAAO,KAAK,CAAC,KAAc,EAAE,QAAiB,EAAE,QAAiB,CAAC,CAAC;gBAChF,MAAM,IAAI,GAAG,CAAC,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAyB,CAAC;gBAC5F,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAE,QAA2B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;gBACvG,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAC5E,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAE,QAA2B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;YACtG,IAAI,OAAO,QAAQ,KAAK,UAAU;gBAAG,QAAuB,EAAE,CAAC;iBAC1D,IAAI,OAAO,QAAQ,KAAK,UAAU;gBAAG,QAAuB,EAAE,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC,CAAU,CAAC;QAEZ,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,KAAe,EAAE,QAAkB,EAAE,QAAkB,EAAE,EAAE;YACrE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;YAClB,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC;YACd,IAAI,OAAO,KAAK,KAAK,UAAU;gBAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;iBACxF,IAAI,OAAO,QAAQ,KAAK,UAAU;gBAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YACtF,MAAM,IAAI,GACR,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;gBACnC,CAAC,CAAC,SAAS;gBACX,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAE,QAA2B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YAC/F,IAAI,SAAS,EAAE,CAAC;gBACd,SAAS,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBACjG,OAAO,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,QAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAiB,CAAC,CAAC;YACzF,CAAC;YACD,IAAI,IAAI;gBAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,MAAM,EAAE,CAAC;gBACT,SAAS,EAAE,CAAC;gBACZ,OAAO,GAAG,CAAC,QAAiB,CAAC,CAAC;YAChC,CAAC;YACD,IAAI,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC/E,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,IAAI,GAAG;gBAAE,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YAChE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,mBAAmB,CAAC;gBAAE,GAAG,CAAC,SAAS,CAAC,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YACtF,OAAO,GAAG,CAAC,IAAI,EAAE,QAAiB,CAAC,CAAC;QACtC,CAAC,CAAQ,CAAC;QAEV,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
package/dist/headers.js CHANGED
@@ -1,9 +1,35 @@
1
1
  // For frameworks that answer from their own server (Next.js, Nuxt): every response of a traced request gets what the
2
- // widget and the badge read, Tracepanel-Id, Tracepanel-Url and Server-Timing, as its headers go out.
3
- import { ServerResponse } from "node:http";
2
+ // widget and the badge read, Tracepanel-Id, Tracepanel-Url and Server-Timing, as its headers go out. Then too, what
3
+ // the request carried goes into its trace (headers, query, cookies, the body as far as the framework read it for the
4
+ // app), with the response's headers; and a redirect that answers a page's navigation sets the cookie that shows it in
5
+ // the next page's panel. A request's body is tapped as the server hands the request over: the framework reads it from
6
+ // the stream, and its pieces pass the tap on their way (body.ts).
7
+ import http, { ServerResponse } from "node:http";
8
+ import https from "node:https";
9
+ import { tapIncoming, tapOf } from "./body.js";
10
+ import { hasBody, redirectCookie, requestAttrs, responseHeaders, searchOf } from "./request.js";
4
11
  import { exposedHeaders } from "./widget.js";
5
12
  const PATCHED = Symbol.for("tracepanel.headers");
13
+ const TAPPING = Symbol.for("tracepanel.body.tapping");
14
+ /** The app's HTTP servers (made before this runs too) tap the body of each request that has one. */
15
+ function tapBodies(tracepanel) {
16
+ for (const prototype of [http.Server.prototype, https.Server.prototype]) {
17
+ const server = prototype;
18
+ if (server[TAPPING])
19
+ continue;
20
+ server[TAPPING] = true;
21
+ const emit = server.emit;
22
+ server.emit = function (event, ...args) {
23
+ const req = args[0];
24
+ if (event === "request" && req && tracepanel.config.captureRequest && hasBody(req.headers) && !tapOf(req)) {
25
+ tapIncoming(req);
26
+ }
27
+ return emit.call(this, event, ...args);
28
+ };
29
+ }
30
+ }
6
31
  export function headersOnResponses(tracepanel, framework) {
32
+ tapBodies(tracepanel);
7
33
  const prototype = ServerResponse.prototype;
8
34
  if (prototype[PATCHED])
9
35
  return;
@@ -11,10 +37,24 @@ export function headersOnResponses(tracepanel, framework) {
11
37
  const writeHead = prototype.writeHead;
12
38
  prototype.writeHead = function (...args) {
13
39
  if (!this.headersSent) {
40
+ const method = this.req?.method ?? "GET";
41
+ const url = this.req?.url ?? "/";
42
+ const status = typeof args[0] === "number" ? args[0] : this.statusCode;
43
+ // Headers passed to writeHead itself (an object) count too: CORS middleware often sets them there.
44
+ const given = [args[1], args[2]].find((arg) => arg !== null && typeof arg === "object" && !Array.isArray(arg));
45
+ const passed = (given ?? {});
46
+ if (tracepanel.config.captureRequest && this.req) {
47
+ // Before the badge: a response sent outside the request's context finds its trace by the URL until then.
48
+ tracepanel.processor.setTraceAttrs({
49
+ ...requestAttrs(this.req.headers, searchOf(url)),
50
+ ...tapOf(this.req)?.attrs(),
51
+ ...responseHeaders([...Object.entries(this.getHeaders()), ...Object.entries(passed)]),
52
+ }, { method, url });
53
+ }
14
54
  const marks = tracepanel.badge({
15
- method: this.req?.method ?? "GET",
16
- url: this.req?.url ?? "/",
17
- status: typeof args[0] === "number" ? args[0] : this.statusCode,
55
+ method,
56
+ url,
57
+ status,
18
58
  startedMs: performance.now(),
19
59
  page: false,
20
60
  framework: tracepanel.processor.framework() ?? framework,
@@ -23,13 +63,19 @@ export function headersOnResponses(tracepanel, framework) {
23
63
  if (!this.hasHeader(name))
24
64
  this.setHeader(name, value);
25
65
  }
26
- // Headers passed to writeHead itself (an object) count too: CORS middleware often sets them there.
27
- const given = [args[1], args[2]].find((arg) => arg !== null && typeof arg === "object" && !Array.isArray(arg));
28
- const passed = (given ?? {});
29
66
  const lower = Object.fromEntries(Object.entries(passed ?? {}).map(([name, value]) => [name.toLowerCase(), value]));
30
67
  const expose = marks
31
68
  ? exposedHeaders(this.getHeader("access-control-allow-origin") ?? lower["access-control-allow-origin"], this.getHeader("access-control-expose-headers") ?? lower["access-control-expose-headers"])
32
69
  : undefined;
70
+ const redirect = marks && this.req ? redirectCookie(marks.headers["Tracepanel-Id"] ?? "", status, this.req.headers) : undefined;
71
+ if (redirect) {
72
+ // One passed to writeHead would replace the response's own: the cookie joins it there.
73
+ const named = Object.keys(passed).find((name) => name.toLowerCase() === "set-cookie");
74
+ if (named)
75
+ passed[named] = [...[passed[named]].flat(), redirect];
76
+ else
77
+ this.appendHeader("Set-Cookie", redirect);
78
+ }
33
79
  if (expose) {
34
80
  this.setHeader("Access-Control-Expose-Headers", expose);
35
81
  delete passed["access-control-expose-headers"];
@@ -1 +1 @@
1
- {"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"headers.js","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ type Inspector = typeof import("node:inspector");
2
+ type Session = InstanceType<Inspector["Session"]>;
3
+ /** node:inspector, or null where there is none. */
4
+ export declare function inspector(): Inspector | null;
5
+ /** A session with this thread's inspector, connected; undefined where there is none. */
6
+ export declare function connect(): Session | undefined;
7
+ /** A call on a session of this thread, answered before it returns: its result, or the error it failed with. */
8
+ export declare function call<T = Record<string, unknown>>(session: Session, method: string, params?: object): T;
9
+ export type { Session };
@@ -0,0 +1,47 @@
1
+ // Node's inspector, from inside the app: what the profiler and the error's local variables read. A session in the
2
+ // app's own thread answers each call at once, while the call is made, so both stay synchronous. Loaded on first use:
3
+ // a Node built without the inspector, and Bun, which has none to speak of, get neither feature and nothing breaks.
4
+ import { createRequire } from "node:module";
5
+ let loaded;
6
+ /** node:inspector, or null where there is none. */
7
+ export function inspector() {
8
+ if (loaded !== undefined)
9
+ return loaded;
10
+ loaded = null;
11
+ if (process.versions.bun !== undefined || !process.features.inspector)
12
+ return loaded;
13
+ try {
14
+ loaded = createRequire(import.meta.url)("node:inspector");
15
+ }
16
+ catch {
17
+ // Not in this build of Node.
18
+ }
19
+ return loaded;
20
+ }
21
+ /** A session with this thread's inspector, connected; undefined where there is none. */
22
+ export function connect() {
23
+ const found = inspector();
24
+ if (!found)
25
+ return undefined;
26
+ try {
27
+ const session = new found.Session();
28
+ session.connect();
29
+ return session;
30
+ }
31
+ catch {
32
+ return undefined;
33
+ }
34
+ }
35
+ /** A call on a session of this thread, answered before it returns: its result, or the error it failed with. */
36
+ export function call(session, method, params) {
37
+ let failure = null;
38
+ let result;
39
+ session.post(method, params ?? {}, (error, answer) => {
40
+ failure = error;
41
+ result = answer;
42
+ });
43
+ if (failure)
44
+ throw failure;
45
+ return result;
46
+ }
47
+ //# sourceMappingURL=inspector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspector.js","sourceRoot":"","sources":["../src/inspector.ts"],"names":[],"mappings":"AAAA,kHAAkH;AAClH,qHAAqH;AACrH,mHAAmH;AAEnH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAK5C,IAAI,MAAoC,CAAC;AAEzC,mDAAmD;AACnD,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,GAAG,IAAI,CAAC;IACd,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC;IACrF,IAAI,CAAC;QACH,MAAM,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAc,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,OAAO;IACrB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACpC,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,IAAI,CAA8B,OAAgB,EAAE,MAAc,EAAE,MAAe;IACjG,IAAI,OAAO,GAAiB,IAAI,CAAC;IACjC,IAAI,MAAe,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,KAAmB,EAAE,MAAgB,EAAE,EAAE;QAC3E,OAAO,GAAG,KAAK,CAAC;QAChB,MAAM,GAAG,MAAM,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,IAAI,OAAO;QAAE,MAAM,OAAO,CAAC;IAC3B,OAAO,MAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /** The local variables of an error's frames, by the frame's place in its stack (innermost first). */
2
+ export type FrameLocals = (Record<string, string> | undefined)[];
3
+ /**
4
+ * A value as the console shows it, as Python's reprlib cuts one: a plain object, an array, a Map or a Set by its
5
+ * items, nested two deep, ten of each at most; anything else (a class's instance: a request, a connection) and a
6
+ * string at most 160 characters. Masked under a sensitive name.
7
+ */
8
+ export declare function repr(name: string, value: unknown): string;
9
+ /** A frame's variables as text, from its scope objects, innermost first: an inner name hides an outer one. */
10
+ export declare function variables(scopes: object[]): Record<string, string>;
11
+ /** Whether an error, by its stack, is one Next.js throws to steer a render. */
12
+ export declare function steers(stack: string): boolean;
13
+ /** Reads the locals of errors thrown in a trace, for its errors to carry. */
14
+ export declare class Locals {
15
+ private readonly session;
16
+ private readonly root;
17
+ private readonly traceId;
18
+ private tracing;
19
+ private limited;
20
+ private second;
21
+ private pauses;
22
+ private state;
23
+ /** The objects the hook was passed. */
24
+ private received;
25
+ /**
26
+ * What was read, by the error's stack (its trace records that), and the trace it was thrown in. Thrown again in the
27
+ * same trace, an error keeps its first throw's.
28
+ */
29
+ private readonly errors;
30
+ private readonly hookName;
31
+ private constructor();
32
+ /** The reader, with the inspector's debugger on; undefined where there is none, or a debugger is attached. */
33
+ static start(root: string, traceId: () => string | undefined): Locals | undefined;
34
+ /** Whether a trace runs: errors pause only then. */
35
+ traces(running: boolean): void;
36
+ /** The locals read for the error with this stack, taken: each error's are given once. */
37
+ take(stack: string | undefined): FrameLocals | undefined;
38
+ private pauseOn;
39
+ /** At most MAX_PAUSES a second: past them, no pause until the second is over. */
40
+ private budget;
41
+ /** The objects of these ids, handed over by the paused app: called on `objectId`, the hook is passed them. */
42
+ private objects;
43
+ private paused;
44
+ /**
45
+ * The app's frames of the error's stack and the scopes of the frames that run them, paired by line or name: both go
46
+ * from the throw outwards. The stack's `async` callers have no frame running; its innermost frame may have none
47
+ * either, an error made in a helper and thrown by its caller. An error thrown again elsewhere (made outside a trace,
48
+ * thrown in one) has another stack than the debugger's: nothing pairs with its first frames, and none is read.
49
+ */
50
+ private frames;
51
+ }