@fixback/node 0.3.4 → 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.
package/dist/client.d.ts CHANGED
@@ -44,6 +44,10 @@ export declare class FixbackClient {
44
44
  get enabled(): boolean;
45
45
  /** The header the request-context middleware reads a correlation id from. */
46
46
  get requestIdHeader(): string;
47
+ /** Whether the request/response bodies are captured (the `captureBodies` opt-in). */
48
+ get captureBodies(): boolean;
49
+ /** The size cap (bytes) for a captured body when {@link captureBodies} is on. */
50
+ get maxBodyBytes(): number;
47
51
  /**
48
52
  * Report a caught or manually-observed error. `handled` defaults to `true`; the
49
53
  * process handlers pass `handled: false` for an uncaught crash.
package/dist/client.js CHANGED
@@ -62,6 +62,14 @@ class FixbackClient {
62
62
  get requestIdHeader() {
63
63
  return this.config.requestIdHeader;
64
64
  }
65
+ /** Whether the request/response bodies are captured (the `captureBodies` opt-in). */
66
+ get captureBodies() {
67
+ return this.config.captureBodies;
68
+ }
69
+ /** The size cap (bytes) for a captured body when {@link captureBodies} is on. */
70
+ get maxBodyBytes() {
71
+ return this.config.maxBodyBytes;
72
+ }
65
73
  /**
66
74
  * Report a caught or manually-observed error. `handled` defaults to `true`; the
67
75
  * process handlers pass `handled: false` for an uncaught crash.
@@ -137,7 +145,13 @@ class FixbackClient {
137
145
  }
138
146
  }
139
147
  exports.FixbackClient = FixbackClient;
140
- /** The built-in default scrub: re-sweep frame URLs through the shared-core scrubber. */
148
+ /**
149
+ * The built-in default scrub: re-sweep frame URLs through the shared-core scrubber,
150
+ * and — under the `captureBodies` opt-in — redact PII (emails, bearer tokens, long
151
+ * digit runs) from the captured request/response bodies before they leave the
152
+ * process. Masking is the SDK's job (spec 0003 §C); ingest re-scrubs the same fields
153
+ * as defence-in-depth.
154
+ */
141
155
  function applyDefaultScrub(event) {
142
156
  if (event.errorFrames && event.errorFrames.length > 0) {
143
157
  event.errorFrames = event.errorFrames.map((frame) => ({
@@ -145,6 +159,19 @@ function applyDefaultScrub(event) {
145
159
  file: (0, sdk_core_1.scrubUrl)(frame.file),
146
160
  }));
147
161
  }
162
+ const server = event.server;
163
+ if (server &&
164
+ (typeof server.requestBody === "string" || typeof server.responseBody === "string")) {
165
+ event.server = {
166
+ ...server,
167
+ ...(typeof server.requestBody === "string"
168
+ ? { requestBody: (0, sdk_core_1.redactPii)(server.requestBody) }
169
+ : {}),
170
+ ...(typeof server.responseBody === "string"
171
+ ? { responseBody: (0, sdk_core_1.redactPii)(server.responseBody) }
172
+ : {}),
173
+ };
174
+ }
148
175
  }
149
176
  /** Project the event onto the wire payload, dropping the event-only fields. */
150
177
  function toPayload(event) {
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAuMH,oBAqBC;AAGD,8BAEC;AAGD,4CAEC;AAGD,wCAEC;AAGD,sBAEC;AAGD,sBAOC;AAxPD,gDAA0F;AAE1F,qCAAgF;AAChF,uCAAiD;AACjD,uCAAqE;AACrE,mCAAuC;AACvC,2CAA+D;AA+B/D,wFAAwF;AACxF,SAAS,kBAAkB,CACzB,IAA+B,EAC/B,QAAmC;IAEnC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,MAAM,GAA4B,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;IACjF,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAE,MAAwB,CAAC,CAAC,CAAC,SAAS,CAAC;AAChF,CAAC;AAED,MAAa,aAAa;IACP,MAAM,CAAiB;IACvB,SAAS,CAA0B;IAEpD,YAAY,MAAsB,EAAE,OAAmB,EAAE;QACvD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS;YACZ,IAAI,CAAC,SAAS;gBACd,CAAC,MAAM,CAAC,OAAO;oBACb,CAAC,CAAC,IAAI,qBAAS,CAAC;wBACZ,QAAQ,EAAE,MAAM,CAAC,cAAc;wBAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;wBAC3B,YAAY,EAAE,MAAM,CAAC,YAAY;wBACjC,YAAY,EAAE,MAAM,CAAC,YAAY;wBACjC,eAAe,EAAE,MAAM,CAAC,eAAe;wBACvC,SAAS,EAAE,MAAM,CAAC,SAAS;qBAC5B,CAAC;oBACJ,CAAC,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,qFAAqF;IACrF,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;IAC7B,CAAC;IAED,6EAA6E;IAC7E,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,KAAc,EAAE,UAA0B,EAAE;QAC3D,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAA,oBAAY,EAAC,KAAK,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,IAAA,kCAAuB,EAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,CAAC,QAAQ,CACX;YACE,cAAc,EAAE,IAAA,6BAAkB,EAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC;YACtD,IAAI;YACJ,KAAK;YACL,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;YAChC,WAAW,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACpD,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,cAAc,CAAC,OAAe,EAAE,QAAkB,MAAM,EAAE,UAA0B,EAAE;QACpF,MAAM,KAAK,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACtE,IAAI,CAAC,QAAQ,CACX;YACE,cAAc,EAAE,IAAA,6BAAkB,EAAC,SAAS,EAAE,KAAK,CAAC;YACpD,IAAI,EAAE,SAAS;YACf,KAAK;YACL,KAAK;YACL,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;SACjC,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,gFAAgF;IAChF,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC;IAED,6DAA6D;IAC7D,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC;IAED,+EAA+E;IACvE,QAAQ,CACd,OAC2D,EAC3D,OAAuB;QAEvB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QACpD,IAAI,CAAC;YACH,MAAM,KAAK,GAAsB;gBAC/B,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,OAAO,EAAE,OAAO,CAAC,OAAO;gBACxB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBACpC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO;gBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,MAAM,EAAE,kBAAkB,CAAC,IAAA,8BAAoB,GAAE,EAAE,OAAO,CAAC,MAAM,CAAC;aACnE,CAAC;YACF,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK;gBAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC5C,IAAI,CAAC,SAAS;gBAAE,OAAO,CAAC,4CAA4C;YACpE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;IAED,oFAAoF;IAC5E,aAAa,CAAC,KAAwB;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QACxB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC,CAAC,sEAAsE;QACtF,CAAC;IACH,CAAC;CACF;AAhHD,sCAgHC;AAED,wFAAwF;AACxF,SAAS,iBAAiB,CAAC,KAAwB;IACjD,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtD,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACpD,GAAG,KAAK;YACR,IAAI,EAAE,IAAA,mBAAQ,EAAC,KAAK,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC,CAAC;IACN,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,SAAS,SAAS,CAAC,KAAwB;IACzC,MAAM,OAAO,GAAmB,EAAE,cAAc,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC;IACzE,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IACjE,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC7E,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IACjE,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;QAAE,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC7E,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IAC/F,IAAI,KAAK,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;IAChD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gFAAgF;AAEhF,IAAI,YAAY,GAAyB,IAAI,CAAC;AAC9C,IAAI,eAAe,GAAwB,IAAI,CAAC;AAEhD;;;;;GAKG;AACH,SAAgB,IAAI,CAAC,OAAoB,EAAE,IAAiB;IAC1D,MAAM,cAAc,GAAG,YAAY,CAAC;IACpC,MAAM,iBAAiB,GAAG,eAAe,CAAC;IAC1C,IAAI,iBAAiB;QAAE,iBAAiB,EAAE,CAAC;IAC3C,IAAI,cAAc;QAAE,KAAK,cAAc,CAAC,KAAK,EAAE,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAA,sBAAa,EAAC,OAAO,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC/C,YAAY,GAAG,MAAM,CAAC;IACtB,eAAe;QACb,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,wBAAwB,IAAI,MAAM,CAAC,yBAAyB,CAAC;YACrF,CAAC,CAAC,IAAA,gCAAsB,EACpB,MAAM,EACN;gBACE,wBAAwB,EAAE,MAAM,CAAC,wBAAwB;gBACzD,yBAAyB,EAAE,MAAM,CAAC,yBAAyB;aAC5D,EACD,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,CAC7D;YACH,CAAC,CAAC,IAAI,CAAC;IACX,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gFAAgF;AAChF,SAAgB,SAAS;IACvB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,oFAAoF;AACpF,SAAgB,gBAAgB,CAAC,KAAc,EAAE,OAAwB;IACvE,YAAY,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,wEAAwE;AACxE,SAAgB,cAAc,CAAC,OAAe,EAAE,KAAgB,EAAE,OAAwB;IACxF,YAAY,EAAE,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED,8DAA8D;AAC9D,SAAgB,KAAK;IACnB,OAAO,YAAY,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;AACpD,CAAC;AAED,8FAA8F;AAC9F,SAAgB,KAAK;IACnB,MAAM,OAAO,GAAG,YAAY,CAAC;IAC7B,MAAM,SAAS,GAAG,eAAe,CAAC;IAClC,YAAY,GAAG,IAAI,CAAC;IACpB,eAAe,GAAG,IAAI,CAAC;IACvB,IAAI,SAAS;QAAE,SAAS,EAAE,CAAC;IAC3B,OAAO,OAAO,EAAE,KAAK,EAAE,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -50,6 +50,22 @@ export interface InitOptions extends Omit<CommonInitOptions<FixbackErrorEvent>,
50
50
  readonly timeoutMs?: number;
51
51
  /** The header a correlation id is read from. Defaults to `x-request-id`. */
52
52
  readonly requestIdHeader?: string;
53
+ /**
54
+ * Capture the failing request's **request and response bodies** onto the error's
55
+ * Server context (ADR-2026-09-16). **Defaults to `false`** — this relaxes the
56
+ * private-by-default posture (VISION §5), so it is an explicit opt-in a backend
57
+ * turns on for its own internal/staging debugging. When off, nothing is captured
58
+ * or wrapped and behaviour is byte-for-byte unchanged. Bodies are serialized,
59
+ * PII-redacted at the scrub choke point, and dropped when they exceed
60
+ * {@link maxBodyBytes} (an oversized body degrades to exactly the off behaviour).
61
+ */
62
+ readonly captureBodies?: boolean;
63
+ /**
64
+ * The size cap (bytes) for a captured body when {@link captureBodies} is on; a body
65
+ * whose serialized form exceeds it is dropped rather than truncated. Defaults to
66
+ * `16384`, clamped to `[0, 65536]`.
67
+ */
68
+ readonly maxBodyBytes?: number;
53
69
  }
54
70
  /** The validated, defaulted configuration a {@link FixbackClient} runs on. */
55
71
  export interface ResolvedConfig {
@@ -68,6 +84,8 @@ export interface ResolvedConfig {
68
84
  readonly maxQueueSize: number;
69
85
  readonly timeoutMs: number;
70
86
  readonly requestIdHeader: string;
87
+ readonly captureBodies: boolean;
88
+ readonly maxBodyBytes: number;
71
89
  }
72
90
  /**
73
91
  * Resolve raw {@link InitOptions} into a validated {@link ResolvedConfig}. Never
package/dist/config.js CHANGED
@@ -20,6 +20,10 @@ const DEFAULT_FLUSH_INTERVAL_MS = 5_000;
20
20
  const DEFAULT_MAX_QUEUE_SIZE = 1_024;
21
21
  const DEFAULT_TIMEOUT_MS = 30_000;
22
22
  const DEFAULT_REQUEST_ID_HEADER = "x-request-id";
23
+ /** The default per-body size cap (bytes) when `captureBodies` is on — a larger body is dropped. */
24
+ const DEFAULT_MAX_BODY_BYTES = 16_384;
25
+ /** A hard ceiling on the body cap so a misconfigured knob can't buffer unbounded bodies. */
26
+ const MAX_BODY_BYTES_CEILING = 65_536;
23
27
  /** Trim a string option, returning `undefined` for a blank or non-string value. */
24
28
  function trimmed(value) {
25
29
  if (typeof value !== "string")
@@ -68,6 +72,10 @@ function resolveConfig(options) {
68
72
  maxQueueSize: clampInt(options.maxQueueSize, DEFAULT_MAX_QUEUE_SIZE, 1, Number.MAX_SAFE_INTEGER),
69
73
  timeoutMs: clampInt(options.timeoutMs, DEFAULT_TIMEOUT_MS, 0, Number.MAX_SAFE_INTEGER),
70
74
  requestIdHeader: (trimmed(options.requestIdHeader) ?? DEFAULT_REQUEST_ID_HEADER).toLowerCase(),
75
+ // Body capture is a strict opt-in (only an explicit `true` turns it on), so a
76
+ // truthy-but-not-true value never relaxes the private-by-default posture.
77
+ captureBodies: options.captureBodies === true,
78
+ maxBodyBytes: clampInt(options.maxBodyBytes, DEFAULT_MAX_BODY_BYTES, 0, MAX_BODY_BYTES_CEILING),
71
79
  };
72
80
  }
73
81
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/context.d.ts CHANGED
@@ -19,6 +19,20 @@ export interface RequestStore {
19
19
  readonly requestId?: string;
20
20
  /** The app-supplied user ref, written by {@link setRequestUser}. Never scraped. */
21
21
  user?: string;
22
+ /**
23
+ * Whether the request/response bodies are being captured for this request
24
+ * (the `captureBodies` opt-in, ADR-2026-09-16). When unset, {@link deriveServerContext}
25
+ * carries no bodies — the private-by-default path.
26
+ */
27
+ captureBodies?: boolean;
28
+ /** The size cap (bytes) for a captured body; a larger body is dropped. */
29
+ maxBodyBytes?: number;
30
+ /**
31
+ * The raw response body recorded by the wrapped `res.json`/`res.send` — the first
32
+ * one the request resolved with. Serialized and capped at read time in
33
+ * {@link deriveServerContext}. Only ever set when {@link captureBodies} is on.
34
+ */
35
+ responseBody?: unknown;
22
36
  }
23
37
  /** The active request store, or `undefined` outside a request scope. */
24
38
  export declare function getRequestStore(): RequestStore | undefined;
@@ -30,11 +44,22 @@ export declare function runWithRequestStore<T>(store: RequestStore, fn: () => T)
30
44
  * throws). The SDK never derives identity from the request — only what you pass here.
31
45
  */
32
46
  export declare function setRequestUser(user: string): void;
47
+ /**
48
+ * Serialize a captured body to a string within a byte cap, or `undefined` when there
49
+ * is nothing usable to store (ADR-2026-09-16). A string rides as-is; a plain object is
50
+ * JSON-serialized; binary (a `Buffer` or typed array) and non-body primitives are
51
+ * dropped. An empty result, an unserialisable value (a circular object), or one whose
52
+ * serialized form exceeds `maxBytes` all degrade to `undefined` — exactly the
53
+ * body-absent path, so an oversized body renders like no body at all.
54
+ */
55
+ export declare function serializeBody(value: unknown, maxBytes: number): string | undefined;
33
56
  /**
34
57
  * Derive the private-by-default {@link ServerContext} from a request store: the HTTP
35
58
  * method, the route **pattern**, the resolved status, the correlation id, and the
36
59
  * app-supplied user ref. Returns `undefined` when there is no store or nothing
37
- * resolvable — never the concrete path, a body, a header, or a query value.
60
+ * resolvable — never the concrete path, a header, or a query value. The request and
61
+ * response **bodies** are added only when the store opted into `captureBodies`
62
+ * (ADR-2026-09-16), each serialized and dropped if it exceeds the store's cap.
38
63
  */
39
64
  export declare function deriveServerContext(store: RequestStore | undefined): ServerContext | undefined;
40
65
  /** The {@link ServerContext} for the active request, or `undefined` outside one. */
@@ -43,11 +68,21 @@ export declare function currentServerContext(): ServerContext | undefined;
43
68
  export interface RequestContextOptions {
44
69
  /** The header a correlation id is read from. Defaults to `x-request-id`. */
45
70
  readonly requestIdHeader?: string;
71
+ /**
72
+ * Record the request/response bodies onto the store (the `captureBodies` opt-in,
73
+ * ADR-2026-09-16). Off by default; when on, the middleware also wraps the response
74
+ * writers to record the response body. Resolved from the active client's config by
75
+ * the adapters, never asked of the app here.
76
+ */
77
+ readonly captureBodies?: boolean;
78
+ /** The size cap (bytes) for a captured body when {@link captureBodies} is on. */
79
+ readonly maxBodyBytes?: number;
46
80
  }
47
81
  /**
48
82
  * Build the Express-style request-context middleware: it opens an ALS store for the
49
83
  * request (adopting an inbound correlation id, or minting one) and runs the rest of
50
84
  * the request within it. Shared by the Express adapter and the NestJS module so both
51
- * frameworks get per-request correlation the same way.
85
+ * frameworks get per-request correlation the same way. Under `captureBodies` it also
86
+ * wraps the response writers so the response body can be recorded (ADR-2026-09-16).
52
87
  */
53
88
  export declare function createRequestContextMiddleware(options?: RequestContextOptions): (req: HttpRequestLike, res: HttpResponseLike, next: NextFunction) => void;
package/dist/context.js CHANGED
@@ -14,12 +14,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.getRequestStore = getRequestStore;
15
15
  exports.runWithRequestStore = runWithRequestStore;
16
16
  exports.setRequestUser = setRequestUser;
17
+ exports.serializeBody = serializeBody;
17
18
  exports.deriveServerContext = deriveServerContext;
18
19
  exports.currentServerContext = currentServerContext;
19
20
  exports.createRequestContextMiddleware = createRequestContextMiddleware;
20
21
  const node_async_hooks_1 = require("node:async_hooks");
21
22
  const node_crypto_1 = require("node:crypto");
22
23
  const http_1 = require("./http");
24
+ /** The fallback body cap used when a store opts into body capture without naming one. */
25
+ const FALLBACK_MAX_BODY_BYTES = 16_384;
23
26
  const storage = new node_async_hooks_1.AsyncLocalStorage();
24
27
  /** The active request store, or `undefined` outside a request scope. */
25
28
  function getRequestStore() {
@@ -39,11 +42,80 @@ function setRequestUser(user) {
39
42
  if (store && typeof user === "string" && user.length > 0)
40
43
  store.user = user;
41
44
  }
45
+ /**
46
+ * Serialize a captured body to a string within a byte cap, or `undefined` when there
47
+ * is nothing usable to store (ADR-2026-09-16). A string rides as-is; a plain object is
48
+ * JSON-serialized; binary (a `Buffer` or typed array) and non-body primitives are
49
+ * dropped. An empty result, an unserialisable value (a circular object), or one whose
50
+ * serialized form exceeds `maxBytes` all degrade to `undefined` — exactly the
51
+ * body-absent path, so an oversized body renders like no body at all.
52
+ */
53
+ function serializeBody(value, maxBytes) {
54
+ if (value === undefined || value === null)
55
+ return undefined;
56
+ let text;
57
+ if (typeof value === "string") {
58
+ text = value;
59
+ }
60
+ else if (typeof value === "object") {
61
+ if (Buffer.isBuffer(value) || ArrayBuffer.isView(value))
62
+ return undefined;
63
+ try {
64
+ text = JSON.stringify(value);
65
+ }
66
+ catch {
67
+ return undefined; // circular / unserialisable — degrade to absent
68
+ }
69
+ if (typeof text !== "string")
70
+ return undefined; // e.g. a value whose toJSON returns undefined
71
+ }
72
+ else {
73
+ return undefined; // number / boolean / bigint / symbol / function — not a body
74
+ }
75
+ if (text.length === 0)
76
+ return undefined;
77
+ if (Buffer.byteLength(text, "utf8") > maxBytes)
78
+ return undefined; // oversized — degrade to absent
79
+ return text;
80
+ }
81
+ /**
82
+ * Wrap a response's `json`/`send` writers so the **first** body the request resolves
83
+ * with is recorded onto the store (for {@link deriveServerContext} to read). Installed
84
+ * by the request-context middleware only under the `captureBodies` opt-in. Recording
85
+ * never breaks the response: a throw while recording is swallowed and the original
86
+ * writer always runs; a frozen (non-writable) response is left untouched, so the body
87
+ * simply degrades to absent.
88
+ */
89
+ function installResponseBodyCapture(res, store) {
90
+ for (const method of ["json", "send"]) {
91
+ const original = res[method];
92
+ if (typeof original !== "function")
93
+ continue;
94
+ const wrapped = function (...args) {
95
+ try {
96
+ if (store.responseBody === undefined && args.length > 0)
97
+ store.responseBody = args[0];
98
+ }
99
+ catch {
100
+ /* recording must never break the response */
101
+ }
102
+ return original.apply(this, args);
103
+ };
104
+ try {
105
+ res[method] = wrapped;
106
+ }
107
+ catch {
108
+ /* a frozen response object — skip; the body degrades to absent */
109
+ }
110
+ }
111
+ }
42
112
  /**
43
113
  * Derive the private-by-default {@link ServerContext} from a request store: the HTTP
44
114
  * method, the route **pattern**, the resolved status, the correlation id, and the
45
115
  * app-supplied user ref. Returns `undefined` when there is no store or nothing
46
- * resolvable — never the concrete path, a body, a header, or a query value.
116
+ * resolvable — never the concrete path, a header, or a query value. The request and
117
+ * response **bodies** are added only when the store opted into `captureBodies`
118
+ * (ADR-2026-09-16), each serialized and dropped if it exceeds the store's cap.
47
119
  */
48
120
  function deriveServerContext(store) {
49
121
  if (!store)
@@ -62,6 +134,15 @@ function deriveServerContext(store) {
62
134
  ctx.requestId = store.requestId;
63
135
  if (store.user)
64
136
  ctx.user = store.user;
137
+ if (store.captureBodies) {
138
+ const maxBytes = store.maxBodyBytes ?? FALLBACK_MAX_BODY_BYTES;
139
+ const requestBody = serializeBody(store.req.body, maxBytes);
140
+ if (requestBody !== undefined)
141
+ ctx.requestBody = requestBody;
142
+ const responseBody = serializeBody(store.responseBody, maxBytes);
143
+ if (responseBody !== undefined)
144
+ ctx.responseBody = responseBody;
145
+ }
65
146
  return Object.keys(ctx).length > 0 ? ctx : undefined;
66
147
  }
67
148
  /** The {@link ServerContext} for the active request, or `undefined` outside one. */
@@ -81,16 +162,25 @@ function readRequestId(req, header) {
81
162
  * Build the Express-style request-context middleware: it opens an ALS store for the
82
163
  * request (adopting an inbound correlation id, or minting one) and runs the rest of
83
164
  * the request within it. Shared by the Express adapter and the NestJS module so both
84
- * frameworks get per-request correlation the same way.
165
+ * frameworks get per-request correlation the same way. Under `captureBodies` it also
166
+ * wraps the response writers so the response body can be recorded (ADR-2026-09-16).
85
167
  */
86
168
  function createRequestContextMiddleware(options = {}) {
87
169
  const header = (options.requestIdHeader ?? "x-request-id").toLowerCase();
170
+ const captureBodies = options.captureBodies === true;
171
+ const maxBodyBytes = options.maxBodyBytes;
88
172
  return function fixbackRequestContext(req, res, next) {
89
173
  const store = {
90
174
  req,
91
175
  res,
92
176
  requestId: readRequestId(req, header) ?? (0, node_crypto_1.randomUUID)(),
93
177
  };
178
+ if (captureBodies) {
179
+ store.captureBodies = true;
180
+ if (typeof maxBodyBytes === "number")
181
+ store.maxBodyBytes = maxBodyBytes;
182
+ installResponseBodyCapture(res, store);
183
+ }
94
184
  runWithRequestStore(store, () => next());
95
185
  };
96
186
  }
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
package/dist/express.js CHANGED
@@ -25,8 +25,14 @@ const http_1 = require("./http");
25
25
  * `app.use(fixbackRequestContext())`.
26
26
  */
27
27
  function fixbackRequestContext(options = {}) {
28
- const header = options.requestIdHeader ?? (0, client_1.getClient)()?.requestIdHeader;
29
- return (0, context_1.createRequestContextMiddleware)(header ? { requestIdHeader: header } : {});
28
+ const client = (0, client_1.getClient)();
29
+ const header = options.requestIdHeader ?? client?.requestIdHeader;
30
+ return (0, context_1.createRequestContextMiddleware)({
31
+ ...(header ? { requestIdHeader: header } : {}),
32
+ // The `captureBodies` opt-in lives on `init`, not on this factory — resolve it
33
+ // from the active client so the middleware wraps the response writers (ADR-2026-09-16).
34
+ ...(client?.captureBodies ? { captureBodies: true, maxBodyBytes: client.maxBodyBytes } : {}),
35
+ });
30
36
  }
31
37
  /**
32
38
  * Build the error-handling middleware. Mount it after your routes:
@@ -38,14 +44,27 @@ function fixbackErrorHandler(options = {}) {
38
44
  captureException: (error, context) => (0, client_1.captureException)(error, context),
39
45
  };
40
46
  return function fixbackErrorHandlerMiddleware(error, req, res, next) {
41
- try {
42
- const server = { ...(0, http_1.serverContextFromRequest)(req), statusCode: (0, http_1.errorStatus)(error, res) };
43
- client.captureException(error, { handled: true, server });
47
+ const capture = () => {
48
+ try {
49
+ const server = { ...(0, http_1.serverContextFromRequest)(req), statusCode: (0, http_1.errorStatus)(error, res) };
50
+ client.captureException(error, { handled: true, server });
51
+ }
52
+ catch {
53
+ // Capture must never break the request pipeline — always forward the error.
54
+ }
55
+ };
56
+ // Under the `captureBodies` opt-in (ADR-2026-09-16) the response body is only
57
+ // available once the app's own error handler has sent the response, so forward
58
+ // first and capture after. Otherwise keep the original order — capture, then
59
+ // forward — so behaviour is byte-for-byte unchanged when the opt-in is off.
60
+ if ((0, client_1.getClient)()?.captureBodies) {
61
+ next(error);
62
+ capture();
44
63
  }
45
- catch {
46
- // Capture must never break the request pipeline — always forward the error.
64
+ else {
65
+ capture();
66
+ next(error);
47
67
  }
48
- next(error);
49
68
  };
50
69
  }
51
70
  //# sourceMappingURL=express.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AA+CH,sDAGC;AAOD,kDAaC;AApED,qCAIkB;AAClB,uCAA2D;AAC3D,iCAMgB;AA6BhB;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,UAAiC,EAAE;IACvE,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,IAAI,IAAA,kBAAS,GAAE,EAAE,eAAe,CAAC;IACvE,OAAO,IAAA,wCAA8B,EAAC,MAAM,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACnF,CAAC;AAED;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,UAA+B,EAAE;IACnE,MAAM,MAAM,GAAkB,OAAO,CAAC,MAAM,IAAI;QAC9C,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,yBAAsB,EAAC,KAAK,EAAE,OAAO,CAAC;KAC7E,CAAC;IACF,OAAO,SAAS,6BAA6B,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI;QACjE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,EAAE,GAAG,IAAA,+BAAwB,EAAC,GAAG,CAAC,EAAE,UAAU,EAAE,IAAA,kBAAW,EAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;YACzF,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,4EAA4E;QAC9E,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,CAAC;IACd,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AA+CH,sDASC;AAOD,kDAyBC;AAtFD,qCAIkB;AAClB,uCAA2D;AAC3D,iCAMgB;AA6BhB;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,UAAiC,EAAE;IACvE,MAAM,MAAM,GAAG,IAAA,kBAAS,GAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,IAAI,MAAM,EAAE,eAAe,CAAC;IAClE,OAAO,IAAA,wCAA8B,EAAC;QACpC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,+EAA+E;QAC/E,wFAAwF;QACxF,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7F,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,UAA+B,EAAE;IACnE,MAAM,MAAM,GAAkB,OAAO,CAAC,MAAM,IAAI;QAC9C,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,yBAAsB,EAAC,KAAK,EAAE,OAAO,CAAC;KAC7E,CAAC;IACF,OAAO,SAAS,6BAA6B,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI;QACjE,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,EAAE,GAAG,IAAA,+BAAwB,EAAC,GAAG,CAAC,EAAE,UAAU,EAAE,IAAA,kBAAW,EAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;gBACzF,MAAM,CAAC,gBAAgB,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5D,CAAC;YAAC,MAAM,CAAC;gBACP,4EAA4E;YAC9E,CAAC;QACH,CAAC,CAAC;QACF,8EAA8E;QAC9E,+EAA+E;QAC/E,6EAA6E;QAC7E,4EAA4E;QAC5E,IAAI,IAAA,kBAAS,GAAE,EAAE,aAAa,EAAE,CAAC;YAC/B,IAAI,CAAC,KAAK,CAAC,CAAC;YACZ,OAAO,EAAE,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,OAAO,EAAE,CAAC;YACV,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
package/dist/http.d.ts CHANGED
@@ -8,7 +8,14 @@
8
8
  * the private-by-default fields are read here — never bodies, headers beyond the
9
9
  * correlation id, query values, or env.
10
10
  */
11
- /** The request slice the adapters read — never its body, headers (bar the id), or query. */
11
+ /** A framework response writer (`res.json` / `res.send`) — wrapped under `captureBodies`. */
12
+ export type ResponseWriter = (this: unknown, ...args: unknown[]) => unknown;
13
+ /**
14
+ * The request slice the adapters read — headers (bar the correlation id) and query are
15
+ * never read. The parsed **body** is read only under the `captureBodies` opt-in
16
+ * (default off, ADR-2026-09-16); it is whatever the app's body parser already put on
17
+ * `req.body`, so Fixback parses nothing itself.
18
+ */
12
19
  export interface HttpRequestLike {
13
20
  readonly method?: string;
14
21
  readonly baseUrl?: string;
@@ -18,10 +25,19 @@ export interface HttpRequestLike {
18
25
  readonly path?: string | RegExp;
19
26
  } | undefined;
20
27
  readonly headers?: Readonly<Record<string, string | string[] | undefined>>;
28
+ /** The parsed request body the app's body parser set — read only under `captureBodies`. */
29
+ readonly body?: unknown;
21
30
  }
22
- /** The response slice the adapters read — only the resolved status. */
31
+ /**
32
+ * The response slice the adapters read — the resolved status, plus the `json`/`send`
33
+ * writers the request-context middleware wraps (only under `captureBodies`) to record
34
+ * the response body. The writers are optional and non-readonly so the wrapper can
35
+ * replace them; a frozen response simply keeps its own and the body degrades to absent.
36
+ */
23
37
  export interface HttpResponseLike {
24
38
  readonly statusCode?: number;
39
+ json?: ResponseWriter;
40
+ send?: ResponseWriter;
25
41
  }
26
42
  /** The Express/Nest `next` callback — `next(err)` forwards to the error pipeline. */
27
43
  export type NextFunction = (err?: unknown) => void;
package/dist/http.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AA0BH,wCASC;AAUD,4DAMC;AAGD,sCAOC;AAMD,kCAMC;AArDD;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,GAAoB;IACjD,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC;IAClC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpE,MAAM,OAAO,GACX,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACtC,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,wBAAwB,CAAC,GAAoB;IAC3D,MAAM,GAAG,GAAwC,EAAE,CAAC;IACpD,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACrF,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAK;QAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gGAAgG;AAChG,SAAgB,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,KAAmD,CAAC;QAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACnE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,GAAqB;IAC/D,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,SAAS,IAAI,SAAS,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,YAAY,GAAG,GAAG,CAAC,UAAU,CAAC;IACpC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,IAAI,GAAG;QAAE,OAAO,YAAY,CAAC;IACjF,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;AA2CH,wCASC;AAUD,4DAMC;AAGD,sCAOC;AAMD,kCAMC;AArDD;;;;;GAKG;AACH,SAAgB,cAAc,CAAC,GAAoB;IACjD,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC;IAClC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpE,MAAM,OAAO,GACX,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACtF,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACpE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACtC,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,wBAAwB,CAAC,GAAoB;IAC3D,MAAM,GAAG,GAAwC,EAAE,CAAC;IACpD,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACrF,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,KAAK;QAAE,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7B,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gGAAgG;AAChG,SAAgB,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,KAAmD,CAAC;QAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QACnE,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,GAAG,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,SAAgB,WAAW,CAAC,KAAc,EAAE,GAAqB;IAC/D,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,SAAS,IAAI,SAAS,IAAI,GAAG;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,YAAY,GAAG,GAAG,CAAC,UAAU,CAAC;IACpC,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,IAAI,GAAG;QAAE,OAAO,YAAY,CAAC;IACjF,OAAO,GAAG,CAAC;AACb,CAAC"}
package/dist/nestjs.js CHANGED
@@ -80,8 +80,20 @@ function captureNestException(exception, host, client = defaultClient) {
80
80
  */
81
81
  let FixbackExceptionFilter = class FixbackExceptionFilter extends core_1.BaseExceptionFilter {
82
82
  catch(exception, host) {
83
- captureNestException(exception, host);
84
- super.catch(exception, host);
83
+ // Under the `captureBodies` opt-in (ADR-2026-09-16) the response body is recorded
84
+ // by the request-context middleware's wrapped writers only once Nest has produced
85
+ // the response, so let `super.catch` run first and capture after — this is how the
86
+ // framework's own payload (e.g. a `ValidationPipe` array) reaches the Server
87
+ // context. With the opt-in off, keep the original order — capture, then respond —
88
+ // so behaviour is unchanged.
89
+ if ((0, client_1.getClient)()?.captureBodies) {
90
+ super.catch(exception, host);
91
+ captureNestException(exception, host);
92
+ }
93
+ else {
94
+ captureNestException(exception, host);
95
+ super.catch(exception, host);
96
+ }
85
97
  }
86
98
  };
87
99
  exports.FixbackExceptionFilter = FixbackExceptionFilter;
@@ -101,9 +113,17 @@ let FixbackModule = FixbackModule_1 = class FixbackModule {
101
113
  };
102
114
  }
103
115
  configure(consumer) {
104
- const requestIdHeader = (0, client_1.getClient)()?.requestIdHeader;
116
+ const client = (0, client_1.getClient)();
117
+ const requestIdHeader = client?.requestIdHeader;
105
118
  consumer
106
- .apply((0, context_1.createRequestContextMiddleware)(requestIdHeader ? { requestIdHeader } : {}))
119
+ .apply((0, context_1.createRequestContextMiddleware)({
120
+ ...(requestIdHeader ? { requestIdHeader } : {}),
121
+ // The `captureBodies` opt-in is resolved from `init`, so the middleware wraps
122
+ // the response writers to record the response body (ADR-2026-09-16).
123
+ ...(client?.captureBodies
124
+ ? { captureBodies: true, maxBodyBytes: client.maxBodyBytes }
125
+ : {}),
126
+ }))
107
127
  .forRoutes("*");
108
128
  }
109
129
  };
@@ -1 +1 @@
1
- {"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -10,4 +10,4 @@
10
10
  * ever drift. Do not hand-edit this line to a value other than `package.json`'s
11
11
  * version.
12
12
  */
13
- export declare const NODE_SDK_VERSION = "0.3.4";
13
+ export declare const NODE_SDK_VERSION = "0.4.0";
package/dist/version.js CHANGED
@@ -13,5 +13,5 @@ exports.NODE_SDK_VERSION = void 0;
13
13
  * ever drift. Do not hand-edit this line to a value other than `package.json`'s
14
14
  * version.
15
15
  */
16
- exports.NODE_SDK_VERSION = "0.3.4";
16
+ exports.NODE_SDK_VERSION = "0.4.0";
17
17
  //# sourceMappingURL=version.js.map
package/dist/wire.d.ts CHANGED
@@ -17,8 +17,15 @@ export type Severity = "fatal" | "error" | "warning" | "info" | "debug";
17
17
  * The **server context** captured for a backend error (ADR-0060, spec #224).
18
18
  * Private-by-default: the route **pattern** (never the concrete path with values),
19
19
  * the HTTP method, the resolved status, a correlation id, and an **app-supplied**
20
- * user ref only. Never request/response bodies, never `Authorization`/`Cookie`
21
- * headers, never env vars, never query-string values.
20
+ * user ref are always carried. Never `Authorization`/`Cookie` headers, never env
21
+ * vars, never query-string values.
22
+ *
23
+ * The request/response **bodies** are the one relaxation — captured only when the
24
+ * project opts into `init({ captureBodies: true })` (default off, ADR-2026-09-16),
25
+ * already serialized to a string and size-capped, and PII-redacted at the scrub
26
+ * choke point. They ride to the trusted secret-key server door, which re-scrubs them
27
+ * as defence-in-depth; the browser (publishable-key) door has no server-context slot,
28
+ * so a page can never smuggle one in.
22
29
  */
23
30
  export interface ServerContext {
24
31
  /** The HTTP method (`GET`, `POST`, …). */
@@ -31,6 +38,17 @@ export interface ServerContext {
31
38
  readonly requestId?: string;
32
39
  /** An **app-supplied** user reference (via `setUser`) — never scraped from the request. */
33
40
  readonly user?: string;
41
+ /**
42
+ * The failing request's **body**, serialized and size-capped — present only under
43
+ * the `captureBodies` opt-in (default off). Absent when off, when no body was
44
+ * captured, or when it exceeded the cap (degrades to exactly the off behaviour).
45
+ */
46
+ readonly requestBody?: string;
47
+ /**
48
+ * The **response body** the request resolved with, serialized and size-capped —
49
+ * present only under the `captureBodies` opt-in, on the same terms as {@link requestBody}.
50
+ */
51
+ readonly responseBody?: string;
34
52
  }
35
53
  /**
36
54
  * The assembled event a capture produces, handed to the project's optional
@@ -74,9 +92,10 @@ export type BeforeSend = (event: FixbackErrorEvent) => FixbackErrorEvent | null;
74
92
  /**
75
93
  * One captured backend error **on the wire** — the payload item the SDK posts.
76
94
  * `errorSignature` is required (the ADR-0062 fold key); everything else is optional.
77
- * Mirrors the server's `errorItemBody`. `server` rides along for forward
78
- * compatibility — the current endpoint strips unknown keys, so it is harmless today
79
- * and ready for when the server persists it.
95
+ * Mirrors the server's `errorItemBody`. `server` carries the failing request's
96
+ * context, which the endpoint persists onto the error's Server context (route /
97
+ * method / status, and — under the `captureBodies` opt-in — the request/response
98
+ * bodies); any slot the endpoint does not model is stripped there.
80
99
  */
81
100
  export interface ServerErrorPayload {
82
101
  readonly errorSignature: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fixback/node",
3
- "version": "0.3.4",
3
+ "version": "0.4.0",
4
4
  "description": "The Fixback backend error SDK for Node servers — one-call init, batched secret-key capture, process handlers, and Express + NestJS adapters.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -50,7 +50,7 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "@fixback/sdk-core": "0.5.0"
53
+ "@fixback/sdk-core": "0.6.0"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@nestjs/common": ">=10.0.0",