@ttt-productions/monitoring-core 0.13.4 → 0.13.6

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/adapter.d.ts CHANGED
@@ -2,7 +2,11 @@ import type { MonitoringInitOptions, MonitoringUser, ScopeLike } from "./types.j
2
2
  export interface MonitoringAdapter {
3
3
  init(options: MonitoringInitOptions): void | Promise<void>;
4
4
  captureException(error: unknown, context?: Record<string, unknown>): void;
5
- captureMessage(message: string, level?: "fatal" | "error" | "warning" | "info" | "debug"): void;
5
+ /** `context` follows the same contract as `captureException`: keys become extras,
6
+ * with `tags` (flat string map) and `level` special-cased onto the real Sentry
7
+ * fields — see `capture-context.ts`. The explicit `level` argument remains the
8
+ * message's severity; a `level` inside `context` is applied to the scope. */
9
+ captureMessage(message: string, level?: "fatal" | "error" | "warning" | "info" | "debug", context?: Record<string, unknown>): void;
6
10
  setUser(user: MonitoringUser | null): void;
7
11
  setTag(key: string, value: string): void;
8
12
  withScope?<T>(fn: (scope: ScopeLike) => T): T;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1E,cAAc,CACZ,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GACvD,IAAI,CAAC;IAER,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,CAAC;IAE9C,aAAa,CAAC,CAAC,UAAU,EAAE;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;QACzD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,GAAG,IAAI,CAAC;CACV"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEnF,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1E;;;kFAG8E;IAC9E,cAAc,CACZ,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,EACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAAC;IAER,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;IAC3C,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,CAAC;IAE9C,aAAa,CAAC,CAAC,UAAU,EAAE;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;QACzD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,GAAG,IAAI,CAAC;CACV"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"","sourcesContent":["import type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"./types.js\";\n\nexport interface MonitoringAdapter {\n init(options: MonitoringInitOptions): void | Promise<void>;\n\n captureException(error: unknown, context?: Record<string, unknown>): void;\n captureMessage(\n message: string,\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\"\n ): void;\n\n setUser(user: MonitoringUser | null): void;\n setTag(key: string, value: string): void;\n\n withScope?<T>(fn: (scope: ScopeLike) => T): T;\n \n addBreadcrumb?(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }): void;\n}"]}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"","sourcesContent":["import type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"./types.js\";\n\nexport interface MonitoringAdapter {\n init(options: MonitoringInitOptions): void | Promise<void>;\n\n captureException(error: unknown, context?: Record<string, unknown>): void;\n /** `context` follows the same contract as `captureException`: keys become extras,\n * with `tags` (flat string map) and `level` special-cased onto the real Sentry\n * fields — see `capture-context.ts`. The explicit `level` argument remains the\n * message's severity; a `level` inside `context` is applied to the scope. */\n captureMessage(\n message: string,\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\",\n context?: Record<string, unknown>\n ): void;\n\n setUser(user: MonitoringUser | null): void;\n setTag(key: string, value: string): void;\n\n withScope?<T>(fn: (scope: ScopeLike) => T): T;\n \n addBreadcrumb?(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }): void;\n}"]}
@@ -7,7 +7,7 @@ const noopScope = {
7
7
  export const NoopAdapter = {
8
8
  init: (_options) => { },
9
9
  captureException: (_error, _context) => { },
10
- captureMessage: (_message, _level) => { },
10
+ captureMessage: (_message, _level, _context) => { },
11
11
  setUser: (_user) => { },
12
12
  setTag: (_key, _value) => { },
13
13
  withScope: (fn) => fn(noopScope),
@@ -1 +1 @@
1
- {"version":3,"file":"noop.js","sourceRoot":"","sources":["../../src/adapters/noop.ts"],"names":[],"mappings":"AAGA,MAAM,SAAS,GAAc;IAC3B,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;IAChB,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;IACjB,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;IAClB,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;CACrB,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAsB;IAC5C,IAAI,EAAE,CAAC,QAA+B,EAAE,EAAE,GAAE,CAAC;IAE7C,gBAAgB,EAAE,CAAC,MAAe,EAAE,QAAkC,EAAE,EAAE,GAAE,CAAC;IAC7E,cAAc,EAAE,CAAC,QAAgB,EAAE,MAAY,EAAE,EAAE,GAAE,CAAC;IAEtD,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE,GAAE,CAAC;IAC7C,MAAM,EAAE,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,GAAE,CAAC;IAE5C,SAAS,EAAE,CAAI,EAA2B,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;IAE5D,aAAa,EAAE,CAAC,WAKf,EAAE,EAAE,GAAE,CAAC;CACT,CAAC","sourcesContent":["import type { MonitoringAdapter } from \"../adapter.js\";\nimport type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"../types.js\";\n\nconst noopScope: ScopeLike = {\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n};\n\nexport const NoopAdapter: MonitoringAdapter = {\n init: (_options: MonitoringInitOptions) => {},\n\n captureException: (_error: unknown, _context?: Record<string, unknown>) => {},\n captureMessage: (_message: string, _level?: any) => {},\n\n setUser: (_user: MonitoringUser | null) => {},\n setTag: (_key: string, _value: string) => {},\n\n withScope: <T>(fn: (scope: ScopeLike) => T) => fn(noopScope),\n \n addBreadcrumb: (_breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }) => {},\n};"]}
1
+ {"version":3,"file":"noop.js","sourceRoot":"","sources":["../../src/adapters/noop.ts"],"names":[],"mappings":"AAGA,MAAM,SAAS,GAAc;IAC3B,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;IAChB,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;IACjB,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;IAClB,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;CACrB,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAsB;IAC5C,IAAI,EAAE,CAAC,QAA+B,EAAE,EAAE,GAAE,CAAC;IAE7C,gBAAgB,EAAE,CAAC,MAAe,EAAE,QAAkC,EAAE,EAAE,GAAE,CAAC;IAC7E,cAAc,EAAE,CAAC,QAAgB,EAAE,MAAY,EAAE,QAAkC,EAAE,EAAE,GAAE,CAAC;IAE1F,OAAO,EAAE,CAAC,KAA4B,EAAE,EAAE,GAAE,CAAC;IAC7C,MAAM,EAAE,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,GAAE,CAAC;IAE5C,SAAS,EAAE,CAAI,EAA2B,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC;IAE5D,aAAa,EAAE,CAAC,WAKf,EAAE,EAAE,GAAE,CAAC;CACT,CAAC","sourcesContent":["import type { MonitoringAdapter } from \"../adapter.js\";\nimport type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"../types.js\";\n\nconst noopScope: ScopeLike = {\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n};\n\nexport const NoopAdapter: MonitoringAdapter = {\n init: (_options: MonitoringInitOptions) => {},\n\n captureException: (_error: unknown, _context?: Record<string, unknown>) => {},\n captureMessage: (_message: string, _level?: any, _context?: Record<string, unknown>) => {},\n\n setUser: (_user: MonitoringUser | null) => {},\n setTag: (_key: string, _value: string) => {},\n\n withScope: <T>(fn: (scope: ScopeLike) => T) => fn(noopScope),\n \n addBreadcrumb: (_breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }) => {},\n};"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sentry-node.d.ts","sourceRoot":"","sources":["../../src/adapters/sentry-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AA2BvD,eAAO,MAAM,iBAAiB,EAAE,iBA4H/B,CAAC"}
1
+ {"version":3,"file":"sentry-node.d.ts","sourceRoot":"","sources":["../../src/adapters/sentry-node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AA2BvD,eAAO,MAAM,iBAAiB,EAAE,iBA6I/B,CAAC"}
@@ -49,13 +49,27 @@ export const SentryNodeAdapter = {
49
49
  S.captureException(error);
50
50
  })();
51
51
  },
52
- captureMessage(message, level) {
52
+ captureMessage(message, level, context) {
53
53
  if (sentryNodeInstance) {
54
+ if (context) {
55
+ sentryNodeInstance.withScope((scope) => {
56
+ applyCaptureContext(scope, context);
57
+ sentryNodeInstance.captureMessage(message, level);
58
+ });
59
+ return;
60
+ }
54
61
  sentryNodeInstance.captureMessage(message, level);
55
62
  return;
56
63
  }
57
64
  void (async () => {
58
65
  const S = await getSentryNode();
66
+ if (context) {
67
+ S.withScope((scope) => {
68
+ applyCaptureContext(scope, context);
69
+ S.captureMessage(message, level);
70
+ });
71
+ return;
72
+ }
59
73
  S.captureMessage(message, level);
60
74
  })();
61
75
  },
@@ -1 +1 @@
1
- {"version":3,"file":"sentry-node.js","sourceRoot":"","sources":["../../src/adapters/sentry-node.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MonitoringAdapter } from \"../adapter.js\";\nimport type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"../types.js\";\nimport { applyCaptureContext } from \"../capture-context.js\";\n\ntype SentryNodeLike = {\n init: (opts: any) => void;\n captureException: (e: unknown, hint?: any) => void;\n captureMessage: (m: string, level?: any) => void;\n setUser: (u: any) => void;\n setTag: (k: string, v: string) => void;\n withScope: (fn: (scope: any) => void) => void;\n addBreadcrumb: (breadcrumb: any) => void;\n};\n\nlet sentryNodePromise: Promise<SentryNodeLike> | null = null;\nlet sentryNodeInstance: SentryNodeLike | null = null;\n\nfunction getSentryNode(): Promise<SentryNodeLike> {\n if (!sentryNodePromise) {\n sentryNodePromise = import(\"@sentry/node\").then((m) => {\n sentryNodeInstance = m as any;\n return sentryNodeInstance!;\n });\n }\n return sentryNodePromise;\n}\n\nexport const SentryNodeAdapter: MonitoringAdapter = {\n async init(options: MonitoringInitOptions) {\n const enabled = options.enabled ?? true;\n if (!enabled || !options.dsn) return;\n\n const S = await getSentryNode();\n S.init({\n dsn: options.dsn,\n environment: options.environment,\n enabled: true,\n release: options.release,\n ...(options.tracesSampleRate !== undefined ? { tracesSampleRate: options.tracesSampleRate } : {}),\n ...(options.integrations !== undefined ? { integrations: options.integrations } : {}),\n });\n },\n\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (sentryNodeInstance) {\n if (context) {\n sentryNodeInstance.withScope((scope) => {\n applyCaptureContext(scope, context);\n sentryNodeInstance!.captureException(error);\n });\n return;\n }\n sentryNodeInstance.captureException(error);\n return;\n }\n\n void (async () => {\n const S = await getSentryNode();\n\n if (context) {\n S.withScope((scope) => {\n applyCaptureContext(scope, context);\n S.captureException(error);\n });\n return;\n }\n\n S.captureException(error);\n })();\n },\n\n captureMessage(message: string, level?: any) {\n if (sentryNodeInstance) {\n sentryNodeInstance.captureMessage(message, level);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.captureMessage(message, level);\n })();\n },\n\n setUser(user: MonitoringUser | null) {\n if (sentryNodeInstance) {\n sentryNodeInstance.setUser(user as any);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.setUser(user as any);\n })();\n },\n\n setTag(key: string, value: string) {\n if (sentryNodeInstance) {\n sentryNodeInstance.setTag(key, value);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.setTag(key, value);\n })();\n },\n\n // NOTE: withScope calls `fn` exactly once. When Sentry is already loaded\n // (the expected steady state — `init()` awaits the dynamic import, and\n // callers must await `initMonitoring()` before serving traffic), it runs\n // synchronously through the real Sentry scope. Only during the narrow\n // pre-load race window (a call that races the very first `getSentryNode()`\n // resolution) does it fall back to a synchronous no-op-scope call plus an\n // async replay against the real scope — mirroring the browser adapter's\n // same accepted tradeoff for that same race window.\n withScope<T>(fn: (scope: ScopeLike) => T): T {\n if (sentryNodeInstance) {\n let result: T;\n sentryNodeInstance.withScope((scope) => {\n result = fn(scope as any);\n });\n return result!;\n }\n\n const minimalScope: ScopeLike = {\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n };\n\n void (async () => {\n const S = await getSentryNode();\n S.withScope((scope) => fn(scope as any));\n })();\n\n return fn(minimalScope);\n },\n\n addBreadcrumb(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }) {\n if (sentryNodeInstance) {\n sentryNodeInstance.addBreadcrumb(breadcrumb);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.addBreadcrumb(breadcrumb);\n })();\n },\n};"]}
1
+ {"version":3,"file":"sentry-node.js","sourceRoot":"","sources":["../../src/adapters/sentry-node.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MonitoringAdapter } from \"../adapter.js\";\nimport type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"../types.js\";\nimport { applyCaptureContext } from \"../capture-context.js\";\n\ntype SentryNodeLike = {\n init: (opts: any) => void;\n captureException: (e: unknown, hint?: any) => void;\n captureMessage: (m: string, level?: any) => void;\n setUser: (u: any) => void;\n setTag: (k: string, v: string) => void;\n withScope: (fn: (scope: any) => void) => void;\n addBreadcrumb: (breadcrumb: any) => void;\n};\n\nlet sentryNodePromise: Promise<SentryNodeLike> | null = null;\nlet sentryNodeInstance: SentryNodeLike | null = null;\n\nfunction getSentryNode(): Promise<SentryNodeLike> {\n if (!sentryNodePromise) {\n sentryNodePromise = import(\"@sentry/node\").then((m) => {\n sentryNodeInstance = m as any;\n return sentryNodeInstance!;\n });\n }\n return sentryNodePromise;\n}\n\nexport const SentryNodeAdapter: MonitoringAdapter = {\n async init(options: MonitoringInitOptions) {\n const enabled = options.enabled ?? true;\n if (!enabled || !options.dsn) return;\n\n const S = await getSentryNode();\n S.init({\n dsn: options.dsn,\n environment: options.environment,\n enabled: true,\n release: options.release,\n ...(options.tracesSampleRate !== undefined ? { tracesSampleRate: options.tracesSampleRate } : {}),\n ...(options.integrations !== undefined ? { integrations: options.integrations } : {}),\n });\n },\n\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (sentryNodeInstance) {\n if (context) {\n sentryNodeInstance.withScope((scope) => {\n applyCaptureContext(scope, context);\n sentryNodeInstance!.captureException(error);\n });\n return;\n }\n sentryNodeInstance.captureException(error);\n return;\n }\n\n void (async () => {\n const S = await getSentryNode();\n\n if (context) {\n S.withScope((scope) => {\n applyCaptureContext(scope, context);\n S.captureException(error);\n });\n return;\n }\n\n S.captureException(error);\n })();\n },\n\n captureMessage(message: string, level?: any, context?: Record<string, unknown>) {\n if (sentryNodeInstance) {\n if (context) {\n sentryNodeInstance.withScope((scope) => {\n applyCaptureContext(scope, context);\n sentryNodeInstance!.captureMessage(message, level);\n });\n return;\n }\n sentryNodeInstance.captureMessage(message, level);\n return;\n }\n\n void (async () => {\n const S = await getSentryNode();\n\n if (context) {\n S.withScope((scope) => {\n applyCaptureContext(scope, context);\n S.captureMessage(message, level);\n });\n return;\n }\n\n S.captureMessage(message, level);\n })();\n },\n\n setUser(user: MonitoringUser | null) {\n if (sentryNodeInstance) {\n sentryNodeInstance.setUser(user as any);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.setUser(user as any);\n })();\n },\n\n setTag(key: string, value: string) {\n if (sentryNodeInstance) {\n sentryNodeInstance.setTag(key, value);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.setTag(key, value);\n })();\n },\n\n // NOTE: withScope calls `fn` exactly once. When Sentry is already loaded\n // (the expected steady state — `init()` awaits the dynamic import, and\n // callers must await `initMonitoring()` before serving traffic), it runs\n // synchronously through the real Sentry scope. Only during the narrow\n // pre-load race window (a call that races the very first `getSentryNode()`\n // resolution) does it fall back to a synchronous no-op-scope call plus an\n // async replay against the real scope — mirroring the browser adapter's\n // same accepted tradeoff for that same race window.\n withScope<T>(fn: (scope: ScopeLike) => T): T {\n if (sentryNodeInstance) {\n let result: T;\n sentryNodeInstance.withScope((scope) => {\n result = fn(scope as any);\n });\n return result!;\n }\n\n const minimalScope: ScopeLike = {\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n };\n\n void (async () => {\n const S = await getSentryNode();\n S.withScope((scope) => fn(scope as any));\n })();\n\n return fn(minimalScope);\n },\n\n addBreadcrumb(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }) {\n if (sentryNodeInstance) {\n sentryNodeInstance.addBreadcrumb(breadcrumb);\n return;\n }\n void (async () => {\n const S = await getSentryNode();\n S.addBreadcrumb(breadcrumb);\n })();\n },\n};"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/adapters/sentry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AA2BvD,eAAO,MAAM,aAAa,EAAE,iBA0H3B,CAAC"}
1
+ {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/adapters/sentry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AA2BvD,eAAO,MAAM,aAAa,EAAE,iBA2I3B,CAAC"}
@@ -49,13 +49,27 @@ export const SentryAdapter = {
49
49
  S.captureException(error);
50
50
  })();
51
51
  },
52
- captureMessage(message, level) {
52
+ captureMessage(message, level, context) {
53
53
  if (sentryInstance) {
54
+ if (context && sentryInstance.withScope) {
55
+ sentryInstance.withScope((scope) => {
56
+ applyCaptureContext(scope, context);
57
+ sentryInstance.captureMessage(message, level);
58
+ });
59
+ return;
60
+ }
54
61
  sentryInstance.captureMessage(message, level);
55
62
  return;
56
63
  }
57
64
  void (async () => {
58
65
  const S = await getSentry();
66
+ if (context && S.withScope) {
67
+ S.withScope((scope) => {
68
+ applyCaptureContext(scope, context);
69
+ S.captureMessage(message, level);
70
+ });
71
+ return;
72
+ }
59
73
  S.captureMessage(message, level);
60
74
  })();
61
75
  },
@@ -1 +1 @@
1
- {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/adapters/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MonitoringAdapter } from \"../adapter.js\";\nimport type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"../types.js\";\nimport { applyCaptureContext } from \"../capture-context.js\";\n\ntype SentryLike = {\n init: (opts: any) => void;\n captureException: (e: unknown) => void;\n captureMessage: (m: string, level?: any) => void;\n setUser: (u: any) => void;\n setTag: (k: string, v: string) => void;\n withScope?: (fn: (scope: any) => void) => void;\n addBreadcrumb?: (breadcrumb: any) => void;\n};\n\nlet sentryPromise: Promise<SentryLike> | null = null;\nlet sentryInstance: SentryLike | null = null;\n\nfunction getSentry(): Promise<SentryLike> {\n if (!sentryPromise) {\n sentryPromise = import(\"@sentry/nextjs\").then((m) => {\n sentryInstance = m as any;\n return sentryInstance!;\n });\n }\n return sentryPromise;\n}\n\nexport const SentryAdapter: MonitoringAdapter = {\n async init(options: MonitoringInitOptions) {\n const enabled = options.enabled ?? true;\n if (!enabled || !options.dsn) return;\n\n const S = await getSentry();\n S.init({\n dsn: options.dsn,\n environment: options.environment,\n enabled: true,\n release: options.release,\n ...(options.tracesSampleRate !== undefined ? { tracesSampleRate: options.tracesSampleRate } : {}),\n ...(options.integrations !== undefined ? { integrations: options.integrations } : {}),\n });\n },\n\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (sentryInstance) {\n if (context && sentryInstance.withScope) {\n sentryInstance.withScope((scope) => {\n applyCaptureContext(scope, context);\n sentryInstance!.captureException(error);\n });\n return;\n }\n sentryInstance.captureException(error);\n return;\n }\n\n void (async () => {\n const S = await getSentry();\n\n if (context && S.withScope) {\n S.withScope((scope) => {\n applyCaptureContext(scope, context);\n S.captureException(error);\n });\n return;\n }\n\n S.captureException(error);\n })();\n },\n\n captureMessage(message: string, level?: any) {\n if (sentryInstance) {\n sentryInstance.captureMessage(message, level);\n return;\n }\n void (async () => {\n const S = await getSentry();\n S.captureMessage(message, level);\n })();\n },\n\n setUser(user: MonitoringUser | null) {\n if (sentryInstance) {\n sentryInstance.setUser(user as any);\n return;\n }\n void (async () => {\n const S = await getSentry();\n S.setUser(user as any);\n })();\n },\n\n setTag(key: string, value: string) {\n if (sentryInstance) {\n sentryInstance.setTag(key, value);\n return;\n }\n void (async () => {\n const S = await getSentry();\n S.setTag(key, value);\n })();\n },\n\n withScope<T>(fn: (scope: ScopeLike) => T): T {\n if (sentryInstance && sentryInstance.withScope) {\n let result: T;\n sentryInstance.withScope((scope) => {\n result = fn(scope as any);\n });\n return result!;\n }\n\n // Sentry not loaded yet — run with no-op scope, then replay async\n const minimalScope: ScopeLike = {\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n };\n\n void (async () => {\n const S = await getSentry();\n if (!S.withScope) return;\n S.withScope((scope) => fn(scope as any));\n })();\n\n return fn(minimalScope);\n },\n\n addBreadcrumb(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }) {\n if (sentryInstance) {\n if (sentryInstance.addBreadcrumb) {\n sentryInstance.addBreadcrumb(breadcrumb);\n }\n return;\n }\n void (async () => {\n const S = await getSentry();\n if (S.addBreadcrumb) {\n S.addBreadcrumb(breadcrumb);\n }\n })();\n },\n};"]}
1
+ {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/adapters/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MonitoringAdapter } from \"../adapter.js\";\nimport type { MonitoringInitOptions, MonitoringUser, ScopeLike } from \"../types.js\";\nimport { applyCaptureContext } from \"../capture-context.js\";\n\ntype SentryLike = {\n init: (opts: any) => void;\n captureException: (e: unknown) => void;\n captureMessage: (m: string, level?: any) => void;\n setUser: (u: any) => void;\n setTag: (k: string, v: string) => void;\n withScope?: (fn: (scope: any) => void) => void;\n addBreadcrumb?: (breadcrumb: any) => void;\n};\n\nlet sentryPromise: Promise<SentryLike> | null = null;\nlet sentryInstance: SentryLike | null = null;\n\nfunction getSentry(): Promise<SentryLike> {\n if (!sentryPromise) {\n sentryPromise = import(\"@sentry/nextjs\").then((m) => {\n sentryInstance = m as any;\n return sentryInstance!;\n });\n }\n return sentryPromise;\n}\n\nexport const SentryAdapter: MonitoringAdapter = {\n async init(options: MonitoringInitOptions) {\n const enabled = options.enabled ?? true;\n if (!enabled || !options.dsn) return;\n\n const S = await getSentry();\n S.init({\n dsn: options.dsn,\n environment: options.environment,\n enabled: true,\n release: options.release,\n ...(options.tracesSampleRate !== undefined ? { tracesSampleRate: options.tracesSampleRate } : {}),\n ...(options.integrations !== undefined ? { integrations: options.integrations } : {}),\n });\n },\n\n captureException(error: unknown, context?: Record<string, unknown>) {\n if (sentryInstance) {\n if (context && sentryInstance.withScope) {\n sentryInstance.withScope((scope) => {\n applyCaptureContext(scope, context);\n sentryInstance!.captureException(error);\n });\n return;\n }\n sentryInstance.captureException(error);\n return;\n }\n\n void (async () => {\n const S = await getSentry();\n\n if (context && S.withScope) {\n S.withScope((scope) => {\n applyCaptureContext(scope, context);\n S.captureException(error);\n });\n return;\n }\n\n S.captureException(error);\n })();\n },\n\n captureMessage(message: string, level?: any, context?: Record<string, unknown>) {\n if (sentryInstance) {\n if (context && sentryInstance.withScope) {\n sentryInstance.withScope((scope) => {\n applyCaptureContext(scope, context);\n sentryInstance!.captureMessage(message, level);\n });\n return;\n }\n sentryInstance.captureMessage(message, level);\n return;\n }\n\n void (async () => {\n const S = await getSentry();\n\n if (context && S.withScope) {\n S.withScope((scope) => {\n applyCaptureContext(scope, context);\n S.captureMessage(message, level);\n });\n return;\n }\n\n S.captureMessage(message, level);\n })();\n },\n\n setUser(user: MonitoringUser | null) {\n if (sentryInstance) {\n sentryInstance.setUser(user as any);\n return;\n }\n void (async () => {\n const S = await getSentry();\n S.setUser(user as any);\n })();\n },\n\n setTag(key: string, value: string) {\n if (sentryInstance) {\n sentryInstance.setTag(key, value);\n return;\n }\n void (async () => {\n const S = await getSentry();\n S.setTag(key, value);\n })();\n },\n\n withScope<T>(fn: (scope: ScopeLike) => T): T {\n if (sentryInstance && sentryInstance.withScope) {\n let result: T;\n sentryInstance.withScope((scope) => {\n result = fn(scope as any);\n });\n return result!;\n }\n\n // Sentry not loaded yet — run with no-op scope, then replay async\n const minimalScope: ScopeLike = {\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n };\n\n void (async () => {\n const S = await getSentry();\n if (!S.withScope) return;\n S.withScope((scope) => fn(scope as any));\n })();\n\n return fn(minimalScope);\n },\n\n addBreadcrumb(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n }) {\n if (sentryInstance) {\n if (sentryInstance.addBreadcrumb) {\n sentryInstance.addBreadcrumb(breadcrumb);\n }\n return;\n }\n void (async () => {\n const S = await getSentry();\n if (S.addBreadcrumb) {\n S.addBreadcrumb(breadcrumb);\n }\n })();\n },\n};"]}
package/dist/api.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { MonitoringUser } from "./types.js";
2
2
  export declare function captureException(error: unknown, context?: Record<string, unknown>): void;
3
- export declare function captureMessage(message: string, level?: "fatal" | "error" | "warning" | "info" | "debug"): void;
3
+ export declare function captureMessage(message: string, level?: "fatal" | "error" | "warning" | "info" | "debug", context?: Record<string, unknown>): void;
4
4
  export declare function setUser(user: MonitoringUser | null): void;
5
5
  export declare function setTag(key: string, value: string): void;
6
6
  export declare function withScope(fn: (scope: any) => any): any;
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QAEjF;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,QAGzD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,QAElD;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAEhD;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,OAQhD;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,QAKA"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAGjD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QAEjF;AAED,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,EACxD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QAGlC;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,QAElD;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAEhD;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,GAAG,OAQhD;AAED,wBAAgB,aAAa,CAAC,UAAU,EAAE;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,QAKA"}
package/dist/api.js CHANGED
@@ -2,8 +2,8 @@ import { getMonitoringAdapter } from "./init.js";
2
2
  export function captureException(error, context) {
3
3
  return getMonitoringAdapter().captureException(error, context);
4
4
  }
5
- export function captureMessage(message, level) {
6
- return getMonitoringAdapter().captureMessage(message, level);
5
+ export function captureMessage(message, level, context) {
6
+ return getMonitoringAdapter().captureMessage(message, level, context);
7
7
  }
8
8
  export function setUser(user) {
9
9
  return getMonitoringAdapter().setUser(user);
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,OAAiC;IAChF,OAAO,oBAAoB,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,KAAwD;IAExD,OAAO,oBAAoB,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAA2B;IACjD,OAAO,oBAAoB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAW,EAAE,KAAa;IAC/C,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,EAAuB;IAC/C,MAAM,CAAC,GAAG,oBAAoB,EAAE,CAAC;IACjC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;QAChB,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;QACjB,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;QAClB,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAK7B;IACC,MAAM,CAAC,GAAG,oBAAoB,EAAE,CAAC;IACjC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;QACpB,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC","sourcesContent":["import type { MonitoringUser } from \"./types.js\";\nimport { getMonitoringAdapter } from \"./init.js\";\n\nexport function captureException(error: unknown, context?: Record<string, unknown>) {\n return getMonitoringAdapter().captureException(error, context);\n}\n\nexport function captureMessage(\n message: string,\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\"\n) {\n return getMonitoringAdapter().captureMessage(message, level);\n}\n\nexport function setUser(user: MonitoringUser | null) {\n return getMonitoringAdapter().setUser(user);\n}\n\nexport function setTag(key: string, value: string) {\n return getMonitoringAdapter().setTag(key, value);\n}\n\nexport function withScope(fn: (scope: any) => any) {\n const a = getMonitoringAdapter();\n return a.withScope ? a.withScope(fn as any) : fn({\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n });\n}\n\nexport function addBreadcrumb(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n}) {\n const a = getMonitoringAdapter();\n if (a.addBreadcrumb) {\n a.addBreadcrumb(breadcrumb);\n }\n}"]}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,UAAU,gBAAgB,CAAC,KAAc,EAAE,OAAiC;IAChF,OAAO,oBAAoB,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,KAAwD,EACxD,OAAiC;IAEjC,OAAO,oBAAoB,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAA2B;IACjD,OAAO,oBAAoB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAW,EAAE,KAAa;IAC/C,OAAO,oBAAoB,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,EAAuB;IAC/C,MAAM,CAAC,GAAG,oBAAoB,EAAE,CAAC;IACjC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;QAChB,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC;QACjB,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC;QAClB,UAAU,EAAE,GAAG,EAAE,GAAE,CAAC;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,UAK7B;IACC,MAAM,CAAC,GAAG,oBAAoB,EAAE,CAAC;IACjC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;QACpB,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC","sourcesContent":["import type { MonitoringUser } from \"./types.js\";\nimport { getMonitoringAdapter } from \"./init.js\";\n\nexport function captureException(error: unknown, context?: Record<string, unknown>) {\n return getMonitoringAdapter().captureException(error, context);\n}\n\nexport function captureMessage(\n message: string,\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\",\n context?: Record<string, unknown>\n) {\n return getMonitoringAdapter().captureMessage(message, level, context);\n}\n\nexport function setUser(user: MonitoringUser | null) {\n return getMonitoringAdapter().setUser(user);\n}\n\nexport function setTag(key: string, value: string) {\n return getMonitoringAdapter().setTag(key, value);\n}\n\nexport function withScope(fn: (scope: any) => any) {\n const a = getMonitoringAdapter();\n return a.withScope ? a.withScope(fn as any) : fn({\n setTag: () => {},\n setUser: () => {},\n setExtra: () => {},\n setContext: () => {},\n });\n}\n\nexport function addBreadcrumb(breadcrumb: {\n category?: string;\n message?: string;\n level?: \"fatal\" | \"error\" | \"warning\" | \"info\" | \"debug\";\n data?: Record<string, unknown>;\n}) {\n const a = getMonitoringAdapter();\n if (a.addBreadcrumb) {\n a.addBreadcrumb(breadcrumb);\n }\n}"]}
@@ -8,7 +8,8 @@
8
8
  *
9
9
  * This package is GENERIC — it ships only obvious, domain-neutral defaults
10
10
  * (full IPv4/IPv6 addresses, bearer/authorization tokens, generic credential
11
- * assignments). Product-specific patterns (evidence-bucket URL prefixes,
11
+ * assignments, URL-borne credential parameters such as `oobCode` / `id_token`).
12
+ * Product-specific patterns (evidence-bucket URL prefixes,
12
13
  * detector-hash shapes, NCMEC credential markers) are INJECTED by the consuming
13
14
  * app via {@link createTelemetryScrubber}'s `patterns` option. No app-data-package
14
15
  * import, no app-specific literals.
@@ -1 +1 @@
1
- {"version":3,"file":"scrubber.d.ts","sourceRoot":"","sources":["../src/scrubber.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/C,MAAM,MAAM,mBAAmB,GAAG;IAChC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,EAY9C,CAAC;AAwBF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CASrF;AAwCD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,EACnD,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,wBAA6B,GACrC,CAAC,CAmCH;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,eAAe,GAAG,IAAI,CAAC;AAEhG;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,wBAA6B,GAAG,cAAc,CAK9F"}
1
+ {"version":3,"file":"scrubber.d.ts","sourceRoot":"","sources":["../src/scrubber.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/C,MAAM,MAAM,mBAAmB,GAAG;IAChC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,EAAE,MAAM,EAyC9C,CAAC;AAwBF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CASrF;AAwCD;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,eAAe,EACnD,KAAK,EAAE,CAAC,EACR,OAAO,GAAE,wBAA6B,GACrC,CAAC,CAmCH;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,eAAe,GAAG,IAAI,CAAC;AAEhG;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,wBAA6B,GAAG,cAAc,CAK9F"}
package/dist/scrubber.js CHANGED
@@ -8,7 +8,8 @@
8
8
  *
9
9
  * This package is GENERIC — it ships only obvious, domain-neutral defaults
10
10
  * (full IPv4/IPv6 addresses, bearer/authorization tokens, generic credential
11
- * assignments). Product-specific patterns (evidence-bucket URL prefixes,
11
+ * assignments, URL-borne credential parameters such as `oobCode` / `id_token`).
12
+ * Product-specific patterns (evidence-bucket URL prefixes,
12
13
  * detector-hash shapes, NCMEC credential markers) are INJECTED by the consuming
13
14
  * app via {@link createTelemetryScrubber}'s `patterns` option. No app-data-package
14
15
  * import, no app-specific literals.
@@ -29,6 +30,35 @@ export const DEFAULT_FORBIDDEN_PATTERNS = [
29
30
  /\b(?:[0-9a-fA-F]{1,4}:){1,7}:(?:[0-9a-fA-F]{1,4}:?){0,6}(?:[0-9a-fA-F]{1,4})?\b|::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\b/g,
30
31
  // Authorization / bearer token: "Bearer xyz", "Authorization: Basic xyz".
31
32
  /\b(?:Bearer|Basic)\s+[A-Za-z0-9._~+/-]{8,}={0,2}/gi,
33
+ // URL-borne credential PARAMETERS — bearer credentials that ride in a query
34
+ // string, where the browser SDK records the landing URL into `request.url`,
35
+ // navigation breadcrumbs, and session replay:
36
+ // - `oobCode` — the Firebase email-action one-time code
37
+ // (?mode=resetPassword&oobCode=…). Whoever reads it can complete the
38
+ // password reset, i.e. take the account over.
39
+ // - ANY `<prefix>token` spelling — `id_token`, `idToken`, `authToken`,
40
+ // `session_token`, `csrf_token`, … The generic assignment below cannot
41
+ // reach these: its `\btoken\b` needs a word boundary that both camelCase
42
+ // (`d` before `Token`) and snake_case (`_` before `token`) deny, which is
43
+ // why it had to enumerate `access[_-]?token` and `refresh[_-]?token` by
44
+ // hand. `[a-z]*[_-]?token\b` covers the whole class instead — the trailing
45
+ // `\b` is what keeps `valid_tokens`, `tokenizer`, and `tokenize` out.
46
+ // (Measured: no backtracking cost — the literal `token` anchor makes a
47
+ // non-matching alpha run fail fast, sub-ms on 40k chars.)
48
+ //
49
+ // This entry runs BEFORE the generic assignment ON PURPOSE, and its value
50
+ // class is the generic one MINUS `&`: these live in a query string, so
51
+ // stopping at the next parameter keeps `mode=`, `state=`, `lang=`, and
52
+ // `continueUrl=` readable instead of swallowing the rest of the URL. Order is
53
+ // load-bearing for any spelling the greedy pattern CAN reach — `id-token`,
54
+ // `X-Auth-Token` (`-` IS a word boundary) — which it would otherwise consume
55
+ // to end-of-string. The class stays negated rather than shaped to
56
+ // base64url/JWT so an unexpected value over-redacts instead of leaking a tail.
57
+ //
58
+ // This does NOT subsume the generic pattern's own token branches, so those
59
+ // stay: a value carrying an early `&` (`token=ab&cdef`) has fewer than 4
60
+ // non-`&` chars here and falls through to the greedy entry by design.
61
+ /\b(?:oob[_-]?code|[a-z]*[_-]?token)\b\s*[:=]\s*["']?[^\s"',}{&]{4,}/gi,
32
62
  // Generic credential assignment: password=..., api_key: "...", secret=...,
33
63
  // token=..., apiKey=..., access_token=... (value up to whitespace/quote).
34
64
  /\b(?:password|passwd|pwd|secret|api[_-]?key|apikey|access[_-]?token|refresh[_-]?token|token|client[_-]?secret|authorization)\b\s*[:=]\s*["']?[^\s"',}{]{4,}/gi,
@@ -1 +1 @@
1
- {"version":3,"file":"scrubber.js","sourceRoot":"","sources":["../src/scrubber.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Telemetry scrubber — generic Sentry-event redaction.\n *\n * A defense-in-depth `beforeSend`-style hook that walks an ENTIRE Sentry event\n * (message, exception values + stacktrace frame vars, breadcrumbs, extra,\n * contexts, tags, request data, user) and replaces any substring matching a\n * forbidden pattern with a fixed placeholder.\n *\n * This package is GENERIC — it ships only obvious, domain-neutral defaults\n * (full IPv4/IPv6 addresses, bearer/authorization tokens, generic credential\n * assignments). Product-specific patterns (evidence-bucket URL prefixes,\n * detector-hash shapes, NCMEC credential markers) are INJECTED by the consuming\n * app via {@link createTelemetryScrubber}'s `patterns` option. No app-data-package\n * import, no app-specific literals.\n */\n\n/** The fixed replacement written over any matched forbidden substring. */\nexport const REDACTION_PLACEHOLDER = \"[REDACTED]\";\n\n/**\n * A forbidden pattern. Either a `RegExp` (matched globally against every string\n * in the event) or a literal `string` (every occurrence replaced). Strings are\n * treated as literals, not regex source, so callers do not have to escape them.\n */\nexport type ForbiddenPattern = RegExp | string;\n\nexport type RedactStringOptions = {\n /** Patterns to strip. Defaults to {@link DEFAULT_FORBIDDEN_PATTERNS}. */\n patterns?: ForbiddenPattern[];\n /** Replacement text. Defaults to {@link REDACTION_PLACEHOLDER}. */\n placeholder?: string;\n};\n\n/**\n * Generic, domain-neutral built-in patterns. These are intentionally\n * conservative (specific → low collateral on ordinary errors) but catch the\n * obvious secrets that must never reach telemetry regardless of app.\n */\nexport const DEFAULT_FORBIDDEN_PATTERNS: RegExp[] = [\n // Full IPv4 address (four dotted octets, each 0–255).\n /\\b(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\b/g,\n // Full (uncompressed) IPv6 address — eight hextet groups.\n /\\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\b/g,\n // Compressed IPv6 with a \"::\" run (e.g. 2001:db8::1, ::1, fe80::abcd).\n /\\b(?:[0-9a-fA-F]{1,4}:){1,7}:(?:[0-9a-fA-F]{1,4}:?){0,6}(?:[0-9a-fA-F]{1,4})?\\b|::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\\b/g,\n // Authorization / bearer token: \"Bearer xyz\", \"Authorization: Basic xyz\".\n /\\b(?:Bearer|Basic)\\s+[A-Za-z0-9._~+/-]{8,}={0,2}/gi,\n // Generic credential assignment: password=..., api_key: \"...\", secret=...,\n // token=..., apiKey=..., access_token=... (value up to whitespace/quote).\n /\\b(?:password|passwd|pwd|secret|api[_-]?key|apikey|access[_-]?token|refresh[_-]?token|token|client[_-]?secret|authorization)\\b\\s*[:=]\\s*[\"']?[^\\s\"',}{]{4,}/gi,\n];\n\ntype CompiledPattern = { regex: RegExp; isLiteral: boolean; literal?: string };\n\nfunction escapeRegExp(input: string): string {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction compilePatterns(patterns: ForbiddenPattern[]): CompiledPattern[] {\n return patterns.map((p) => {\n if (typeof p === \"string\") {\n return {\n regex: new RegExp(escapeRegExp(p), \"g\"),\n isLiteral: true,\n literal: p,\n };\n }\n // Ensure the flag set is global so `String.replace` strips every hit; clone\n // so we never mutate a caller-owned RegExp's lastIndex across calls.\n const flags = p.flags.includes(\"g\") ? p.flags : p.flags + \"g\";\n return { regex: new RegExp(p.source, flags), isLiteral: false };\n });\n}\n\n/**\n * Redact every forbidden-pattern hit inside a single string. Pure and safe on\n * any input. Empty when nothing matches → returns the original reference.\n */\nexport function redactString(value: string, options: RedactStringOptions = {}): string {\n const placeholder = options.placeholder ?? REDACTION_PLACEHOLDER;\n const compiled = compilePatterns(options.patterns ?? DEFAULT_FORBIDDEN_PATTERNS);\n let out = value;\n for (const { regex } of compiled) {\n regex.lastIndex = 0;\n out = out.replace(regex, placeholder);\n }\n return out;\n}\n\ntype DeepRedactOptions = {\n patterns: ForbiddenPattern[];\n placeholder: string;\n};\n\n/**\n * Recursively redact every string reachable inside an arbitrary value (objects,\n * arrays, nested combinations). Non-string primitives pass through untouched.\n * Object keys are NOT rewritten (a forbidden value hiding in a key is\n * pathological and rewriting keys would corrupt the event shape); only values\n * are scrubbed. Guards against cycles.\n */\nfunction deepRedact(value: unknown, options: DeepRedactOptions, seen: WeakSet<object>): unknown {\n if (typeof value === \"string\") {\n return redactString(value, options);\n }\n if (value === null || typeof value !== \"object\") {\n return value;\n }\n if (seen.has(value as object)) {\n return value;\n }\n seen.add(value as object);\n\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n value[i] = deepRedact(value[i], options, seen);\n }\n return value;\n }\n\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n record[key] = deepRedact(record[key], options, seen);\n }\n return record;\n}\n\n/**\n * Minimal structural shape of a Sentry event we walk. Deliberately loose — we\n * do not depend on `@sentry/*` types (this package's Sentry deps are optional\n * peers, and the scrubber is provider-agnostic). Unknown fields are left alone\n * except that we deep-redact the free-form containers below.\n */\nexport type ScrubbableEvent = {\n message?: unknown;\n exception?: { values?: Array<Record<string, unknown>> } | unknown;\n breadcrumbs?: unknown;\n extra?: unknown;\n contexts?: unknown;\n tags?: unknown;\n request?: unknown;\n user?: unknown;\n [key: string]: unknown;\n};\n\nexport type TelemetryScrubberOptions = {\n /**\n * App-injected forbidden patterns (evidence-bucket URL prefixes, detector-hash\n * shapes, NCMEC credential markers, …). Merged AFTER the generic defaults\n * unless {@link includeDefaults} is false.\n */\n patterns?: ForbiddenPattern[];\n /** Include {@link DEFAULT_FORBIDDEN_PATTERNS}. Defaults to true. */\n includeDefaults?: boolean;\n /** Replacement text. Defaults to {@link REDACTION_PLACEHOLDER}. */\n placeholder?: string;\n};\n\n/**\n * Redact a whole Sentry event in place and return it. Exported so the backend\n * `withScope` / manual-capture path can benefit even where a `beforeSend`\n * pipeline is not wired.\n */\nexport function redactEvent<T extends ScrubbableEvent>(\n event: T,\n options: TelemetryScrubberOptions = {}\n): T {\n if (event === null || typeof event !== \"object\") return event;\n\n const includeDefaults = options.includeDefaults ?? true;\n const patterns: ForbiddenPattern[] = [\n ...(includeDefaults ? DEFAULT_FORBIDDEN_PATTERNS : []),\n ...(options.patterns ?? []),\n ];\n const deepOptions: DeepRedactOptions = {\n patterns,\n placeholder: options.placeholder ?? REDACTION_PLACEHOLDER,\n };\n const seen = new WeakSet<object>();\n\n // Top-level message (string or {message,params} structured form).\n if (event.message !== undefined) {\n event.message = deepRedact(event.message, deepOptions, seen);\n }\n\n // Exception values: type/value strings plus stacktrace frame vars/filenames.\n const exception = event.exception as { values?: Array<Record<string, unknown>> } | undefined;\n if (exception && Array.isArray(exception.values)) {\n for (const val of exception.values) {\n deepRedact(val, deepOptions, seen);\n }\n }\n\n // Free-form containers — walked wholesale.\n for (const container of [\"breadcrumbs\", \"extra\", \"contexts\", \"tags\", \"request\", \"user\"] as const) {\n if (event[container] !== undefined) {\n event[container] = deepRedact(event[container], deepOptions, seen);\n }\n }\n\n return event;\n}\n\n/**\n * A Sentry `beforeSend`-style hook: `(event, hint?) => event | null`. Drop-in\n * for `Sentry.init({ beforeSend })` in both the browser and Node SDKs.\n */\nexport type BeforeSendHook = (event: ScrubbableEvent, hint?: unknown) => ScrubbableEvent | null;\n\n/**\n * Build a `beforeSend` hook that scrubs every outgoing event. The app supplies\n * its product-specific `patterns`; generic defaults are included unless disabled.\n *\n * @example\n * Sentry.init({\n * dsn,\n * beforeSend: createTelemetryScrubber({\n * patterns: [\n * 'https://storage.googleapis.com/example-ncii-evidence/',\n * /\\bncmec-[a-z0-9]{16,}\\b/gi,\n * /\\b[a-f0-9]{64}\\b/g, // detector hash shape\n * ],\n * }),\n * });\n */\nexport function createTelemetryScrubber(options: TelemetryScrubberOptions = {}): BeforeSendHook {\n return (event, _hint) => {\n if (event === null || typeof event !== \"object\") return event;\n return redactEvent(event, options);\n };\n}\n"]}
1
+ {"version":3,"file":"scrubber.js","sourceRoot":"","sources":["../src/scrubber.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Telemetry scrubber — generic Sentry-event redaction.\n *\n * A defense-in-depth `beforeSend`-style hook that walks an ENTIRE Sentry event\n * (message, exception values + stacktrace frame vars, breadcrumbs, extra,\n * contexts, tags, request data, user) and replaces any substring matching a\n * forbidden pattern with a fixed placeholder.\n *\n * This package is GENERIC — it ships only obvious, domain-neutral defaults\n * (full IPv4/IPv6 addresses, bearer/authorization tokens, generic credential\n * assignments, URL-borne credential parameters such as `oobCode` / `id_token`).\n * Product-specific patterns (evidence-bucket URL prefixes,\n * detector-hash shapes, NCMEC credential markers) are INJECTED by the consuming\n * app via {@link createTelemetryScrubber}'s `patterns` option. No app-data-package\n * import, no app-specific literals.\n */\n\n/** The fixed replacement written over any matched forbidden substring. */\nexport const REDACTION_PLACEHOLDER = \"[REDACTED]\";\n\n/**\n * A forbidden pattern. Either a `RegExp` (matched globally against every string\n * in the event) or a literal `string` (every occurrence replaced). Strings are\n * treated as literals, not regex source, so callers do not have to escape them.\n */\nexport type ForbiddenPattern = RegExp | string;\n\nexport type RedactStringOptions = {\n /** Patterns to strip. Defaults to {@link DEFAULT_FORBIDDEN_PATTERNS}. */\n patterns?: ForbiddenPattern[];\n /** Replacement text. Defaults to {@link REDACTION_PLACEHOLDER}. */\n placeholder?: string;\n};\n\n/**\n * Generic, domain-neutral built-in patterns. These are intentionally\n * conservative (specific → low collateral on ordinary errors) but catch the\n * obvious secrets that must never reach telemetry regardless of app.\n */\nexport const DEFAULT_FORBIDDEN_PATTERNS: RegExp[] = [\n // Full IPv4 address (four dotted octets, each 0–255).\n /\\b(?:(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)\\b/g,\n // Full (uncompressed) IPv6 address — eight hextet groups.\n /\\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\\b/g,\n // Compressed IPv6 with a \"::\" run (e.g. 2001:db8::1, ::1, fe80::abcd).\n /\\b(?:[0-9a-fA-F]{1,4}:){1,7}:(?:[0-9a-fA-F]{1,4}:?){0,6}(?:[0-9a-fA-F]{1,4})?\\b|::(?:[0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}\\b/g,\n // Authorization / bearer token: \"Bearer xyz\", \"Authorization: Basic xyz\".\n /\\b(?:Bearer|Basic)\\s+[A-Za-z0-9._~+/-]{8,}={0,2}/gi,\n // URL-borne credential PARAMETERS — bearer credentials that ride in a query\n // string, where the browser SDK records the landing URL into `request.url`,\n // navigation breadcrumbs, and session replay:\n // - `oobCode` — the Firebase email-action one-time code\n // (?mode=resetPassword&oobCode=…). Whoever reads it can complete the\n // password reset, i.e. take the account over.\n // - ANY `<prefix>token` spelling — `id_token`, `idToken`, `authToken`,\n // `session_token`, `csrf_token`, … The generic assignment below cannot\n // reach these: its `\\btoken\\b` needs a word boundary that both camelCase\n // (`d` before `Token`) and snake_case (`_` before `token`) deny, which is\n // why it had to enumerate `access[_-]?token` and `refresh[_-]?token` by\n // hand. `[a-z]*[_-]?token\\b` covers the whole class instead — the trailing\n // `\\b` is what keeps `valid_tokens`, `tokenizer`, and `tokenize` out.\n // (Measured: no backtracking cost — the literal `token` anchor makes a\n // non-matching alpha run fail fast, sub-ms on 40k chars.)\n //\n // This entry runs BEFORE the generic assignment ON PURPOSE, and its value\n // class is the generic one MINUS `&`: these live in a query string, so\n // stopping at the next parameter keeps `mode=`, `state=`, `lang=`, and\n // `continueUrl=` readable instead of swallowing the rest of the URL. Order is\n // load-bearing for any spelling the greedy pattern CAN reach — `id-token`,\n // `X-Auth-Token` (`-` IS a word boundary) — which it would otherwise consume\n // to end-of-string. The class stays negated rather than shaped to\n // base64url/JWT so an unexpected value over-redacts instead of leaking a tail.\n //\n // This does NOT subsume the generic pattern's own token branches, so those\n // stay: a value carrying an early `&` (`token=ab&cdef`) has fewer than 4\n // non-`&` chars here and falls through to the greedy entry by design.\n /\\b(?:oob[_-]?code|[a-z]*[_-]?token)\\b\\s*[:=]\\s*[\"']?[^\\s\"',}{&]{4,}/gi,\n // Generic credential assignment: password=..., api_key: \"...\", secret=...,\n // token=..., apiKey=..., access_token=... (value up to whitespace/quote).\n /\\b(?:password|passwd|pwd|secret|api[_-]?key|apikey|access[_-]?token|refresh[_-]?token|token|client[_-]?secret|authorization)\\b\\s*[:=]\\s*[\"']?[^\\s\"',}{]{4,}/gi,\n];\n\ntype CompiledPattern = { regex: RegExp; isLiteral: boolean; literal?: string };\n\nfunction escapeRegExp(input: string): string {\n return input.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction compilePatterns(patterns: ForbiddenPattern[]): CompiledPattern[] {\n return patterns.map((p) => {\n if (typeof p === \"string\") {\n return {\n regex: new RegExp(escapeRegExp(p), \"g\"),\n isLiteral: true,\n literal: p,\n };\n }\n // Ensure the flag set is global so `String.replace` strips every hit; clone\n // so we never mutate a caller-owned RegExp's lastIndex across calls.\n const flags = p.flags.includes(\"g\") ? p.flags : p.flags + \"g\";\n return { regex: new RegExp(p.source, flags), isLiteral: false };\n });\n}\n\n/**\n * Redact every forbidden-pattern hit inside a single string. Pure and safe on\n * any input. Empty when nothing matches → returns the original reference.\n */\nexport function redactString(value: string, options: RedactStringOptions = {}): string {\n const placeholder = options.placeholder ?? REDACTION_PLACEHOLDER;\n const compiled = compilePatterns(options.patterns ?? DEFAULT_FORBIDDEN_PATTERNS);\n let out = value;\n for (const { regex } of compiled) {\n regex.lastIndex = 0;\n out = out.replace(regex, placeholder);\n }\n return out;\n}\n\ntype DeepRedactOptions = {\n patterns: ForbiddenPattern[];\n placeholder: string;\n};\n\n/**\n * Recursively redact every string reachable inside an arbitrary value (objects,\n * arrays, nested combinations). Non-string primitives pass through untouched.\n * Object keys are NOT rewritten (a forbidden value hiding in a key is\n * pathological and rewriting keys would corrupt the event shape); only values\n * are scrubbed. Guards against cycles.\n */\nfunction deepRedact(value: unknown, options: DeepRedactOptions, seen: WeakSet<object>): unknown {\n if (typeof value === \"string\") {\n return redactString(value, options);\n }\n if (value === null || typeof value !== \"object\") {\n return value;\n }\n if (seen.has(value as object)) {\n return value;\n }\n seen.add(value as object);\n\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n value[i] = deepRedact(value[i], options, seen);\n }\n return value;\n }\n\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n record[key] = deepRedact(record[key], options, seen);\n }\n return record;\n}\n\n/**\n * Minimal structural shape of a Sentry event we walk. Deliberately loose — we\n * do not depend on `@sentry/*` types (this package's Sentry deps are optional\n * peers, and the scrubber is provider-agnostic). Unknown fields are left alone\n * except that we deep-redact the free-form containers below.\n */\nexport type ScrubbableEvent = {\n message?: unknown;\n exception?: { values?: Array<Record<string, unknown>> } | unknown;\n breadcrumbs?: unknown;\n extra?: unknown;\n contexts?: unknown;\n tags?: unknown;\n request?: unknown;\n user?: unknown;\n [key: string]: unknown;\n};\n\nexport type TelemetryScrubberOptions = {\n /**\n * App-injected forbidden patterns (evidence-bucket URL prefixes, detector-hash\n * shapes, NCMEC credential markers, …). Merged AFTER the generic defaults\n * unless {@link includeDefaults} is false.\n */\n patterns?: ForbiddenPattern[];\n /** Include {@link DEFAULT_FORBIDDEN_PATTERNS}. Defaults to true. */\n includeDefaults?: boolean;\n /** Replacement text. Defaults to {@link REDACTION_PLACEHOLDER}. */\n placeholder?: string;\n};\n\n/**\n * Redact a whole Sentry event in place and return it. Exported so the backend\n * `withScope` / manual-capture path can benefit even where a `beforeSend`\n * pipeline is not wired.\n */\nexport function redactEvent<T extends ScrubbableEvent>(\n event: T,\n options: TelemetryScrubberOptions = {}\n): T {\n if (event === null || typeof event !== \"object\") return event;\n\n const includeDefaults = options.includeDefaults ?? true;\n const patterns: ForbiddenPattern[] = [\n ...(includeDefaults ? DEFAULT_FORBIDDEN_PATTERNS : []),\n ...(options.patterns ?? []),\n ];\n const deepOptions: DeepRedactOptions = {\n patterns,\n placeholder: options.placeholder ?? REDACTION_PLACEHOLDER,\n };\n const seen = new WeakSet<object>();\n\n // Top-level message (string or {message,params} structured form).\n if (event.message !== undefined) {\n event.message = deepRedact(event.message, deepOptions, seen);\n }\n\n // Exception values: type/value strings plus stacktrace frame vars/filenames.\n const exception = event.exception as { values?: Array<Record<string, unknown>> } | undefined;\n if (exception && Array.isArray(exception.values)) {\n for (const val of exception.values) {\n deepRedact(val, deepOptions, seen);\n }\n }\n\n // Free-form containers — walked wholesale.\n for (const container of [\"breadcrumbs\", \"extra\", \"contexts\", \"tags\", \"request\", \"user\"] as const) {\n if (event[container] !== undefined) {\n event[container] = deepRedact(event[container], deepOptions, seen);\n }\n }\n\n return event;\n}\n\n/**\n * A Sentry `beforeSend`-style hook: `(event, hint?) => event | null`. Drop-in\n * for `Sentry.init({ beforeSend })` in both the browser and Node SDKs.\n */\nexport type BeforeSendHook = (event: ScrubbableEvent, hint?: unknown) => ScrubbableEvent | null;\n\n/**\n * Build a `beforeSend` hook that scrubs every outgoing event. The app supplies\n * its product-specific `patterns`; generic defaults are included unless disabled.\n *\n * @example\n * Sentry.init({\n * dsn,\n * beforeSend: createTelemetryScrubber({\n * patterns: [\n * 'https://storage.googleapis.com/example-ncii-evidence/',\n * /\\bncmec-[a-z0-9]{16,}\\b/gi,\n * /\\b[a-f0-9]{64}\\b/g, // detector hash shape\n * ],\n * }),\n * });\n */\nexport function createTelemetryScrubber(options: TelemetryScrubberOptions = {}): BeforeSendHook {\n return (event, _hint) => {\n if (event === null || typeof event !== \"object\") return event;\n return redactEvent(event, options);\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttt-productions/monitoring-core",
3
- "version": "0.13.4",
3
+ "version": "0.13.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/ttt-productions/ttt-packages.git",