@argusdev/sdk-node 0.1.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 ADDED
@@ -0,0 +1,33 @@
1
+ # @argusdev/sdk-node
2
+
3
+ Node.js SDK for [Argus](https://github.com/oluwatobicode/argus) — captures uncaught exceptions and unhandled rejections, with an optional Express error handler.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @argusdev/sdk-node
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { init } from "@argusdev/sdk-node";
15
+
16
+ init({ dsn: "https://<publicKey>@<host>/<projectId>", environment: "production" });
17
+ ```
18
+
19
+ `process.on("uncaughtException")` and `process.on("unhandledRejection")` are wired automatically. On an uncaught exception the event is sent, then the process exits `1` (crash behavior preserved).
20
+
21
+ ### Express
22
+
23
+ Add the error handler **after your routes**, before your own:
24
+
25
+ ```ts
26
+ import { argusErrorHandler } from "@argusdev/sdk-node";
27
+
28
+ app.use(argusErrorHandler());
29
+ ```
30
+
31
+ It captures the error with request context, then passes it along — it observes, never absorbs.
32
+
33
+ MIT © Treasure Odetokun
@@ -0,0 +1,7 @@
1
+ interface RequestLike {
2
+ method?: string;
3
+ originalUrl?: string;
4
+ url?: string;
5
+ }
6
+ export declare function argusErrorHandler(): (err: unknown, req: RequestLike, _res: unknown, next: (err?: unknown) => void) => void;
7
+ export {};
@@ -0,0 +1,20 @@
1
+ import { captureException } from "./init";
2
+ /*
3
+ * Usage (LAST middleware, after routes):
4
+ * app.use(argusErrorHandler());
5
+ *
6
+ * Captures the error with request context, then passes it along so the
7
+ * app's own error handler still responds to the user. We observe, never absorb.
8
+ */
9
+ export function argusErrorHandler() {
10
+ return (err, req, _res, next) => {
11
+ void captureException(err, {
12
+ request: {
13
+ method: req.method,
14
+ url: req.originalUrl ?? req.url,
15
+ },
16
+ });
17
+ next(err);
18
+ };
19
+ }
20
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAS1C;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CACL,GAAY,EACZ,GAAgB,EAChB,IAAa,EACb,IAA6B,EACvB,EAAE;QACR,KAAK,gBAAgB,CAAC,GAAG,EAAE;YACzB,OAAO,EAAE;gBACP,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,EAAE,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,GAAG;aAChC;SACF,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,CAAC;IACZ,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { init, captureException } from "./init";
2
+ export type { InitOptions } from "./init";
3
+ export { argusErrorHandler } from "./express";
4
+ export { parseStack } from "./stacktrace";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ /* Public surface of @argusdev/sdk-node */
2
+ export { init, captureException } from "./init";
3
+ export { argusErrorHandler } from "./express";
4
+ export { parseStack } from "./stacktrace";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAE1C,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAEhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
package/dist/init.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { type EnvelopeOptions } from "@argusdev/sdk-core";
2
+ export interface InitOptions {
3
+ dsn: string;
4
+ environment?: string;
5
+ release?: string;
6
+ }
7
+ export declare function init(options: InitOptions): void;
8
+ export declare function captureException(err: unknown, extra?: EnvelopeOptions): Promise<void>;
package/dist/init.js ADDED
@@ -0,0 +1,39 @@
1
+ import { parseDsn, getIngestUrl, buildEnvelope, sendEnvelope, } from "@argusdev/sdk-core";
2
+ import { parseStack } from "./stacktrace";
3
+ /* set once by init(); null means "not initialized — do nothing, never crash" */
4
+ let client = null;
5
+ export function init(options) {
6
+ const parsed = parseDsn(options.dsn); /* throws on bad DSN — loudly, at startup */
7
+ client = {
8
+ url: getIngestUrl(parsed),
9
+ publicKey: parsed.publicKey,
10
+ environment: options.environment,
11
+ release: options.release,
12
+ };
13
+ process.on("uncaughtException", (err) => {
14
+ /* capture, wait for the send, then exit non-zero — after an uncaught
15
+ exception the process state is untrustworthy; Node docs say exit. */
16
+ void captureException(err).finally(() => process.exit(1));
17
+ });
18
+ process.on("unhandledRejection", (reason) => {
19
+ void captureException(reason);
20
+ });
21
+ }
22
+ export async function captureException(err, extra = {}) {
23
+ if (!client)
24
+ return; /* init() not called — silently no-op */
25
+ /* people reject(non-Error) all the time — normalize */
26
+ const error = err instanceof Error ? err : new Error(String(err));
27
+ let frames = parseStack(error.stack);
28
+ if (frames.length === 0) {
29
+ /* validator requires >= 1 frame — synthesize one rather than drop the event */
30
+ frames = [{ filename: "<unknown>", lineno: 1 }];
31
+ }
32
+ const envelope = buildEnvelope(error.name, error.message, frames, {
33
+ environment: client.environment,
34
+ release: client.release,
35
+ ...extra,
36
+ });
37
+ await sendEnvelope(client.url, client.publicKey, envelope);
38
+ }
39
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,YAAY,GAEb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQ1C,gFAAgF;AAChF,IAAI,MAAM,GAKC,IAAI,CAAC;AAEhB,MAAM,UAAU,IAAI,CAAC,OAAoB;IACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,4CAA4C;IAClF,MAAM,GAAG;QACP,GAAG,EAAE,YAAY,CAAC,MAAM,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAU,EAAE,EAAE;QAC7C;+EACuE;QACvE,KAAK,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAe,EAAE,EAAE;QACnD,KAAK,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAY,EACZ,QAAyB,EAAE;IAE3B,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,wCAAwC;IAE7D,uDAAuD;IACvD,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAElE,IAAI,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,+EAA+E;QAC/E,MAAM,GAAG,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,QAAQ,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE;QAChE,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,GAAG,KAAK;KACT,CAAC,CAAC;IAEH,MAAM,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { StackFrame } from "@argusdev/sdk-core";
2
+ export declare function parseStack(stack: string | undefined): StackFrame[];
@@ -0,0 +1,26 @@
1
+ /* V8 stack lines come in two shapes:
2
+ * at inner (/app/src/service.ts:42:17) ← named
3
+ * at /app/src/index.ts:7:3 ← anonymous
4
+ * One regex covers both: the "name (" part is optional.
5
+ */
6
+ const FRAME_REGEX = /^at\s+(?:(.+?)\s+\()?(.+):(\d+):(\d+)\)?$/;
7
+ export function parseStack(stack) {
8
+ if (!stack)
9
+ return [];
10
+ const frames = stack.split("\n").map((line) => {
11
+ const match = line.trim().match(FRAME_REGEX);
12
+ if (!match)
13
+ return null;
14
+ const frame = {
15
+ filename: match[2],
16
+ lineno: Number(match[3]),
17
+ colno: Number(match[4]),
18
+ };
19
+ if (match[1]) {
20
+ frame.function = match[1];
21
+ }
22
+ return frame;
23
+ });
24
+ return frames.filter((frame) => frame !== null);
25
+ }
26
+ //# sourceMappingURL=stacktrace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stacktrace.js","sourceRoot":"","sources":["../src/stacktrace.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,GAAG,2CAA2C,CAAC;AAEhE,MAAM,UAAU,UAAU,CAAC,KAAyB;IAClD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAqB,EAAE;QAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC7C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,KAAK,GAAe;YACxB,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAE;YACnB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACxB,CAAC;QACF,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAuB,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;AACvE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@argusdev/sdk-node",
3
+ "version": "0.1.0",
4
+ "description": "Argus SDK for Node.js — uncaught exceptions, unhandled rejections, Express middleware.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "dev": "tsc --watch",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "dependencies": {
23
+ "@argusdev/sdk-core": "workspace:*"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^26.0.1",
27
+ "typescript": "~6.0.3"
28
+ },
29
+ "license": "MIT",
30
+ "author": "Treasure Odetokun",
31
+ "homepage": "https://github.com/oluwatobicode/argus#readme",
32
+ "keywords": [
33
+ "argus",
34
+ "error-tracking",
35
+ "monitoring",
36
+ "sdk",
37
+ "node",
38
+ "express"
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git+https://github.com/oluwatobicode/argus.git",
43
+ "directory": "packages/sdk-node"
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ }
48
+ }