@fixback/node 0.2.0 → 0.3.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/README.md +4 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +25 -19
- package/dist/config.js +11 -6
- package/dist/config.js.map +1 -1
- package/dist/host-identity.d.ts +60 -0
- package/dist/host-identity.js +72 -0
- package/dist/host-identity.js.map +1 -0
- package/dist/http.d.ts +2 -2
- package/dist/http.js +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/stack.d.ts +8 -18
- package/dist/stack.js +8 -77
- package/dist/stack.js.map +1 -1
- package/dist/transport.d.ts +1 -17
- package/dist/transport.js +4 -20
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wire.d.ts +10 -16
- package/package.json +8 -6
- package/src/client.test.ts +0 -272
- package/src/client.ts +0 -262
- package/src/config.test.ts +0 -79
- package/src/config.ts +0 -131
- package/src/context.test.ts +0 -99
- package/src/context.ts +0 -124
- package/src/express.test.ts +0 -112
- package/src/express.ts +0 -85
- package/src/fingerprint-parity.test.ts +0 -86
- package/src/http.ts +0 -83
- package/src/index.ts +0 -51
- package/src/nestjs.test.ts +0 -146
- package/src/nestjs.ts +0 -123
- package/src/process.test.ts +0 -154
- package/src/process.ts +0 -153
- package/src/stack.test.ts +0 -89
- package/src/stack.ts +0 -153
- package/src/transport.test.ts +0 -187
- package/src/transport.ts +0 -227
- package/src/version.test.ts +0 -10
- package/src/version.ts +0 -13
- package/src/wire.ts +0 -116
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@ Backend errors authenticate with the Project **secret key**, so they arrive
|
|
|
8
8
|
**Internal** tier and tagged `platform: node`. Fleet-wide crash-loops collapse into a
|
|
9
9
|
single Issue with a rising occurrence count instead of flooding your queue.
|
|
10
10
|
|
|
11
|
+
> 📖 **Full documentation: [docs.fixback.dev/sdk/node](https://docs.fixback.dev/sdk/node)** — guides, concepts, and the complete API reference.
|
|
12
|
+
|
|
11
13
|
## Install
|
|
12
14
|
|
|
13
15
|
```bash
|
|
@@ -37,7 +39,8 @@ That single call wires:
|
|
|
37
39
|
|
|
38
40
|
- a **batched** secret-key transport that backs off on `429` (honouring `Retry-After`);
|
|
39
41
|
- process-level `uncaughtException` / `unhandledRejection` capture that **never changes
|
|
40
|
-
your process's exit behaviour
|
|
42
|
+
your process's exit behaviour** — `autoCapture: false` turns both off (or
|
|
43
|
+
`captureUncaughtException` / `captureUnhandledRejection` individually);
|
|
41
44
|
- and the manual capture API below.
|
|
42
45
|
|
|
43
46
|
### Manual capture
|
package/dist/client.js
CHANGED
|
@@ -68,7 +68,7 @@ class FixbackClient {
|
|
|
68
68
|
*/
|
|
69
69
|
captureException(error, context = {}) {
|
|
70
70
|
const { type, value, stack } = (0, stack_1.extractError)(error);
|
|
71
|
-
const frames = (0,
|
|
71
|
+
const frames = (0, sdk_core_1.extractStructuredFrames)(stack);
|
|
72
72
|
this.dispatch({
|
|
73
73
|
errorSignature: (0, sdk_core_1.computeFingerprint)(type, value, stack),
|
|
74
74
|
type,
|
package/dist/client.js.map
CHANGED
|
@@ -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,
|
|
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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -7,32 +7,38 @@
|
|
|
7
7
|
* Numeric knobs are clamped to safe bounds (the batch to the server's 500-item cap)
|
|
8
8
|
* instead of rejected.
|
|
9
9
|
*/
|
|
10
|
-
import type
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
/**
|
|
14
|
-
|
|
10
|
+
import { type CommonInitOptions, DEFAULT_API_URL } from "@fixback/sdk-core";
|
|
11
|
+
import type { BeforeSend, FixbackErrorEvent } from "./wire";
|
|
12
|
+
export { DEFAULT_API_URL };
|
|
13
|
+
/**
|
|
14
|
+
* Options for {@link init} — the one call that wires backend capture.
|
|
15
|
+
*
|
|
16
|
+
* The shared half (`apiUrl`, `release`, `environment`, `enabled`, `scrub`,
|
|
17
|
+
* `beforeSend`) comes from `CommonInitOptions` so it means the same here as in the
|
|
18
|
+
* browser and Expo SDKs (ADR-0028); `beforeSend` is bound to this SDK's
|
|
19
|
+
* {@link FixbackErrorEvent}. The two capture-SDK trace options are omitted rather
|
|
20
|
+
* than inherited: a backend has no breadcrumb buffer and no console/network
|
|
21
|
+
* streams, so `beforeBreadcrumb` and `capture` would be dead names here.
|
|
22
|
+
* {@link autoCapture} is the backend's equivalent umbrella.
|
|
23
|
+
*/
|
|
24
|
+
export interface InitOptions extends Omit<CommonInitOptions<FixbackErrorEvent>, "beforeBreadcrumb" | "capture"> {
|
|
15
25
|
/**
|
|
16
26
|
* The Project **secret key** (`sk_…`) the backend authenticates with — the same
|
|
17
27
|
* key `npx fixback sourcemaps upload` uses (never the publishable key). Without it
|
|
18
28
|
* the SDK stays inert.
|
|
19
29
|
*/
|
|
20
30
|
readonly secretKey: string;
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
readonly
|
|
29
|
-
/**
|
|
30
|
-
readonly scrub?: boolean;
|
|
31
|
-
/** Master gate — set `false` to disable all capture (e.g. in local dev). Defaults to `true`. */
|
|
32
|
-
readonly enabled?: boolean;
|
|
33
|
-
/** Install the polite `uncaughtException` handler. Defaults to `true`. */
|
|
31
|
+
/**
|
|
32
|
+
* Automatic error capture — the polite process handlers that file uncaught
|
|
33
|
+
* exceptions and unhandled rejections as `handled: false` errors. Defaults to
|
|
34
|
+
* `true`; set `false` to install neither. The two per-signal flags below override
|
|
35
|
+
* it individually, so `{ autoCapture: false, captureUnhandledRejection: true }`
|
|
36
|
+
* installs only the rejection handler.
|
|
37
|
+
*/
|
|
38
|
+
readonly autoCapture?: boolean;
|
|
39
|
+
/** Install the polite `uncaughtException` handler. Defaults to {@link autoCapture}. */
|
|
34
40
|
readonly captureUncaughtException?: boolean;
|
|
35
|
-
/** Install the polite `unhandledRejection` handler. Defaults to
|
|
41
|
+
/** Install the polite `unhandledRejection` handler. Defaults to {@link autoCapture}. */
|
|
36
42
|
readonly captureUnhandledRejection?: boolean;
|
|
37
43
|
/** Flush the buffer once it reaches this many errors. Defaults to `100`; capped at `500`. */
|
|
38
44
|
readonly maxBatchSize?: number;
|
package/dist/config.js
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.DEFAULT_API_URL = void 0;
|
|
13
13
|
exports.resolveConfig = resolveConfig;
|
|
14
|
-
|
|
15
|
-
exports
|
|
14
|
+
const sdk_core_1 = require("@fixback/sdk-core");
|
|
15
|
+
Object.defineProperty(exports, "DEFAULT_API_URL", { enumerable: true, get: function () { return sdk_core_1.DEFAULT_API_URL; } });
|
|
16
16
|
/** The largest batch the server-error endpoint accepts (`MAX_SERVER_ERROR_BATCH`). */
|
|
17
17
|
const SERVER_MAX_BATCH = 500;
|
|
18
18
|
const DEFAULT_MAX_BATCH_SIZE = 100;
|
|
@@ -29,8 +29,12 @@ function trimmed(value) {
|
|
|
29
29
|
}
|
|
30
30
|
/** Normalise an api base URL: trim and strip trailing slashes. */
|
|
31
31
|
function normalizeApiUrl(value) {
|
|
32
|
-
const base = trimmed(value) ??
|
|
33
|
-
return base.replace(/\/+$/, "") ||
|
|
32
|
+
const base = trimmed(value) ?? sdk_core_1.DEFAULT_API_URL;
|
|
33
|
+
return base.replace(/\/+$/, "") || sdk_core_1.DEFAULT_API_URL;
|
|
34
|
+
}
|
|
35
|
+
/** A per-signal flag: an explicit boolean wins, else the umbrella default. */
|
|
36
|
+
function underUmbrella(flag, umbrella) {
|
|
37
|
+
return typeof flag === "boolean" ? flag : umbrella;
|
|
34
38
|
}
|
|
35
39
|
/** Clamp a positive-integer option to `[min, max]`, falling back to `fallback`. */
|
|
36
40
|
function clampInt(value, fallback, min, max) {
|
|
@@ -47,6 +51,7 @@ function resolveConfig(options) {
|
|
|
47
51
|
const secretKey = trimmed(options.secretKey) ?? "";
|
|
48
52
|
const apiUrl = normalizeApiUrl(options.apiUrl);
|
|
49
53
|
const enabled = options.enabled !== false && secretKey.length > 0;
|
|
54
|
+
const autoCapture = options.autoCapture !== false;
|
|
50
55
|
return {
|
|
51
56
|
enabled,
|
|
52
57
|
secretKey,
|
|
@@ -56,8 +61,8 @@ function resolveConfig(options) {
|
|
|
56
61
|
release: trimmed(options.release),
|
|
57
62
|
beforeSend: typeof options.beforeSend === "function" ? options.beforeSend : undefined,
|
|
58
63
|
scrub: options.scrub !== false,
|
|
59
|
-
captureUncaughtException: options.captureUncaughtException
|
|
60
|
-
captureUnhandledRejection: options.captureUnhandledRejection
|
|
64
|
+
captureUncaughtException: underUmbrella(options.captureUncaughtException, autoCapture),
|
|
65
|
+
captureUnhandledRejection: underUmbrella(options.captureUnhandledRejection, autoCapture),
|
|
61
66
|
maxBatchSize: clampInt(options.maxBatchSize, DEFAULT_MAX_BATCH_SIZE, 1, SERVER_MAX_BATCH),
|
|
62
67
|
flushIntervalMs: clampInt(options.flushIntervalMs, DEFAULT_FLUSH_INTERVAL_MS, 0, Number.MAX_SAFE_INTEGER),
|
|
63
68
|
maxQueueSize: clampInt(options.maxQueueSize, DEFAULT_MAX_QUEUE_SIZE, 1, Number.MAX_SAFE_INTEGER),
|
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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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Host identity** minting (ADR-0032; ticket #251) — the escape hatch for a backend
|
|
3
|
+
* that already knows who its users are.
|
|
4
|
+
*
|
|
5
|
+
* A Host identity is a compact `HS256` JWT the customer's own server mints with the
|
|
6
|
+
* Project's **secret key** and hands to a capture SDK; ingest verifies it and tiers the
|
|
7
|
+
* Reporter (Member ⇒ Internal, else Invited) with no Connect round trip. This helper is
|
|
8
|
+
* the executable statement of the signing recipe, so a customer never has to hand-roll
|
|
9
|
+
* JWT signing:
|
|
10
|
+
*
|
|
11
|
+
* key = sha256(secretKey) // hex — the value the server stores and verifies against
|
|
12
|
+
* token = base64url(header).base64url(payload).base64url(HMAC-SHA256(key, signingInput))
|
|
13
|
+
*
|
|
14
|
+
* The MAC key is `sha256(secretKey)` because that hash (`api_key.secret_hash`) is the
|
|
15
|
+
* only key material the server keeps — the secret plaintext is shown once at issuance
|
|
16
|
+
* and never stored (ADR-0005). Signing with anything else would produce a token ingest
|
|
17
|
+
* could never verify.
|
|
18
|
+
*
|
|
19
|
+
* It runs on the customer's **server**, never in a browser or the app bundle — the
|
|
20
|
+
* secret key is a real credential and must not ship to a client. (This SDK is a Node
|
|
21
|
+
* backend SDK, so that is where it lives.)
|
|
22
|
+
*/
|
|
23
|
+
/** What {@link mintHostIdentity} needs to mint a token. */
|
|
24
|
+
export interface MintHostIdentityOptions {
|
|
25
|
+
/**
|
|
26
|
+
* The Project **secret key** (`sk_…`), the same credential {@link init} and
|
|
27
|
+
* `npx fixback sourcemaps upload` use. It signs the token; keep it server-side.
|
|
28
|
+
*/
|
|
29
|
+
readonly secretKey: string;
|
|
30
|
+
/**
|
|
31
|
+
* The customer's own stable identifier for the user — becomes the JWT `sub`, which
|
|
32
|
+
* keys the Reporter. Must be non-empty; a token that names no one is refused by
|
|
33
|
+
* ingest.
|
|
34
|
+
*/
|
|
35
|
+
readonly subject: string;
|
|
36
|
+
/**
|
|
37
|
+
* The user's email address, optional. When it matches an Org Member, ingest tiers
|
|
38
|
+
* the Reporter **Internal**; when it matches any verified Fixback Account, the
|
|
39
|
+
* Reporter is unified with that Account's (one person, one Reporter). Omit it for a
|
|
40
|
+
* valid-but-external identity, which ingest tiers **Invited**.
|
|
41
|
+
*/
|
|
42
|
+
readonly email?: string;
|
|
43
|
+
/**
|
|
44
|
+
* How long the token is valid, in seconds. Defaults to one hour. `exp` is
|
|
45
|
+
* mandatory — an identity assertion that never expires is exactly what an
|
|
46
|
+
* escape-hatch credential must not be (ADR-0032) — so this is always set.
|
|
47
|
+
*/
|
|
48
|
+
readonly expiresInSeconds?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Mint a Host identity JWT for a user. Signs an `HS256` token with `sha256(secretKey)`,
|
|
52
|
+
* exactly as ingest verifies it, so the returned string can be handed straight to a
|
|
53
|
+
* capture SDK as its `hostIdentity`.
|
|
54
|
+
*
|
|
55
|
+
* Throws on a missing secret key or subject: unlike `init` (which is fail-quiet so a
|
|
56
|
+
* misconfiguration never breaks the host server), minting is an explicit call whose
|
|
57
|
+
* only job is to produce a usable token — a bad argument is a programming error worth
|
|
58
|
+
* surfacing, not a silent empty token that ingest would reject downstream.
|
|
59
|
+
*/
|
|
60
|
+
export declare function mintHostIdentity(options: MintHostIdentityOptions): string;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* **Host identity** minting (ADR-0032; ticket #251) — the escape hatch for a backend
|
|
4
|
+
* that already knows who its users are.
|
|
5
|
+
*
|
|
6
|
+
* A Host identity is a compact `HS256` JWT the customer's own server mints with the
|
|
7
|
+
* Project's **secret key** and hands to a capture SDK; ingest verifies it and tiers the
|
|
8
|
+
* Reporter (Member ⇒ Internal, else Invited) with no Connect round trip. This helper is
|
|
9
|
+
* the executable statement of the signing recipe, so a customer never has to hand-roll
|
|
10
|
+
* JWT signing:
|
|
11
|
+
*
|
|
12
|
+
* key = sha256(secretKey) // hex — the value the server stores and verifies against
|
|
13
|
+
* token = base64url(header).base64url(payload).base64url(HMAC-SHA256(key, signingInput))
|
|
14
|
+
*
|
|
15
|
+
* The MAC key is `sha256(secretKey)` because that hash (`api_key.secret_hash`) is the
|
|
16
|
+
* only key material the server keeps — the secret plaintext is shown once at issuance
|
|
17
|
+
* and never stored (ADR-0005). Signing with anything else would produce a token ingest
|
|
18
|
+
* could never verify.
|
|
19
|
+
*
|
|
20
|
+
* It runs on the customer's **server**, never in a browser or the app bundle — the
|
|
21
|
+
* secret key is a real credential and must not ship to a client. (This SDK is a Node
|
|
22
|
+
* backend SDK, so that is where it lives.)
|
|
23
|
+
*/
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.mintHostIdentity = mintHostIdentity;
|
|
26
|
+
const node_crypto_1 = require("node:crypto");
|
|
27
|
+
/** How long a minted Host identity is valid by default — one hour. */
|
|
28
|
+
const DEFAULT_EXPIRES_IN_SECONDS = 60 * 60;
|
|
29
|
+
/** base64url with no padding — the JWT segment encoding. */
|
|
30
|
+
function base64url(input) {
|
|
31
|
+
return Buffer.from(input).toString("base64url");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Mint a Host identity JWT for a user. Signs an `HS256` token with `sha256(secretKey)`,
|
|
35
|
+
* exactly as ingest verifies it, so the returned string can be handed straight to a
|
|
36
|
+
* capture SDK as its `hostIdentity`.
|
|
37
|
+
*
|
|
38
|
+
* Throws on a missing secret key or subject: unlike `init` (which is fail-quiet so a
|
|
39
|
+
* misconfiguration never breaks the host server), minting is an explicit call whose
|
|
40
|
+
* only job is to produce a usable token — a bad argument is a programming error worth
|
|
41
|
+
* surfacing, not a silent empty token that ingest would reject downstream.
|
|
42
|
+
*/
|
|
43
|
+
function mintHostIdentity(options) {
|
|
44
|
+
const secretKey = typeof options.secretKey === "string" ? options.secretKey.trim() : "";
|
|
45
|
+
const subject = typeof options.subject === "string" ? options.subject.trim() : "";
|
|
46
|
+
if (!secretKey) {
|
|
47
|
+
throw new Error("mintHostIdentity: a Project secret key (sk_…) is required");
|
|
48
|
+
}
|
|
49
|
+
if (!subject) {
|
|
50
|
+
throw new Error("mintHostIdentity: a non-empty `subject` is required");
|
|
51
|
+
}
|
|
52
|
+
const ttl = typeof options.expiresInSeconds === "number" &&
|
|
53
|
+
Number.isFinite(options.expiresInSeconds) &&
|
|
54
|
+
options.expiresInSeconds > 0
|
|
55
|
+
? Math.floor(options.expiresInSeconds)
|
|
56
|
+
: DEFAULT_EXPIRES_IN_SECONDS;
|
|
57
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
58
|
+
const header = { alg: "HS256", typ: "JWT" };
|
|
59
|
+
const payload = {
|
|
60
|
+
sub: subject,
|
|
61
|
+
iat: nowSeconds,
|
|
62
|
+
exp: nowSeconds + ttl,
|
|
63
|
+
};
|
|
64
|
+
const email = typeof options.email === "string" ? options.email.trim() : "";
|
|
65
|
+
if (email)
|
|
66
|
+
payload.email = email;
|
|
67
|
+
const signingInput = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(payload))}`;
|
|
68
|
+
const key = (0, node_crypto_1.createHash)("sha256").update(secretKey).digest("hex");
|
|
69
|
+
const signature = (0, node_crypto_1.createHmac)("sha256", key).update(signingInput).digest();
|
|
70
|
+
return `${signingInput}.${base64url(signature)}`;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=host-identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-identity.js","sourceRoot":"","sources":["../src/host-identity.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;;AAkDH,4CAmCC;AAnFD,6CAAqD;AAErD,sEAAsE;AACtE,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,CAAC;AA8B3C,4DAA4D;AAC5D,SAAS,SAAS,CAAC,KAAsB;IACvC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,gBAAgB,CAAC,OAAgC;IAC/D,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,MAAM,OAAO,GACX,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,GAAG,GACP,OAAO,OAAO,CAAC,gBAAgB,KAAK,QAAQ;QAC5C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC;QACzC,OAAO,CAAC,gBAAgB,GAAG,CAAC;QAC1B,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC;QACtC,CAAC,CAAC,0BAA0B,CAAC;IACjC,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAEjD,MAAM,MAAM,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;IAC5C,MAAM,OAAO,GAA4B;QACvC,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,UAAU;QACf,GAAG,EAAE,UAAU,GAAG,GAAG;KACtB,CAAC;IACF,MAAM,KAAK,GAAG,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5E,IAAI,KAAK;QAAE,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;IAEjC,MAAM,YAAY,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,SAAS,CACpE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CACxB,EAAE,CAAC;IACJ,MAAM,GAAG,GAAG,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1E,OAAO,GAAG,YAAY,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;AACnD,CAAC"}
|
package/dist/http.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Minimal **structural** types for the HTTP surface the adapters touch, plus
|
|
3
3
|
* {@link routePatternOf}.
|
|
4
4
|
*
|
|
5
|
-
* Described structurally (the same posture
|
|
6
|
-
* SDK needs no `@types/express` dependency: Express and NestJS (on Express) both pass
|
|
5
|
+
* Described structurally (the same posture the shared core takes for `fetch`) so
|
|
6
|
+
* the SDK needs no `@types/express` dependency: Express and NestJS (on Express) both pass
|
|
7
7
|
* requests/responses that satisfy these shapes, and tests pass plain objects. Only
|
|
8
8
|
* the private-by-default fields are read here — never bodies, headers beyond the
|
|
9
9
|
* correlation id, query values, or env.
|
package/dist/http.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
* Minimal **structural** types for the HTTP surface the adapters touch, plus
|
|
4
4
|
* {@link routePatternOf}.
|
|
5
5
|
*
|
|
6
|
-
* Described structurally (the same posture
|
|
7
|
-
* SDK needs no `@types/express` dependency: Express and NestJS (on Express) both pass
|
|
6
|
+
* Described structurally (the same posture the shared core takes for `fetch`) so
|
|
7
|
+
* the SDK needs no `@types/express` dependency: Express and NestJS (on Express) both pass
|
|
8
8
|
* requests/responses that satisfy these shapes, and tests pass plain objects. Only
|
|
9
9
|
* the private-by-default fields are read here — never bodies, headers beyond the
|
|
10
10
|
* correlation id, query values, or env.
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export { currentServerContext, getRequestStore, setRequestUser, setRequestUser a
|
|
|
17
17
|
export type { RequestStore } from "./context";
|
|
18
18
|
export { DEFAULT_API_URL } from "./config";
|
|
19
19
|
export type { InitOptions } from "./config";
|
|
20
|
+
export { mintHostIdentity } from "./host-identity";
|
|
21
|
+
export type { MintHostIdentityOptions } from "./host-identity";
|
|
20
22
|
export type { CaptureTransport } from "./transport";
|
|
21
23
|
export type { BeforeSend, FixbackErrorEvent, ServerContext, ServerErrorPayload, Severity, } from "./wire";
|
|
22
24
|
export type { CapturedFrame } from "@fixback/sdk-core";
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* `setUser`, and the shared types.
|
|
14
14
|
*/
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.NODE_SDK_VERSION = exports.DEFAULT_API_URL = exports.setUser = exports.setRequestUser = exports.getRequestStore = exports.currentServerContext = exports.init = exports.getClient = exports.flush = exports.FixbackClient = exports.close = exports.captureMessage = exports.captureException = void 0;
|
|
16
|
+
exports.NODE_SDK_VERSION = exports.mintHostIdentity = exports.DEFAULT_API_URL = exports.setUser = exports.setRequestUser = exports.getRequestStore = exports.currentServerContext = exports.init = exports.getClient = exports.flush = exports.FixbackClient = exports.close = exports.captureMessage = exports.captureException = void 0;
|
|
17
17
|
// Capture surface + lifecycle.
|
|
18
18
|
var client_1 = require("./client");
|
|
19
19
|
Object.defineProperty(exports, "captureException", { enumerable: true, get: function () { return client_1.captureException; } });
|
|
@@ -32,6 +32,10 @@ Object.defineProperty(exports, "setUser", { enumerable: true, get: function () {
|
|
|
32
32
|
// Configuration.
|
|
33
33
|
var config_1 = require("./config");
|
|
34
34
|
Object.defineProperty(exports, "DEFAULT_API_URL", { enumerable: true, get: function () { return config_1.DEFAULT_API_URL; } });
|
|
35
|
+
// Host identity (ADR-0032) — mint a server-signed identity JWT a capture SDK presents
|
|
36
|
+
// as its `hostIdentity`, so a backend can tier its own users without Connect.
|
|
37
|
+
var host_identity_1 = require("./host-identity");
|
|
38
|
+
Object.defineProperty(exports, "mintHostIdentity", { enumerable: true, get: function () { return host_identity_1.mintHostIdentity; } });
|
|
35
39
|
// The SDK's own version, reported as the capture `sdkVersion`.
|
|
36
40
|
var version_1 = require("./version");
|
|
37
41
|
Object.defineProperty(exports, "NODE_SDK_VERSION", { enumerable: true, get: function () { return version_1.NODE_SDK_VERSION; } });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAEH,+BAA+B;AAC/B,mCAQkB;AAPhB,0GAAA,gBAAgB,OAAA;AAChB,wGAAA,cAAc,OAAA;AACd,+FAAA,KAAK,OAAA;AACL,uGAAA,aAAa,OAAA;AACb,+FAAA,KAAK,OAAA;AACL,mGAAA,SAAS,OAAA;AACT,8FAAA,IAAI,OAAA;AAIN,uFAAuF;AACvF,qCAA6G;AAApG,+GAAA,oBAAoB,OAAA;AAAE,0GAAA,eAAe,OAAA;AAAE,yGAAA,cAAc,OAAA;AAAE,kGAAA,cAAc,OAAW;AAGzF,iBAAiB;AACjB,mCAA2C;AAAlC,yGAAA,eAAe,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;AAEH,+BAA+B;AAC/B,mCAQkB;AAPhB,0GAAA,gBAAgB,OAAA;AAChB,wGAAA,cAAc,OAAA;AACd,+FAAA,KAAK,OAAA;AACL,uGAAA,aAAa,OAAA;AACb,+FAAA,KAAK,OAAA;AACL,mGAAA,SAAS,OAAA;AACT,8FAAA,IAAI,OAAA;AAIN,uFAAuF;AACvF,qCAA6G;AAApG,+GAAA,oBAAoB,OAAA;AAAE,0GAAA,eAAe,OAAA;AAAE,yGAAA,cAAc,OAAA;AAAE,kGAAA,cAAc,OAAW;AAGzF,iBAAiB;AACjB,mCAA2C;AAAlC,yGAAA,eAAe,OAAA;AAGxB,sFAAsF;AACtF,8EAA8E;AAC9E,iDAAmD;AAA1C,iHAAA,gBAAgB,OAAA;AAkBzB,+DAA+D;AAC/D,qCAA6C;AAApC,2GAAA,gBAAgB,OAAA"}
|
package/dist/stack.d.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Turning a thrown value into the
|
|
3
|
-
*
|
|
4
|
-
* **structured stack frames** for the wire ({@link extractStructuredFrames}).
|
|
2
|
+
* Turning a thrown value into the distilled `type | value | stack` a fingerprint is
|
|
3
|
+
* built from.
|
|
5
4
|
*
|
|
6
|
-
* The distillation mirrors the
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* The distillation mirrors the capture SDKs' exactly — `type = error.name`,
|
|
6
|
+
* `value = error.message`, `stack = error.stack` — so the same logical error yields
|
|
7
|
+
* the same shared-core fingerprint on every surface (the ADR-0028 parity guarantee).
|
|
8
|
+
* Parsing that stack into **structured frames** for the wire is the shared core's job
|
|
9
|
+
* (`extractStructuredFrames`, `@fixback/sdk-core`), so every SDK reads a stack with
|
|
10
|
+
* one parser.
|
|
12
11
|
*/
|
|
13
|
-
import { type CapturedFrame } from "@fixback/sdk-core";
|
|
14
12
|
/** The distilled shape a fingerprint and a report are built from. */
|
|
15
13
|
export interface ExtractedError {
|
|
16
14
|
readonly type: string;
|
|
@@ -23,11 +21,3 @@ export interface ExtractedError {
|
|
|
23
21
|
* value; any other value is stringified. Never throws.
|
|
24
22
|
*/
|
|
25
23
|
export declare function extractError(input: unknown): ExtractedError;
|
|
26
|
-
/**
|
|
27
|
-
* Extract structured frames from a stack for the wire (#117, ADR-0024), top of stack
|
|
28
|
-
* first. Keeps the full (scrubbed) script path so server-side symbolication can match
|
|
29
|
-
* it against uploaded sourcemaps; skips unlocatable frames (`native`, `<anonymous>`,
|
|
30
|
-
* eval); caps the count. V8 is Node's format; the Firefox/Safari form is handled too
|
|
31
|
-
* so the parser matches the browser SDK's exactly.
|
|
32
|
-
*/
|
|
33
|
-
export declare function extractStructuredFrames(stack: string | undefined, limit?: number): CapturedFrame[];
|
package/dist/stack.js
CHANGED
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Turning a thrown value into the
|
|
4
|
-
*
|
|
5
|
-
* **structured stack frames** for the wire ({@link extractStructuredFrames}).
|
|
3
|
+
* Turning a thrown value into the distilled `type | value | stack` a fingerprint is
|
|
4
|
+
* built from.
|
|
6
5
|
*
|
|
7
|
-
* The distillation mirrors the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* The distillation mirrors the capture SDKs' exactly — `type = error.name`,
|
|
7
|
+
* `value = error.message`, `stack = error.stack` — so the same logical error yields
|
|
8
|
+
* the same shared-core fingerprint on every surface (the ADR-0028 parity guarantee).
|
|
9
|
+
* Parsing that stack into **structured frames** for the wire is the shared core's job
|
|
10
|
+
* (`extractStructuredFrames`, `@fixback/sdk-core`), so every SDK reads a stack with
|
|
11
|
+
* one parser.
|
|
13
12
|
*/
|
|
14
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
14
|
exports.extractError = extractError;
|
|
16
|
-
exports.extractStructuredFrames = extractStructuredFrames;
|
|
17
|
-
const sdk_core_1 = require("@fixback/sdk-core");
|
|
18
|
-
/** The most structured frames shipped per error (mirrors the server's cap). */
|
|
19
|
-
const STRUCTURED_FRAME_LIMIT = 30;
|
|
20
15
|
/** Coerce any value to a string without throwing (a hostile `toString` can throw). */
|
|
21
16
|
function asString(value) {
|
|
22
17
|
if (typeof value === "string")
|
|
@@ -75,68 +70,4 @@ function extractError(input) {
|
|
|
75
70
|
}
|
|
76
71
|
return { type: "Error", value: asString(input), stack: undefined };
|
|
77
72
|
}
|
|
78
|
-
/** Split a `file:line:col` location into parts; `null` when it has no line. */
|
|
79
|
-
function parseLocation(location) {
|
|
80
|
-
// The file may itself contain colons (https://…, node:internal/…), so split from
|
|
81
|
-
// the right: the trailing `:line(:col)?` are the numeric groups.
|
|
82
|
-
const match = location.match(/^(.*?):(\d+)(?::(\d+))?$/);
|
|
83
|
-
if (!match)
|
|
84
|
-
return null;
|
|
85
|
-
const file = match[1] ?? "";
|
|
86
|
-
if (file.length === 0 || file === "native" || file.includes("<anonymous>")) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
const line = Number(match[2]);
|
|
90
|
-
if (!Number.isFinite(line))
|
|
91
|
-
return null;
|
|
92
|
-
const column = match[3] !== undefined ? Number(match[3]) : null;
|
|
93
|
-
return { file, line, column };
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Extract structured frames from a stack for the wire (#117, ADR-0024), top of stack
|
|
97
|
-
* first. Keeps the full (scrubbed) script path so server-side symbolication can match
|
|
98
|
-
* it against uploaded sourcemaps; skips unlocatable frames (`native`, `<anonymous>`,
|
|
99
|
-
* eval); caps the count. V8 is Node's format; the Firefox/Safari form is handled too
|
|
100
|
-
* so the parser matches the browser SDK's exactly.
|
|
101
|
-
*/
|
|
102
|
-
function extractStructuredFrames(stack, limit = STRUCTURED_FRAME_LIMIT) {
|
|
103
|
-
if (typeof stack !== "string" || stack.length === 0)
|
|
104
|
-
return [];
|
|
105
|
-
const frames = [];
|
|
106
|
-
for (const raw of stack.split("\n")) {
|
|
107
|
-
if (frames.length >= limit)
|
|
108
|
-
break;
|
|
109
|
-
const line = raw.trim();
|
|
110
|
-
let fn = null;
|
|
111
|
-
let location = null;
|
|
112
|
-
// V8: "at fn (loc)" | "at loc"
|
|
113
|
-
const v8Named = line.match(/^at\s+(.+?)\s+\((.+)\)$/);
|
|
114
|
-
const v8Bare = v8Named ? null : line.match(/^at\s+(.+)$/);
|
|
115
|
-
const geckoAt = v8Named || v8Bare ? -1 : line.indexOf("@");
|
|
116
|
-
if (v8Named) {
|
|
117
|
-
fn = v8Named[1] ?? null;
|
|
118
|
-
location = v8Named[2] ?? null;
|
|
119
|
-
}
|
|
120
|
-
else if (v8Bare) {
|
|
121
|
-
location = v8Bare[1] ?? null;
|
|
122
|
-
}
|
|
123
|
-
else if (geckoAt >= 0) {
|
|
124
|
-
// Firefox / Safari: "fn@loc" | "@loc"
|
|
125
|
-
fn = geckoAt > 0 ? line.slice(0, geckoAt) : null;
|
|
126
|
-
location = line.slice(geckoAt + 1);
|
|
127
|
-
}
|
|
128
|
-
if (!location)
|
|
129
|
-
continue;
|
|
130
|
-
const parsed = parseLocation(location);
|
|
131
|
-
if (!parsed)
|
|
132
|
-
continue;
|
|
133
|
-
frames.push({
|
|
134
|
-
file: (0, sdk_core_1.scrubUrl)(parsed.file),
|
|
135
|
-
line: parsed.line,
|
|
136
|
-
column: parsed.column,
|
|
137
|
-
function: fn && fn.length > 0 ? fn : null,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
return frames;
|
|
141
|
-
}
|
|
142
73
|
//# sourceMappingURL=stack.js.map
|
package/dist/stack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAkDH,oCAuBC;AA1DD,sFAAsF;AACtF,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,uFAAuF;AACvF,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,GAAG,GAAG,KAAkB,CAAC;IAC/B,OAAO,CACL,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAC/B,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ;QAC7B,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAC7B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO;YACL,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO;YACrC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;YAC9B,KAAK,EAAE,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;SACjE,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC3D,CAAC;IACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,KAAkB,CAAC;YAC/B,OAAO;gBACL,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO;gBACnC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;gBAC5B,KAAK,EAAE,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aAC7D,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;AACrE,CAAC"}
|
package/dist/transport.d.ts
CHANGED
|
@@ -13,24 +13,8 @@
|
|
|
13
13
|
* - **Fail-quiet (story 34):** an unreachable, timing-out, or refusing endpoint never
|
|
14
14
|
* throws to the host and never grows the buffer without bound (`maxQueueSize`).
|
|
15
15
|
*/
|
|
16
|
-
import { AutoReportBackoff } from "@fixback/sdk-core";
|
|
16
|
+
import { AutoReportBackoff, type FetchLike } from "@fixback/sdk-core";
|
|
17
17
|
import type { ServerErrorPayload } from "./wire";
|
|
18
|
-
/** The response slice the transport reads. Satisfied by the global `fetch` Response. */
|
|
19
|
-
export interface FetchResponseLike {
|
|
20
|
-
readonly ok: boolean;
|
|
21
|
-
readonly status: number;
|
|
22
|
-
readonly headers?: {
|
|
23
|
-
get(name: string): string | null;
|
|
24
|
-
} | null;
|
|
25
|
-
}
|
|
26
|
-
/** The request init the transport sends — a subset of the standard `RequestInit`. */
|
|
27
|
-
export interface FetchRequestInit {
|
|
28
|
-
readonly method: string;
|
|
29
|
-
readonly headers?: Record<string, string>;
|
|
30
|
-
readonly body?: string;
|
|
31
|
-
}
|
|
32
|
-
/** A `fetch`-shaped function, injectable for tests. */
|
|
33
|
-
export type FetchLike = (url: string, init: FetchRequestInit) => Promise<FetchResponseLike>;
|
|
34
18
|
/**
|
|
35
19
|
* The narrow transport surface the client depends on — buffer one error, flush, and
|
|
36
20
|
* close. {@link Transport} is the real implementation; tests inject a fake recorder.
|
package/dist/transport.js
CHANGED
|
@@ -17,23 +17,6 @@
|
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
exports.Transport = void 0;
|
|
19
19
|
const sdk_core_1 = require("@fixback/sdk-core");
|
|
20
|
-
/** The global `fetch`, adapted to {@link FetchLike}, or `undefined` when unavailable. */
|
|
21
|
-
function resolveFetch() {
|
|
22
|
-
const g = globalThis;
|
|
23
|
-
if (typeof g.fetch !== "function")
|
|
24
|
-
return undefined;
|
|
25
|
-
const bound = g.fetch.bind(globalThis);
|
|
26
|
-
return (url, init) => bound(url, init);
|
|
27
|
-
}
|
|
28
|
-
/** Read a response header defensively — `null` when unavailable or on any throw. */
|
|
29
|
-
function safeHeader(response, name) {
|
|
30
|
-
try {
|
|
31
|
-
return response.headers?.get?.(name) ?? null;
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
20
|
class Transport {
|
|
38
21
|
config;
|
|
39
22
|
fetchImpl;
|
|
@@ -45,7 +28,7 @@ class Transport {
|
|
|
45
28
|
closed = false;
|
|
46
29
|
constructor(config, deps = {}) {
|
|
47
30
|
this.config = config;
|
|
48
|
-
this.fetchImpl = deps.fetchImpl ?? resolveFetch();
|
|
31
|
+
this.fetchImpl = deps.fetchImpl ?? (0, sdk_core_1.resolveFetch)();
|
|
49
32
|
this.backoff = deps.backoff ?? new sdk_core_1.AutoReportBackoff();
|
|
50
33
|
if (config.flushIntervalMs > 0) {
|
|
51
34
|
this.timer = setInterval(() => {
|
|
@@ -130,6 +113,7 @@ class Transport {
|
|
|
130
113
|
const doFetch = this.fetchImpl;
|
|
131
114
|
if (!doFetch || batch.length === 0)
|
|
132
115
|
return false;
|
|
116
|
+
const body = { errors: batch };
|
|
133
117
|
let response;
|
|
134
118
|
try {
|
|
135
119
|
response = await this.withTimeout(doFetch(this.config.endpoint, {
|
|
@@ -138,7 +122,7 @@ class Transport {
|
|
|
138
122
|
authorization: `Bearer ${this.config.secretKey}`,
|
|
139
123
|
"content-type": "application/json",
|
|
140
124
|
},
|
|
141
|
-
body: JSON.stringify(
|
|
125
|
+
body: JSON.stringify(body),
|
|
142
126
|
}));
|
|
143
127
|
}
|
|
144
128
|
catch {
|
|
@@ -146,7 +130,7 @@ class Transport {
|
|
|
146
130
|
}
|
|
147
131
|
if (!response.ok) {
|
|
148
132
|
if (response.status === 429) {
|
|
149
|
-
this.backoff.hold(safeHeader(response, "retry-after"));
|
|
133
|
+
this.backoff.hold((0, sdk_core_1.safeHeader)(response, "retry-after"));
|
|
150
134
|
return false;
|
|
151
135
|
}
|
|
152
136
|
return false; // refused — fail quiet
|