@reprova/sdk 0.2.0 → 0.5.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.
@@ -0,0 +1,70 @@
1
+ import { stripHeaders } from './stack.js';
2
+ const active = new Set();
3
+ const recent = [];
4
+ const RECENT_CAP = 16;
5
+ const RETENTION_MS = 5000;
6
+ const COHORT_CAP = 8; // must match capture_payload.json's maxItems
7
+ const BODY_CAP = 16 * 1024;
8
+ const FOOTPRINT_QUERY_CAP = 200;
9
+ export function registerContext(ctx) {
10
+ active.add(ctx);
11
+ }
12
+ export function completeContext(ctx) {
13
+ // 'finish' and 'close' can both fire for one response — only move once.
14
+ if (!active.delete(ctx))
15
+ return;
16
+ recent.push({ ctx, endedAt: new Date() });
17
+ const cutoff = Date.now() - RETENTION_MS;
18
+ while (recent.length > RECENT_CAP || (recent.length > 0 && recent[0].endedAt.getTime() < cutoff)) {
19
+ recent.shift();
20
+ }
21
+ }
22
+ // snapshotCohort returns every other request that overlapped the failing one:
23
+ // all currently-active contexts, plus recently-completed ones that ended at or
24
+ // after the failing request started (their writes shaped the state the failing
25
+ // request saw). offset_ms is signed: negative = started before the failing
26
+ // request. Sorted nearest-first, capped at COHORT_CAP.
27
+ export function snapshotCohort(failing) {
28
+ const failingStart = failing.capturedAt.getTime();
29
+ const out = [];
30
+ for (const ctx of active) {
31
+ if (ctx === failing)
32
+ continue;
33
+ out.push(toSnapshot(ctx, failingStart, 'in_flight'));
34
+ }
35
+ const cutoff = Date.now() - RETENTION_MS;
36
+ for (const { ctx, endedAt } of recent) {
37
+ if (ctx === failing)
38
+ continue;
39
+ if (endedAt.getTime() < cutoff)
40
+ continue;
41
+ if (endedAt.getTime() < failingStart)
42
+ continue; // ended before the failing request began — no overlap
43
+ out.push(toSnapshot(ctx, failingStart, 'completed', endedAt));
44
+ }
45
+ out.sort((a, b) => Math.abs(a.offset_ms) - Math.abs(b.offset_ms));
46
+ return out.slice(0, COHORT_CAP);
47
+ }
48
+ function toSnapshot(ctx, failingStart, state, endedAt) {
49
+ const startMs = ctx.capturedAt.getTime();
50
+ return {
51
+ trace_id: ctx.traceId,
52
+ offset_ms: startMs - failingStart,
53
+ state,
54
+ duration_ms: endedAt ? endedAt.getTime() - startMs : undefined,
55
+ request: {
56
+ method: ctx.request.method,
57
+ path: ctx.request.path,
58
+ headers: stripHeaders(ctx.request.headers),
59
+ body: ctx.request.body.slice(0, BODY_CAP),
60
+ auth_claims: ctx.request.authClaims,
61
+ },
62
+ data_footprint: ctx.footprint.length > 0 ? { queries: ctx.footprint.slice(0, FOOTPRINT_QUERY_CAP) } : undefined,
63
+ };
64
+ }
65
+ // Test hook: clears all registry state between tests.
66
+ export function resetRegistryForTests() {
67
+ active.clear();
68
+ recent.length = 0;
69
+ }
70
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAe1C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;AACzC,MAAM,MAAM,GAAqB,EAAE,CAAC;AAEpC,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,6CAA6C;AACnE,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC;AAC3B,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,MAAM,UAAU,eAAe,CAAC,GAAmB;IACjD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAmB;IACjD,wEAAwE;IACxE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;QAAE,OAAO;IAChC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;IACzC,OAAO,MAAM,CAAC,MAAM,GAAG,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;QACjG,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAmBD,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;AAC3E,uDAAuD;AACvD,MAAM,UAAU,cAAc,CAAC,OAAuB;IACpD,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;IAClD,MAAM,GAAG,GAAgC,EAAE,CAAC;IAE5C,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,GAAG,KAAK,OAAO;YAAE,SAAS;QAC9B,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;IACzC,KAAK,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,MAAM,EAAE,CAAC;QACtC,IAAI,GAAG,KAAK,OAAO;YAAE,SAAS;QAC9B,IAAI,OAAO,CAAC,OAAO,EAAE,GAAG,MAAM;YAAE,SAAS;QACzC,IAAI,OAAO,CAAC,OAAO,EAAE,GAAG,YAAY;YAAE,SAAS,CAAC,sDAAsD;QACtG,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAClE,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,UAAU,CACjB,GAAmB,EACnB,YAAoB,EACpB,KAAgC,EAChC,OAAc;IAEd,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;IACzC,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,OAAO;QACrB,SAAS,EAAE,OAAO,GAAG,YAAY;QACjC,KAAK;QACL,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS;QAC9D,OAAO,EAAE;YACP,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM;YAC1B,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI;YACtB,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;YAC1C,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;YACzC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,UAAU;SACpC;QACD,cAAc,EACZ,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;KAClG,CAAC;AACJ,CAAC;AAED,sDAAsD;AACtD,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;AACpB,CAAC"}
package/dist/sdk.d.ts CHANGED
@@ -1,30 +1,46 @@
1
- import type { Response, RequestHandler, ErrorRequestHandler } from 'express';
2
- import { type ReprovaContext } from './context.js';
1
+ import type { Express, Response, RequestHandler, ErrorRequestHandler } from 'express';
2
+ import { type ReprovaContext, type FootprintQuery } from './context.js';
3
+ import { type ReprovaNestFilter, type NestAppLike } from './nest.js';
3
4
  export interface ReprovaOptions {
4
- dsn: string;
5
+ dsn?: string;
5
6
  release: string;
6
7
  environment?: string;
7
8
  recordOutbound?: {
8
9
  allowHosts?: string[];
9
10
  denyHosts?: string[];
10
11
  };
12
+ instrumentHttp?: boolean;
13
+ processHandlers?: boolean;
11
14
  }
15
+ export declare function forwardAsyncErrors(app: object): void;
16
+ export declare function replayErrorHandler(): ErrorRequestHandler;
12
17
  export declare class Reprova {
13
18
  private readonly opts;
14
19
  private readonly transport;
15
20
  readonly release: string;
16
- readonly sdkVersion = "0.1.0";
21
+ readonly sdkVersion = "0.4.0";
22
+ readonly disabled: boolean;
17
23
  private migrationId;
18
24
  private readonly outboundOpts;
19
25
  constructor(opts: ReprovaOptions);
20
26
  static init(opts: ReprovaOptions): Reprova;
21
27
  static getInstance(): Reprova | null;
22
28
  setMigrationId(id: string): void;
29
+ instrumentPrisma(client: unknown, opts?: {
30
+ dmmf?: unknown;
31
+ readMigrationId?: boolean;
32
+ }): Promise<void>;
33
+ setupExpress(app: Express): void;
23
34
  requestHandler(): RequestHandler;
24
35
  errorHandler(): ErrorRequestHandler;
25
36
  captureError(err: Error, opts?: {
26
37
  trigger?: string;
27
38
  }): void;
39
+ nestExceptionFilter(): ReprovaNestFilter;
40
+ setupNest(app: NestAppLike, opts?: {
41
+ prisma?: unknown;
42
+ dmmf?: unknown;
43
+ }): Promise<void>;
28
44
  captureHttp5xx(err: Error | null, statusCode: number, responseBody: string): void;
29
45
  capture(trigger: string, err: Error, ctx: ReprovaContext | undefined, extra?: {
30
46
  response?: {
@@ -33,6 +49,16 @@ export declare class Reprova {
33
49
  };
34
50
  }): void;
35
51
  attachProcessHandlers(): void;
52
+ runWithContext<T>(info: {
53
+ name?: string;
54
+ method?: string;
55
+ path?: string;
56
+ headers?: Record<string, string>;
57
+ body?: string;
58
+ }, fn: () => T | Promise<T>): Promise<T>;
59
+ runJob<T>(name: string, fn: () => T | Promise<T>): Promise<T>;
60
+ private runInContext;
61
+ recordFootprint(query: FootprintQuery): void;
36
62
  private patchOutbound;
37
63
  [Symbol.asyncDispose](): Promise<void>;
38
64
  }
package/dist/sdk.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,QAAQ,EAAgB,cAAc,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAKnE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE;QACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH;AAID,qBAAa,OAAO;IAON,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,WAAW;IAC9B,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmC;gBAEnC,IAAI,EAAE,cAAc;IAWjD,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO;IAM1C,MAAM,CAAC,WAAW,IAAI,OAAO,GAAG,IAAI;IAEpC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAGhC,cAAc,IAAI,cAAc;IAqBhC,YAAY,IAAI,mBAAmB;IAWnC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAM3D,cAAc,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAajF,OAAO,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,KAAK,EACV,GAAG,EAAE,cAAc,GAAG,SAAS,EAC/B,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GACtD,IAAI;IAgCP,qBAAqB,IAAI,IAAI;IAe7B,OAAO,CAAC,aAAa;IA6Cf,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7C;AAGD,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAS9D"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"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"}