@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 +4 -0
- package/dist/client.js +28 -1
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +18 -0
- package/dist/config.js +8 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +37 -2
- package/dist/context.js +92 -2
- package/dist/context.js.map +1 -1
- package/dist/express.js +27 -8
- package/dist/express.js.map +1 -1
- package/dist/http.d.ts +18 -2
- package/dist/http.js.map +1 -1
- package/dist/nestjs.js +24 -4
- package/dist/nestjs.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wire.d.ts +24 -5
- package/package.json +2 -2
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
|
-
/**
|
|
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) {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;
|
|
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
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;
|
|
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
|
|
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
|
|
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
|
}
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;
|
|
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
|
|
29
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
46
|
-
|
|
64
|
+
else {
|
|
65
|
+
capture();
|
|
66
|
+
next(error);
|
|
47
67
|
}
|
|
48
|
-
next(error);
|
|
49
68
|
};
|
|
50
69
|
}
|
|
51
70
|
//# sourceMappingURL=express.js.map
|
package/dist/express.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;AA+CH,
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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;;
|
|
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
|
-
|
|
84
|
-
|
|
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
|
|
116
|
+
const client = (0, client_1.getClient)();
|
|
117
|
+
const requestIdHeader = client?.requestIdHeader;
|
|
105
118
|
consumer
|
|
106
|
-
.apply((0, context_1.createRequestContextMiddleware)(
|
|
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
|
};
|
package/dist/nestjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;AA+CH,oDAwBC;AArED,4BAA0B;AAE1B,2CAQwB;AACxB,uCAA+D;AAE/D,qCAIkB;AAClB,uCAA2D;AAC3D,iCAKgB;AAEhB,yDAAyD;AACzD,MAAM,aAAa,GAAkB;IACnC,gBAAgB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,IAAA,yBAAsB,EAAC,KAAK,EAAE,OAAO,CAAC;CAC7E,CAAC;AAEF,sFAAsF;AACtF,SAAS,UAAU,CAAC,SAAkB,EAAE,GAAqB;IAC3D,IAAI,SAAS,YAAY,sBAAa,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,EAAE,CAAC;QACrC,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC;IAChD,CAAC;IACD,OAAO,IAAA,kBAAW,EAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,SAAgB,oBAAoB,CAClC,SAAkB,EAClB,IAAmB,EACnB,SAAwB,aAAa;IAErC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACrF,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAmB,CAAC;QAC/C,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAoB,IAAI,EAAE,CAAqB,CAAC;QAC7E,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,IAAA,+BAAwB,EAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;QACnE,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CAAC;YACH,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,CAAC;QAAC,MAAM,CAAC;YACP,2CAA2C;QAC7C,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,0BAAmB;IAC7D,KAAK,CAAC,SAAkB,EAAE,IAAmB;QAC3C,oBAAoB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"nestjs.js","sourceRoot":"","sources":["../src/nestjs.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
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
|
|
21
|
-
*
|
|
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`
|
|
78
|
-
*
|
|
79
|
-
* and
|
|
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
|
+
"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.
|
|
53
|
+
"@fixback/sdk-core": "0.6.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@nestjs/common": ">=10.0.0",
|