@voltro/plugin-sentry 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/CHANGELOG.md +52 -0
- package/LICENSE +57 -0
- package/README.md +26 -0
- package/SECURITY.md +56 -0
- package/THIRD-PARTY-NOTICES.md +6389 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +193 -0
- package/dist/web.d.ts +73 -0
- package/dist/web.js +44 -0
- package/package.json +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Cause } from 'effect';
|
|
2
|
+
import { LogRecord } from '@voltro/logger';
|
|
3
|
+
import { Subject } from '@voltro/protocol';
|
|
4
|
+
import { VoltroPlugin } from '@voltro/protocol';
|
|
5
|
+
|
|
6
|
+
export declare interface Breadcrumb {
|
|
7
|
+
/** Unix SECONDS (Sentry breadcrumb convention). */
|
|
8
|
+
readonly timestamp: number;
|
|
9
|
+
readonly level: 'debug' | 'info' | 'warning' | 'error' | 'fatal';
|
|
10
|
+
readonly category?: string;
|
|
11
|
+
readonly message: string;
|
|
12
|
+
readonly data?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare interface BreadcrumbRing {
|
|
16
|
+
/** Record a log line under its trace. */
|
|
17
|
+
readonly add: (traceId: string, record: LogRecord) => void;
|
|
18
|
+
/** Return + REMOVE a trace's breadcrumbs (chronological). */
|
|
19
|
+
readonly take: (traceId: string) => ReadonlyArray<Breadcrumb>;
|
|
20
|
+
readonly drop: (traceId: string) => void;
|
|
21
|
+
readonly size: () => number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare interface BreadcrumbRingOptions {
|
|
25
|
+
readonly maxPerTrace?: number;
|
|
26
|
+
readonly maxTraces?: number;
|
|
27
|
+
readonly ttlMs?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare interface CaptureContext {
|
|
31
|
+
readonly tag: string;
|
|
32
|
+
readonly kind: string;
|
|
33
|
+
readonly subject: Subject;
|
|
34
|
+
readonly traceId: string;
|
|
35
|
+
readonly spanId?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export declare const captureToSentry: (sentry: SentryLike, cause: Cause.Cause<unknown>, ctx: CaptureContext, breadcrumbs: ReadonlyArray<Breadcrumb>) => void;
|
|
39
|
+
|
|
40
|
+
/** Unwrap an Effect `Cause` to the underlying error value (Error | tagged
|
|
41
|
+
* error | defect). `Cause.squash` returns the most informative throwable. */
|
|
42
|
+
export declare const causeToError: (cause: Cause.Cause<unknown>) => unknown;
|
|
43
|
+
|
|
44
|
+
export declare const makeBreadcrumbRing: (opts?: BreadcrumbRingOptions, now?: () => number) => BreadcrumbRing;
|
|
45
|
+
|
|
46
|
+
export declare const parseDsn: (dsn: string | undefined) => SentryDsn | null;
|
|
47
|
+
|
|
48
|
+
declare interface SentryDsn {
|
|
49
|
+
readonly protocol: string;
|
|
50
|
+
readonly publicKey: string;
|
|
51
|
+
readonly host: string;
|
|
52
|
+
readonly projectId: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Extra `Sentry.init` options passed through verbatim — the escape hatch for
|
|
56
|
+
* everything the first-class options don't cover: `beforeSend` /
|
|
57
|
+
* `beforeBreadcrumb` (PII/event scrubbing), `ignoreErrors`, error
|
|
58
|
+
* `sampleRate`, `maxValueLength`, … Structural (not `NodeOptions`) so
|
|
59
|
+
* `@sentry/node` stays an optional dependency.
|
|
60
|
+
*
|
|
61
|
+
* Merge contract: the bag is spread FIRST, then the plugin's own keys — so
|
|
62
|
+
* the plugin stays authoritative for everything it manages (`dsn`,
|
|
63
|
+
* `skipOpenTelemetrySetup`, `tracesSampleRate`, and `environment` /
|
|
64
|
+
* `release` / `profilesSampleRate` when set). `integrations` is the one
|
|
65
|
+
* exception: user integrations are APPENDED to the plugin's own, never
|
|
66
|
+
* replacing them. */
|
|
67
|
+
export declare interface SentryInitOverrides {
|
|
68
|
+
/** Extra Sentry integrations, appended AFTER the plugin's own. */
|
|
69
|
+
readonly integrations?: ReadonlyArray<unknown>;
|
|
70
|
+
readonly [key: string]: unknown;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export declare interface SentryLike {
|
|
74
|
+
withScope(callback: (scope: SentryScopeLike) => void): unknown;
|
|
75
|
+
captureException(exception: unknown): unknown;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export declare const sentryPlugin: (options?: SentryPluginOptions) => VoltroPlugin;
|
|
79
|
+
|
|
80
|
+
export declare interface SentryPluginOptions {
|
|
81
|
+
/** Sentry DSN. Default `SENTRY_DSN` env. Without a valid DSN the plugin is a no-op. */
|
|
82
|
+
readonly dsn?: string;
|
|
83
|
+
/** `environment` tag (Sentry env). Default `SENTRY_ENVIRONMENT` env. */
|
|
84
|
+
readonly environment?: string;
|
|
85
|
+
/** Release identifier (Sentry release health + source maps). Default `SENTRY_RELEASE` env. */
|
|
86
|
+
readonly release?: string;
|
|
87
|
+
/** Performance-trace sample rate (0..1). Default 1.0. Only relevant with `traces`. */
|
|
88
|
+
readonly tracesSampleRate?: number;
|
|
89
|
+
/** Route the framework's OTel spans to Sentry as transactions. Default false
|
|
90
|
+
* (errors + breadcrumbs only — no performance traces). */
|
|
91
|
+
readonly traces?: boolean;
|
|
92
|
+
/** Continuous CPU profiling via @sentry/profiling-node. Default false. */
|
|
93
|
+
readonly profiling?: boolean;
|
|
94
|
+
/** Profile sample rate (0..1) when `profiling`. Default 1.0. */
|
|
95
|
+
readonly profilesSampleRate?: number;
|
|
96
|
+
/** Max breadcrumbs retained per trace. Default 50. */
|
|
97
|
+
readonly maxBreadcrumbs?: number;
|
|
98
|
+
/** Disambiguates multiple instances. */
|
|
99
|
+
readonly name?: string;
|
|
100
|
+
/** Escape hatch: extra `Sentry.init` options (`beforeSend`, `ignoreErrors`,
|
|
101
|
+
* `sampleRate`, extra `integrations`, …). Plugin-managed keys win; user
|
|
102
|
+
* `integrations` are appended. See {@link SentryInitOverrides}. */
|
|
103
|
+
readonly init?: SentryInitOverrides;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
declare interface SentryScopeLike {
|
|
107
|
+
setContext(key: string, context: Record<string, unknown> | null): unknown;
|
|
108
|
+
setTag(key: string, value: string): unknown;
|
|
109
|
+
addBreadcrumb(breadcrumb: Breadcrumb): unknown;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export declare const toBreadcrumb: (r: LogRecord) => Breadcrumb;
|
|
113
|
+
|
|
114
|
+
export { }
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { Cause as e, Effect as t } from "effect";
|
|
2
|
+
import { pluginEnv as n } from "@voltro/env";
|
|
3
|
+
import { addSink as r } from "@voltro/logger";
|
|
4
|
+
import { definePlugin as i, subscribeServerErrors as a } from "@voltro/protocol";
|
|
5
|
+
//#region src/dsn.ts
|
|
6
|
+
var o = (e) => {
|
|
7
|
+
if (!e) return null;
|
|
8
|
+
try {
|
|
9
|
+
let t = new URL(e), n = t.username, r = t.pathname.split("/").filter(Boolean), i = r[r.length - 1];
|
|
10
|
+
return !n || !i ? null : {
|
|
11
|
+
protocol: t.protocol.replace(/:$/, ""),
|
|
12
|
+
publicKey: n,
|
|
13
|
+
host: t.host,
|
|
14
|
+
projectId: i
|
|
15
|
+
};
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}, s = {
|
|
20
|
+
trace: "debug",
|
|
21
|
+
debug: "debug",
|
|
22
|
+
info: "info",
|
|
23
|
+
warn: "warning",
|
|
24
|
+
error: "error",
|
|
25
|
+
fatal: "fatal"
|
|
26
|
+
}, c = (e) => ({
|
|
27
|
+
timestamp: e.ts.getTime() / 1e3,
|
|
28
|
+
level: s[e.level] ?? "info",
|
|
29
|
+
...e.scope ? { category: e.scope } : {},
|
|
30
|
+
message: e.message,
|
|
31
|
+
...Object.keys(e.fields).length > 0 ? { data: { ...e.fields } } : {}
|
|
32
|
+
}), l = (e = {}, t = () => Date.now()) => {
|
|
33
|
+
let n = e.maxPerTrace ?? 50, r = e.maxTraces ?? 1e3, i = e.ttlMs ?? 5 * 6e4, a = /* @__PURE__ */ new Map(), o = () => {
|
|
34
|
+
let e = t() - i;
|
|
35
|
+
for (let [t, n] of a) if (n.at < e) a.delete(t);
|
|
36
|
+
else break;
|
|
37
|
+
};
|
|
38
|
+
return {
|
|
39
|
+
add(e, i) {
|
|
40
|
+
o();
|
|
41
|
+
let s = a.get(e), l = s ?? {
|
|
42
|
+
at: t(),
|
|
43
|
+
crumbs: []
|
|
44
|
+
};
|
|
45
|
+
for (s && a.delete(e), l.at = t(), l.crumbs.push(c(i)), l.crumbs.length > n && l.crumbs.shift(), a.set(e, l); a.size > r;) {
|
|
46
|
+
let e = a.keys().next().value;
|
|
47
|
+
if (e === void 0) break;
|
|
48
|
+
a.delete(e);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
take(e) {
|
|
52
|
+
let t = a.get(e);
|
|
53
|
+
return a.delete(e), t ? t.crumbs : [];
|
|
54
|
+
},
|
|
55
|
+
drop(e) {
|
|
56
|
+
a.delete(e);
|
|
57
|
+
},
|
|
58
|
+
size() {
|
|
59
|
+
return a.size;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}, u = (t) => e.squash(t), d = (e, t, n = []) => {
|
|
63
|
+
e.withScope((r) => {
|
|
64
|
+
r.setTag("voltro.errorSource", t.source), t.name !== void 0 && r.setTag("voltro.name", t.name), t.traceId !== void 0 && r.setContext("trace", { trace_id: t.traceId }), t.fields !== void 0 && r.setContext("voltro", t.fields);
|
|
65
|
+
for (let e of n) r.addBreadcrumb(e);
|
|
66
|
+
e.captureException(t.error);
|
|
67
|
+
});
|
|
68
|
+
}, f = (t, n, r, i) => {
|
|
69
|
+
if (e.isInterruptedOnly(n)) return;
|
|
70
|
+
let a = u(n);
|
|
71
|
+
t.withScope((e) => {
|
|
72
|
+
e.setContext("trace", {
|
|
73
|
+
trace_id: r.traceId,
|
|
74
|
+
...r.spanId === void 0 ? {} : { span_id: r.spanId }
|
|
75
|
+
}), e.setTag("rpc.tag", r.tag), e.setTag("rpc.kind", r.kind), e.setTag("subject.type", r.subject.type), r.subject.tenantId !== void 0 && r.subject.tenantId !== null && e.setTag("tenant.id", r.subject.tenantId);
|
|
76
|
+
for (let t of i) e.addBreadcrumb(t);
|
|
77
|
+
t.captureException(a);
|
|
78
|
+
});
|
|
79
|
+
}, p = n([
|
|
80
|
+
{
|
|
81
|
+
name: "SENTRY_DSN",
|
|
82
|
+
required: !1,
|
|
83
|
+
secret: !0,
|
|
84
|
+
description: "Sentry DSN (carries a project key). Without a valid DSN the plugin is inert."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "SENTRY_ENVIRONMENT",
|
|
88
|
+
required: !1,
|
|
89
|
+
secret: !1,
|
|
90
|
+
description: "Sentry `environment` tag (e.g. production, staging)."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "SENTRY_RELEASE",
|
|
94
|
+
required: !1,
|
|
95
|
+
secret: !1,
|
|
96
|
+
description: "Release identifier for Sentry release health + source maps."
|
|
97
|
+
}
|
|
98
|
+
]), m = (e = {}) => {
|
|
99
|
+
let n = p.read("SENTRY_DSN", e.dsn), s = o(n), c = e.name ? `@voltro/plugin-sentry#${e.name}` : "@voltro/plugin-sentry";
|
|
100
|
+
if (!s) return i({
|
|
101
|
+
name: c,
|
|
102
|
+
description: "Sentry error tracking (inactive — no valid SENTRY_DSN).",
|
|
103
|
+
onActivate: (e) => t.sync(() => e.logger.warn("sentry inactive — no valid DSN (set `dsn` or SENTRY_DSN)")),
|
|
104
|
+
onDeactivate: () => t.void
|
|
105
|
+
});
|
|
106
|
+
let u = p.read("SENTRY_ENVIRONMENT", e.environment), m = p.read("SENTRY_RELEASE", e.release), h = e.tracesSampleRate ?? 1, g = l({ maxPerTrace: e.maxBreadcrumbs ?? 50 }), _, v = (e, t) => {
|
|
107
|
+
if (_) try {
|
|
108
|
+
f(_, e, t, g.take(t.traceId));
|
|
109
|
+
} catch {}
|
|
110
|
+
}, y = (e, n) => e.pipe(t.tapErrorCause((e) => t.sync(() => v(e, {
|
|
111
|
+
tag: n.tag,
|
|
112
|
+
kind: n.kind,
|
|
113
|
+
subject: n.subject,
|
|
114
|
+
traceId: n.traceId,
|
|
115
|
+
...n.spanId === void 0 ? {} : { spanId: n.spanId }
|
|
116
|
+
})))), b = [
|
|
117
|
+
"rpc:intercept:mutation",
|
|
118
|
+
"rpc:intercept:query",
|
|
119
|
+
"rpc:intercept:action",
|
|
120
|
+
`network:outbound:${s.host}`
|
|
121
|
+
], x, S;
|
|
122
|
+
return i({
|
|
123
|
+
name: c,
|
|
124
|
+
description: "Deep Sentry integration — trace-correlated errors + breadcrumbs + (opt-in) performance traces.",
|
|
125
|
+
permissions: b,
|
|
126
|
+
declaredEnv: p.declared,
|
|
127
|
+
interceptMutation: y,
|
|
128
|
+
interceptQuery: y,
|
|
129
|
+
interceptAction: y,
|
|
130
|
+
contributeObservability: async (t) => {
|
|
131
|
+
let r;
|
|
132
|
+
try {
|
|
133
|
+
r = await import("@sentry/node");
|
|
134
|
+
} catch {
|
|
135
|
+
t.logger.warn("sentry requested but @sentry/node is not installed — inactive");
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
let i = [];
|
|
139
|
+
if (e.profiling) try {
|
|
140
|
+
let { nodeProfilingIntegration: e } = await import("@sentry/profiling-node");
|
|
141
|
+
i.push(e());
|
|
142
|
+
} catch {
|
|
143
|
+
t.logger.warn("sentry profiling requested but @sentry/profiling-node is not installed");
|
|
144
|
+
}
|
|
145
|
+
let { integrations: a, ...o } = e.init ?? {};
|
|
146
|
+
if (a && i.push(...a), r.init({
|
|
147
|
+
...o,
|
|
148
|
+
dsn: n,
|
|
149
|
+
skipOpenTelemetrySetup: !0,
|
|
150
|
+
tracesSampleRate: h,
|
|
151
|
+
...u ? { environment: u } : {},
|
|
152
|
+
...m ? { release: m } : {},
|
|
153
|
+
...e.profiling ? { profilesSampleRate: e.profilesSampleRate ?? 1 } : {},
|
|
154
|
+
...i.length > 0 ? { integrations: i } : {}
|
|
155
|
+
}), _ = r, t.logger.info("sentry active", {
|
|
156
|
+
environment: u,
|
|
157
|
+
release: m,
|
|
158
|
+
traces: !!e.traces,
|
|
159
|
+
profiling: !!e.profiling
|
|
160
|
+
}), e.traces) try {
|
|
161
|
+
let { SentrySpanProcessor: e } = await import("@sentry/opentelemetry");
|
|
162
|
+
return {
|
|
163
|
+
spanProcessors: [new e()],
|
|
164
|
+
resourceAttributes: {
|
|
165
|
+
...m ? { "service.version": m } : {},
|
|
166
|
+
...u ? { "deployment.environment": u } : {}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
} catch {
|
|
170
|
+
t.logger.warn("sentry traces requested but @sentry/opentelemetry is not installed — skipping span export");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
onActivate: () => t.sync(() => {
|
|
175
|
+
x = r((e) => {
|
|
176
|
+
let t = e.fields.traceId;
|
|
177
|
+
typeof t == "string" && t.length > 0 && g.add(t, e);
|
|
178
|
+
}), S = a((e) => {
|
|
179
|
+
if (_) try {
|
|
180
|
+
d(_, e, e.traceId ? g.take(e.traceId) : []);
|
|
181
|
+
} catch {}
|
|
182
|
+
});
|
|
183
|
+
}),
|
|
184
|
+
onDeactivate: () => t.promise(async () => {
|
|
185
|
+
x?.(), x = void 0, S?.(), S = void 0;
|
|
186
|
+
try {
|
|
187
|
+
await (await import("@sentry/node")).close(2e3);
|
|
188
|
+
} catch {}
|
|
189
|
+
})
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
//#endregion
|
|
193
|
+
export { f as captureToSentry, u as causeToError, l as makeBreadcrumbRing, o as parseDsn, m as sentryPlugin, c as toBreadcrumb };
|
package/dist/web.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ClientTraceEvent } from '@voltro/client';
|
|
2
|
+
import { reportClientError } from '@voltro/client';
|
|
3
|
+
|
|
4
|
+
/** Report a client error (route render/loader failure OR a manual capture) to
|
|
5
|
+
* Sentry, tagged with its source + route + React component stack. Pure given
|
|
6
|
+
* a `SentryBrowserLike` — unit-testable with a fake. */
|
|
7
|
+
export declare const captureClientError: (sentry: SentryBrowserLike, event: {
|
|
8
|
+
readonly error: unknown;
|
|
9
|
+
readonly source: string;
|
|
10
|
+
readonly componentStack?: string;
|
|
11
|
+
readonly pathname?: string;
|
|
12
|
+
readonly context?: Record<string, unknown>;
|
|
13
|
+
}) => void;
|
|
14
|
+
|
|
15
|
+
/** Tear down the trace + error bridges (tests / hot-reload). */
|
|
16
|
+
export declare const closeSentryBrowser: () => void;
|
|
17
|
+
|
|
18
|
+
/** Initialise browser-side Sentry + wire the rpc trace bridge. Idempotent-ish:
|
|
19
|
+
* a second call re-subscribes the bridge (disposing the first). No-op on the
|
|
20
|
+
* server (SSR) and without a DSN. */
|
|
21
|
+
export declare const initSentryBrowser: (options?: SentryBrowserOptions) => Promise<void>;
|
|
22
|
+
|
|
23
|
+
/** Emit a browser-side Sentry span into the SAME trace as the server
|
|
24
|
+
* transaction the call will produce. */
|
|
25
|
+
export declare const recordClientTraceSpan: (sentry: SentryBrowserLike, event: ClientTraceEvent) => void;
|
|
26
|
+
|
|
27
|
+
export { reportClientError }
|
|
28
|
+
|
|
29
|
+
export declare interface SentryBrowserLike {
|
|
30
|
+
continueTrace<T>(context: {
|
|
31
|
+
sentryTrace: string;
|
|
32
|
+
baggage?: string;
|
|
33
|
+
}, callback: () => T): T;
|
|
34
|
+
startInactiveSpan(options: {
|
|
35
|
+
name: string;
|
|
36
|
+
op?: string;
|
|
37
|
+
attributes?: Record<string, unknown>;
|
|
38
|
+
}): SentrySpanLike;
|
|
39
|
+
withScope(callback: (scope: SentryBrowserScopeLike) => void): unknown;
|
|
40
|
+
captureException(exception: unknown): unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export declare interface SentryBrowserOptions {
|
|
44
|
+
/** Sentry DSN (public — safe in the browser bundle). Without it → no-op. */
|
|
45
|
+
readonly dsn?: string;
|
|
46
|
+
/** `environment` tag. */
|
|
47
|
+
readonly environment?: string;
|
|
48
|
+
/** Release identifier (must match the server's `release` for unified
|
|
49
|
+
* release health + source maps). */
|
|
50
|
+
readonly release?: string;
|
|
51
|
+
/** Performance-trace sample rate (0..1). Default 1.0. */
|
|
52
|
+
readonly tracesSampleRate?: number;
|
|
53
|
+
/** Instrument page loads + client navigations via `browserTracingIntegration`.
|
|
54
|
+
* Default true. */
|
|
55
|
+
readonly browserTracing?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
declare interface SentryBrowserScopeLike {
|
|
59
|
+
setTag(key: string, value: string): unknown;
|
|
60
|
+
setContext(key: string, context: Record<string, unknown> | null): unknown;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Minimal structural slice of `@sentry/react` we use — keeps this testable
|
|
64
|
+
* with a fake; the real module satisfies it structurally. */
|
|
65
|
+
declare interface SentrySpanLike {
|
|
66
|
+
end(): void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Build the `sentry-trace` header for a client trace event (sampled=1 — the
|
|
70
|
+
* framework records always-on; Sentry's client applies its own sample rate). */
|
|
71
|
+
export declare const sentryTraceHeader: (event: ClientTraceEvent) => string;
|
|
72
|
+
|
|
73
|
+
export { }
|
package/dist/web.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { reportClientError as e, subscribeClientErrors as t, subscribeClientTraces as n } from "@voltro/client";
|
|
2
|
+
//#region src/webTrace.ts
|
|
3
|
+
var r = (e, t) => {
|
|
4
|
+
e.withScope((n) => {
|
|
5
|
+
n.setTag("voltro.errorSource", t.source), t.pathname && n.setTag("route.pathname", t.pathname), t.componentStack && n.setContext("react", { componentStack: t.componentStack }), t.context && n.setContext("voltro", t.context), e.captureException(t.error);
|
|
6
|
+
});
|
|
7
|
+
}, i = (e) => `${e.traceId}-${e.spanId}-1`, a = (e, t) => {
|
|
8
|
+
e.continueTrace({ sentryTrace: i(t) }, () => {
|
|
9
|
+
e.startInactiveSpan({
|
|
10
|
+
name: `${t.source}.${t.tag}`,
|
|
11
|
+
op: `rpc.client.${t.source}`,
|
|
12
|
+
attributes: {
|
|
13
|
+
"rpc.tag": t.tag,
|
|
14
|
+
"voltro.source": t.source
|
|
15
|
+
}
|
|
16
|
+
}).end();
|
|
17
|
+
});
|
|
18
|
+
}, o, s, c = async (e = {}) => {
|
|
19
|
+
if (typeof window > "u") return;
|
|
20
|
+
let i = e.dsn;
|
|
21
|
+
if (!i) return;
|
|
22
|
+
let c = await import("@sentry/react");
|
|
23
|
+
c.init({
|
|
24
|
+
dsn: i,
|
|
25
|
+
tracesSampleRate: e.tracesSampleRate ?? 1,
|
|
26
|
+
...e.environment ? { environment: e.environment } : {},
|
|
27
|
+
...e.release ? { release: e.release } : {},
|
|
28
|
+
integrations: e.browserTracing === !1 ? [] : [c.browserTracingIntegration()]
|
|
29
|
+
});
|
|
30
|
+
let l = c;
|
|
31
|
+
o?.(), o = n((e) => {
|
|
32
|
+
try {
|
|
33
|
+
a(l, e);
|
|
34
|
+
} catch {}
|
|
35
|
+
}), s?.(), s = t((e) => {
|
|
36
|
+
try {
|
|
37
|
+
r(l, e);
|
|
38
|
+
} catch {}
|
|
39
|
+
});
|
|
40
|
+
}, l = () => {
|
|
41
|
+
o?.(), o = void 0, s?.(), s = void 0;
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
44
|
+
export { r as captureClientError, l as closeSentryBrowser, c as initSentryBrowser, a as recordClientTraceSpan, e as reportClientError, i as sentryTraceHeader };
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@voltro/plugin-sentry",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Deep Sentry integration — error tracking correlated to the distributed trace, breadcrumbs from the framework log sink, and (opt-in) performance traces routed from the framework's OTel tracer via @sentry/node in OTel-consumer mode. Errors carry the active trace_id + span_id + the request's recent log lines.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"voltro",
|
|
7
|
+
"typescript",
|
|
8
|
+
"framework"
|
|
9
|
+
],
|
|
10
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
11
|
+
"homepage": "https://voltro.dev",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"email": "support@voltro.dev"
|
|
14
|
+
},
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Voltro UG",
|
|
17
|
+
"url": "https://voltro.dev"
|
|
18
|
+
},
|
|
19
|
+
"type": "module",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./web": {
|
|
27
|
+
"types": "./dist/web.d.ts",
|
|
28
|
+
"import": "./dist/web.js",
|
|
29
|
+
"default": "./dist/web.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"main": "./dist/index.js",
|
|
33
|
+
"module": "./dist/index.js",
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"sideEffects": false,
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=24.0.0"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@voltro/client": "0.1.0",
|
|
41
|
+
"@voltro/env": "0.1.0",
|
|
42
|
+
"@voltro/logger": "0.1.0",
|
|
43
|
+
"@voltro/protocol": "0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"optionalDependencies": {
|
|
46
|
+
"@sentry/node": "^10.65.0",
|
|
47
|
+
"@sentry/opentelemetry": "^10.65.0",
|
|
48
|
+
"@sentry/profiling-node": "^10.65.0",
|
|
49
|
+
"@sentry/react": "^10.65.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"effect": "^3.21.4"
|
|
53
|
+
},
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public"
|
|
56
|
+
}
|
|
57
|
+
}
|