@voltro/plugin-sentry 0.60.0 → 0.61.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 CHANGED
@@ -39,6 +39,31 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.61.0] — 2026-08-31
43
+
44
+ ### ⚠ BREAKING
45
+
46
+ - **@voltro/client, @voltro/web, @voltro/cli** — `RpcError.kind` now distinguishes transport, handler, client, and unknown failures; manually emitted events must add the field, while `useConnectionStatus` now degrades only for transport failures and clears on the next rpc success.
47
+
48
+ **`voltro update` carries you across this** — codemod `0.61.0/01_rpc_errors_have_kinds`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.61.0).
49
+ - **@voltro/plugin-sentry, @voltro/cli** — Browser RPC spans now join the active page/navigation transaction and link to the Effect/server trace instead of creating one root transaction per call; `tracesSampleRate`, `browserTracing`, and the new `rpcSpans` switch control the resulting browser trace volume.
50
+
51
+ **`voltro update` carries you across this** — codemod `0.61.0/02_sentry_rpc_spans_join_page`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.61.0).
52
+
53
+ ### Fixed
54
+
55
+ - **@voltro/cli** — **Six SSR failure sites report to Sentry, not three.**
56
+
57
+ 0.60.0 gave the web server its own Sentry and wired the three loud sites: the SSR shell throw, the SPA layout shell throw, and the general render error (which covers a loader throw). The docs said "shell throw, loader throw, PPR/SWR refresh" — and an enumeration in a claim is read as exhaustive.
58
+
59
+ The other three were `warn`-level and reported to nobody: a failed PPR hole pass, a failed background SWR refresh, and a `not-found.tsx` that throws while rendering. They are quieter because the request still serves something — stale HTML, an unfilled hole, a plain 404 — which says something about the REQUEST and nothing about who else could find out. The answer to that is nobody: none of them reaches a browser boundary, so the pod's stdout was the only record.
60
+
61
+ They carry their own `voltro.stage` (`not-found-render`, `ppr-holes`, `swr-refresh`), so a quota-conscious project can drop them by stage without losing the three that fail the request.
62
+
63
+ `webSentry.test.ts` now fails if a render-path `log.error`/`log.warn` gains no reporter beside it — the property, rather than the six call sites.
64
+
65
+ ---
66
+
42
67
  ## [0.60.0] — 2026-08-31
43
68
 
44
69
  ### ⚠ BREAKING
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # @voltro/plugin-sentry
4
4
 
5
- **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
+ **Deep Sentry integration — trace-correlated error tracking, breadcrumbs from the framework log sink, page-owned browser performance spans, and server traces routed from the framework's OTel tracer via @sentry/node in OTel-consumer mode.**
6
6
 
7
7
  [📖 Documentation](https://docs.voltro.dev/docs/plugins/sentry) · [voltro.dev](https://voltro.dev) · [Voltro Cloud](https://voltro.cloud)
8
8
 
package/dist/index.d.ts CHANGED
@@ -92,17 +92,9 @@ export declare interface SentryPluginOptions {
92
92
  /**
93
93
  * Route the framework's OTel spans to Sentry as transactions. Default **true**.
94
94
  *
95
- * It was `false`, and that made the pair's default the worst of the three
96
- * available. The BROWSER half defaults `tracesSampleRate: 1.0` with
97
- * `browserTracing` on, so page loads, navigations and every rpc call already
98
- * become spans without anybody asking. With the server side off, each of those
99
- * spans is emitted and paid for, carries a `traceId` the api also logged, and
100
- * belongs to a trace with no server half — a browser hop hanging off nothing.
101
- * Both-off would at least be coherent; both-on is what the two halves were
102
- * built for.
103
- *
104
- * `false` turns them off and still leaves errors + breadcrumbs, which is the
105
- * whole of the plugin for an app with no trace budget.
95
+ * The browser half records page/navigation transactions and page-owned rpc
96
+ * child spans; those children link to the Effect/server trace. `false` turns
97
+ * server transactions off while leaving errors + breadcrumbs intact.
106
98
  */
107
99
  readonly traces?: boolean;
108
100
  /**
package/dist/index.js CHANGED
@@ -120,7 +120,7 @@ var l = {
120
120
  ], T, E;
121
121
  return s({
122
122
  name: u,
123
- description: "Deep Sentry integration — trace-correlated errors + breadcrumbs + (opt-in) performance traces.",
123
+ description: "Deep Sentry integration — trace-correlated errors, breadcrumbs, and controlled performance traces.",
124
124
  permissions: w,
125
125
  declaredEnv: g.declared,
126
126
  interceptMutation: C,
package/dist/web.d.ts CHANGED
@@ -38,21 +38,27 @@ export declare const isDeclaredRpcFailure: (event: {
38
38
  error: unknown;
39
39
  }) => boolean;
40
40
 
41
- /** Emit a browser-side Sentry span into the SAME trace as the server
42
- * transaction the call will produce. */
41
+ /** Add an rpc marker to the active page/navigation transaction and link it to
42
+ * the Effect trace continued by the server. With no active browser parent,
43
+ * `onlyIfParent` deliberately produces no recorded root transaction. */
43
44
  export declare const recordClientTraceSpan: (sentry: SentryBrowserLike, event: ClientTraceEvent) => void;
44
45
 
45
46
  export { reportClientError }
46
47
 
47
48
  export declare interface SentryBrowserLike {
48
- continueTrace<T>(context: {
49
- sentryTrace: string;
50
- baggage?: string;
51
- }, callback: () => T): T;
52
49
  startInactiveSpan(options: {
53
50
  name: string;
54
51
  op?: string;
52
+ onlyIfParent?: boolean;
55
53
  attributes?: Record<string, unknown>;
54
+ links?: ReadonlyArray<{
55
+ context: {
56
+ traceId: string;
57
+ spanId: string;
58
+ traceFlags: number;
59
+ };
60
+ attributes?: Record<string, string | number | boolean>;
61
+ }>;
56
62
  }): SentrySpanLike;
57
63
  withScope(callback: (scope: SentryBrowserScopeLike) => void): unknown;
58
64
  captureException(exception: unknown): unknown;
@@ -71,6 +77,12 @@ export declare interface SentryBrowserOptions {
71
77
  /** Instrument page loads + client navigations via `browserTracingIntegration`.
72
78
  * Default true. */
73
79
  readonly browserTracing?: boolean;
80
+ /** Record rpc markers under the active page/navigation transaction and link
81
+ * them to their server traces. Defaults to `browserTracing`; set `false` to
82
+ * disable only this bridge while keeping browser error reporting. Set
83
+ * `true` with `browserTracing:false` only when the app creates its own
84
+ * active Sentry transactions. */
85
+ readonly rpcSpans?: boolean;
74
86
  /**
75
87
  * Whether a DECLARED failure that came back from an rpc call reaches Sentry.
76
88
  * **Default `false`**, matching `sentryPlugin({ captureFailures })`.
@@ -97,8 +109,4 @@ declare interface SentrySpanLike {
97
109
  end(): void;
98
110
  }
99
111
 
100
- /** Build the `sentry-trace` header for a client trace event (sampled=1 — the
101
- * framework records always-on; Sentry's client applies its own sample rate). */
102
- export declare const sentryTraceHeader: (event: ClientTraceEvent) => string;
103
-
104
112
  export { }
package/dist/web.js CHANGED
@@ -5,54 +5,66 @@ var i = (e, t) => {
5
5
  e.withScope((n) => {
6
6
  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);
7
7
  });
8
- }, a = (e) => `${e.traceId}-${e.spanId}-1`, o = (e, t) => {
9
- e.continueTrace({ sentryTrace: a(t) }, () => {
10
- e.startInactiveSpan({
11
- name: `${t.source}.${t.tag}`,
12
- op: `rpc.client.${t.source}`,
13
- attributes: {
14
- "rpc.tag": t.tag,
15
- "voltro.source": t.source
16
- }
17
- }).end();
18
- });
19
- }, s = (e) => e.source.startsWith("rpc.") && typeof e.error?._tag == "string", c = (e) => {
8
+ }, a = (e, t) => {
9
+ e.startInactiveSpan({
10
+ name: `${t.source}.${t.tag}`,
11
+ op: `rpc.client.${t.source}`,
12
+ onlyIfParent: !0,
13
+ attributes: {
14
+ "rpc.tag": t.tag,
15
+ "voltro.source": t.source
16
+ },
17
+ links: [{
18
+ context: {
19
+ traceId: t.traceId,
20
+ spanId: t.spanId,
21
+ traceFlags: 1
22
+ },
23
+ attributes: { "voltro.link.type": "rpc.server-trace" }
24
+ }]
25
+ }).end();
26
+ }, o = (e) => e.source.startsWith("rpc.") && typeof e.error?._tag == "string", s = (e) => {
20
27
  let t = r()[e];
21
28
  return typeof t == "string" && t !== "" ? t : void 0;
22
- }, l, u, d = async (e = {}) => {
29
+ }, c, l, u = async (e = {}) => {
23
30
  if (typeof window > "u") return;
24
- let r = e.dsn ?? c("VOLTRO_PUBLIC_SENTRY_DSN");
31
+ let r = e.dsn ?? s("VOLTRO_PUBLIC_SENTRY_DSN");
25
32
  if (!r) return;
26
- let a = e.environment ?? c("VOLTRO_PUBLIC_SENTRY_ENVIRONMENT"), d = e.release ?? c("VOLTRO_PUBLIC_SENTRY_RELEASE"), p = await import("@sentry/react");
27
- p.init({
33
+ let u = e.environment ?? s("VOLTRO_PUBLIC_SENTRY_ENVIRONMENT"), f = e.release ?? s("VOLTRO_PUBLIC_SENTRY_RELEASE"), p = e.tracesSampleRate ?? 1, m = e.browserTracing !== !1, h = e.rpcSpans ?? m, g = await import("@sentry/react");
34
+ g.init({
28
35
  dsn: r,
29
- tracesSampleRate: e.tracesSampleRate ?? 1,
30
- ...a ? { environment: a } : {},
31
- ...d ? { release: d } : {},
32
- integrations: e.browserTracing === !1 ? [] : [p.browserTracingIntegration()]
36
+ tracesSampleRate: p,
37
+ ...u ? { environment: u } : {},
38
+ ...f ? { release: f } : {},
39
+ integrations: m ? [g.browserTracingIntegration()] : []
33
40
  });
34
- let m = p;
35
- l?.(), l = n((e) => {
41
+ let _ = g;
42
+ c?.(), c = void 0, h && (c = n((e) => {
36
43
  try {
37
- o(m, e);
44
+ a(_, e);
38
45
  } catch {}
39
- }), u?.();
40
- let h = e.captureFailures ?? !1;
41
- u = t((e) => {
46
+ })), l?.();
47
+ let v = e.captureFailures ?? !1;
48
+ l = t((e) => {
42
49
  try {
43
- if (s(e) && !f(e.error, h)) return;
44
- i(m, e);
50
+ if (o(e) && !d(e.error, v)) return;
51
+ i(_, e);
45
52
  } catch {}
53
+ }), console.info("[@voltro/plugin-sentry] browser active", {
54
+ tracesSampleRate: p,
55
+ browserTracing: m,
56
+ rpcSpans: h,
57
+ rpcSpanMode: h ? "page-child-with-server-link" : "off"
46
58
  });
47
- }, f = (e, t) => {
59
+ }, d = (e, t) => {
48
60
  if (typeof t != "function") return t;
49
61
  try {
50
62
  return t(e);
51
63
  } catch {
52
64
  return !0;
53
65
  }
54
- }, p = () => {
55
- l?.(), l = void 0, u?.(), u = void 0;
66
+ }, f = () => {
67
+ c?.(), c = void 0, l?.(), l = void 0;
56
68
  };
57
69
  //#endregion
58
- export { i as captureClientError, p as closeSentryBrowser, d as initSentryBrowser, s as isDeclaredRpcFailure, o as recordClientTraceSpan, e as reportClientError, a as sentryTraceHeader };
70
+ export { i as captureClientError, f as closeSentryBrowser, u as initSentryBrowser, o as isDeclaredRpcFailure, a as recordClientTraceSpan, e as reportClientError };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@voltro/plugin-sentry",
3
- "version": "0.60.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.",
3
+ "version": "0.61.0",
4
+ "description": "Deep Sentry integration — error tracking correlated to distributed traces, breadcrumbs from the framework log sink, controlled browser performance spans, and server traces routed from the framework's OTel tracer via @sentry/node in OTel-consumer mode.",
5
5
  "keywords": [
6
6
  "voltro",
7
7
  "typescript",
@@ -43,10 +43,10 @@
43
43
  "node": ">=24.0.0"
44
44
  },
45
45
  "dependencies": {
46
- "@voltro/client": "0.60.0",
47
- "@voltro/env": "0.60.0",
48
- "@voltro/logger": "0.60.0",
49
- "@voltro/protocol": "0.60.0"
46
+ "@voltro/client": "0.61.0",
47
+ "@voltro/env": "0.61.0",
48
+ "@voltro/logger": "0.61.0",
49
+ "@voltro/protocol": "0.61.0"
50
50
  },
51
51
  "optionalDependencies": {
52
52
  "@sentry/node": "^10.70.0",