@sentry/elysia 10.53.0 → 10.54.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/build/cjs/sdk.js CHANGED
@@ -4,53 +4,27 @@ const os = require('node:os');
4
4
  const bun = require('@sentry/bun');
5
5
  const core = require('@sentry/core');
6
6
 
7
- /** Get the default integrations for the Elysia SDK. */
8
7
  function getDefaultIntegrations(_options) {
9
- // Filter out bunServerIntegration
10
- // Elysia already produces an HTTP server span, so we don't need Bun's competing root span.
11
- return bun.getDefaultIntegrations(_options).filter(i => i.name !== bun.bunServerIntegration().name);
8
+ return bun.getDefaultIntegrations(_options).filter((i) => i.name !== bun.bunServerIntegration().name);
12
9
  }
13
-
14
- /**
15
- * Get the runtime name and version.
16
- */
17
10
  function getRuntime() {
18
- if (typeof Bun !== 'undefined') {
19
- return { name: 'bun', version: Bun.version };
11
+ if (typeof Bun !== "undefined") {
12
+ return { name: "bun", version: Bun.version };
20
13
  }
21
-
22
- return { name: 'node', version: process.version };
14
+ return { name: "node", version: process.version };
23
15
  }
24
-
25
- /**
26
- * Initializes the Sentry Elysia SDK.
27
- *
28
- * @example
29
- * ```javascript
30
- * import * as Sentry from '@sentry/elysia';
31
- *
32
- * Sentry.init({
33
- * dsn: '__DSN__',
34
- * tracesSampleRate: 1.0,
35
- * });
36
- * ```
37
- */
38
16
  function init(userOptions = {}) {
39
17
  const options = {
40
18
  ...userOptions,
41
- platform: 'javascript',
19
+ platform: "javascript",
42
20
  runtime: getRuntime(),
43
- serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),
21
+ serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname()
44
22
  };
45
-
46
- core.applySdkMetadata(userOptions, 'elysia', ['elysia', options.runtime.name]);
47
-
23
+ core.applySdkMetadata(userOptions, "elysia", ["elysia", options.runtime.name]);
48
24
  options.transport = options.transport || bun.makeFetchTransport;
49
-
50
- if (options.defaultIntegrations === undefined) {
25
+ if (options.defaultIntegrations === void 0) {
51
26
  options.defaultIntegrations = getDefaultIntegrations(options);
52
27
  }
53
-
54
28
  return bun.init(options);
55
29
  }
56
30
 
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import * as os from 'node:os';\nimport {\n bunServerIntegration,\n getDefaultIntegrations as getBunDefaultIntegrations,\n makeFetchTransport,\n} from '@sentry/bun';\nimport type { Integration, Options } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport { init as initNode, type NodeClient } from '@sentry/bun';\nimport type { ElysiaOptions } from './types';\n\n/** Get the default integrations for the Elysia SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n // Filter out bunServerIntegration\n // Elysia already produces an HTTP server span, so we don't need Bun's competing root span.\n return getBunDefaultIntegrations(_options).filter(i => i.name !== bunServerIntegration().name);\n}\n\n/**\n * Get the runtime name and version.\n */\nfunction getRuntime(): { name: string; version: string } {\n if (typeof Bun !== 'undefined') {\n return { name: 'bun', version: Bun.version };\n }\n\n return { name: 'node', version: process.version };\n}\n\n/**\n * Initializes the Sentry Elysia SDK.\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n *\n * Sentry.init({\n * dsn: '__DSN__',\n * tracesSampleRate: 1.0,\n * });\n * ```\n */\nexport function init(userOptions: ElysiaOptions = {}): NodeClient | undefined {\n const options = {\n ...userOptions,\n platform: 'javascript',\n runtime: getRuntime(),\n serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),\n };\n\n applySdkMetadata(userOptions, 'elysia', ['elysia', options.runtime.name]);\n\n options.transport = options.transport || makeFetchTransport;\n\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n return initNode(options);\n}\n"],"names":["getBunDefaultIntegrations","bunServerIntegration","applySdkMetadata","makeFetchTransport","initNode"],"mappings":";;;;;;AAWA;AACO,SAAS,sBAAsB,CAAC,QAAQ,EAA0B;AACzE;AACA;AACA,EAAE,OAAOA,0BAAyB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA,IAAK,CAAC,CAAC,SAASC,wBAAoB,EAAE,CAAC,IAAI,CAAC;AAChG;;AAEA;AACA;AACA;AACA,SAAS,UAAU,GAAsC;AACzD,EAAE,IAAI,OAAO,GAAA,KAAQ,WAAW,EAAE;AAClC,IAAI,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAA,EAAS;AAChD,EAAE;;AAEF,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAA,EAAS;AACnD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,IAAI,CAAC,WAAW,GAAkB,EAAE,EAA0B;AAC9E,EAAE,MAAM,UAAU;AAClB,IAAI,GAAG,WAAW;AAClB,IAAI,QAAQ,EAAE,YAAY;AAC1B,IAAI,OAAO,EAAE,UAAU,EAAE;AACzB,IAAI,UAAU,EAAE,WAAW,CAAC,UAAA,IAAc,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAA,IAAe,EAAE,CAAC,QAAQ,EAAE;AACzF,GAAG;;AAEH,EAAEC,qBAAgB,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;AAE3E,EAAE,OAAO,CAAC,SAAA,GAAY,OAAO,CAAC,SAAA,IAAaC,sBAAkB;;AAE7D,EAAE,IAAI,OAAO,CAAC,mBAAA,KAAwB,SAAS,EAAE;AACjD,IAAI,OAAO,CAAC,mBAAA,GAAsB,sBAAsB,CAAC,OAAO,CAAC;AACjE,EAAE;;AAEF,EAAE,OAAOC,QAAQ,CAAC,OAAO,CAAC;AAC1B;;;;;"}
1
+ {"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import * as os from 'node:os';\nimport {\n bunServerIntegration,\n getDefaultIntegrations as getBunDefaultIntegrations,\n makeFetchTransport,\n} from '@sentry/bun';\nimport type { Integration, Options } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport { init as initNode, type NodeClient } from '@sentry/bun';\nimport type { ElysiaOptions } from './types';\n\n/** Get the default integrations for the Elysia SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n // Filter out bunServerIntegration\n // Elysia already produces an HTTP server span, so we don't need Bun's competing root span.\n return getBunDefaultIntegrations(_options).filter(i => i.name !== bunServerIntegration().name);\n}\n\n/**\n * Get the runtime name and version.\n */\nfunction getRuntime(): { name: string; version: string } {\n if (typeof Bun !== 'undefined') {\n return { name: 'bun', version: Bun.version };\n }\n\n return { name: 'node', version: process.version };\n}\n\n/**\n * Initializes the Sentry Elysia SDK.\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n *\n * Sentry.init({\n * dsn: '__DSN__',\n * tracesSampleRate: 1.0,\n * });\n * ```\n */\nexport function init(userOptions: ElysiaOptions = {}): NodeClient | undefined {\n const options = {\n ...userOptions,\n platform: 'javascript',\n runtime: getRuntime(),\n serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),\n };\n\n applySdkMetadata(userOptions, 'elysia', ['elysia', options.runtime.name]);\n\n options.transport = options.transport || makeFetchTransport;\n\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n return initNode(options);\n}\n"],"names":["getBunDefaultIntegrations","bunServerIntegration","applySdkMetadata","makeFetchTransport","initNode"],"mappings":";;;;;;AAYO,SAAS,uBAAuB,QAAA,EAAkC;AAGvE,EAAA,OAAOA,0BAAA,CAA0B,QAAQ,CAAA,CAAE,MAAA,CAAO,OAAK,CAAA,CAAE,IAAA,KAASC,wBAAA,EAAqB,CAAE,IAAI,CAAA;AAC/F;AAKA,SAAS,UAAA,GAAgD;AACvD,EAAA,IAAI,OAAO,QAAQ,WAAA,EAAa;AAC9B,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,IAAI,OAAA,EAAQ;AAAA,EAC7C;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,QAAQ,OAAA,EAAQ;AAClD;AAeO,SAAS,IAAA,CAAK,WAAA,GAA6B,EAAC,EAA2B;AAC5E,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,GAAG,WAAA;AAAA,IACH,QAAA,EAAU,YAAA;AAAA,IACV,SAAS,UAAA,EAAW;AAAA,IACpB,UAAA,EAAY,YAAY,UAAA,IAAc,MAAA,CAAO,QAAQ,GAAA,CAAI,WAAA,IAAe,GAAG,QAAA;AAAS,GACtF;AAEA,EAAAC,qBAAA,CAAiB,aAAa,QAAA,EAAU,CAAC,UAAU,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAC,CAAA;AAExE,EAAA,OAAA,CAAQ,SAAA,GAAY,QAAQ,SAAA,IAAaC,sBAAA;AAEzC,EAAA,IAAI,OAAA,CAAQ,wBAAwB,MAAA,EAAW;AAC7C,IAAA,OAAA,CAAQ,mBAAA,GAAsB,uBAAuB,OAAO,CAAA;AAAA,EAC9D;AAEA,EAAA,OAAOC,SAAS,OAAO,CAAA;AACzB;;;;;"}
@@ -2,195 +2,125 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const core = require('@sentry/core');
4
4
 
5
- const ELYSIA_ORIGIN = 'auto.http.elysia';
6
-
7
- /**
8
- * Map Elysia lifecycle phase names to Sentry span ops.
9
- */
5
+ const ELYSIA_ORIGIN = "auto.http.elysia";
10
6
  const ELYSIA_LIFECYCLE_OP_MAP = {
11
- Request: 'middleware.elysia',
12
- Parse: 'middleware.elysia',
13
- Transform: 'middleware.elysia',
14
- BeforeHandle: 'middleware.elysia',
15
- Handle: 'request_handler.elysia',
16
- AfterHandle: 'middleware.elysia',
17
- MapResponse: 'middleware.elysia',
18
- AfterResponse: 'middleware.elysia',
19
- Error: 'middleware.elysia',
7
+ Request: "middleware.elysia",
8
+ Parse: "middleware.elysia",
9
+ Transform: "middleware.elysia",
10
+ BeforeHandle: "middleware.elysia",
11
+ Handle: "request_handler.elysia",
12
+ AfterHandle: "middleware.elysia",
13
+ MapResponse: "middleware.elysia",
14
+ AfterResponse: "middleware.elysia",
15
+ Error: "middleware.elysia"
20
16
  };
21
-
22
17
  function isBun() {
23
- return typeof Bun !== 'undefined';
18
+ return typeof Bun !== "undefined";
24
19
  }
25
-
26
- /**
27
- * Per-request storage for the root span reference.
28
- * .wrap() captures the root span and .trace() reads it.
29
- * This is necessary because Elysia's .trace() callbacks may run in a different
30
- * async context where getActiveSpan() returns undefined.
31
- */
32
- const rootSpanForRequest = new WeakMap();
33
-
34
- const instrumentedApps = new WeakSet();
35
-
36
- /**
37
- * Updates the root span and isolation scope with the parameterized route name.
38
- */
20
+ const rootSpanForRequest = /* @__PURE__ */ new WeakMap();
21
+ const instrumentedApps = /* @__PURE__ */ new WeakSet();
39
22
  function updateRouteTransactionName(request, method, route) {
40
23
  const transactionName = `${method} ${route}`;
41
-
42
- // Try the stored root span first (reliable across async contexts),
43
- // then fall back to getActiveSpan() for cases where async context is preserved.
44
24
  const rootSpan = rootSpanForRequest.get(request);
45
25
  if (rootSpan) {
46
26
  core.updateSpanName(rootSpan, transactionName);
47
- rootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
27
+ rootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
48
28
  } else {
49
29
  const activeSpan = core.getActiveSpan();
50
30
  if (activeSpan) {
51
31
  const root = core.getRootSpan(activeSpan);
52
32
  core.updateSpanName(root, transactionName);
53
- root.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
33
+ root.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
54
34
  }
55
35
  }
56
-
57
36
  core.getIsolationScope().setTransactionName(transactionName);
58
37
  }
59
-
60
38
  function defaultShouldHandleError(context) {
61
39
  const status = context.set.status;
62
- if (status === undefined) {
40
+ if (status === void 0) {
63
41
  return true;
64
42
  }
65
43
  const statusCode = parseInt(String(status), 10);
66
44
  if (Number.isNaN(statusCode)) {
67
45
  return true;
68
46
  }
69
- // Capture server errors (5xx) and unusual status codes (<= 299 in an error handler).
70
- // 3xx and 4xx are not captured by default (client errors / redirects).
71
47
  return statusCode >= 500 || statusCode <= 299;
72
48
  }
73
-
74
- /**
75
- * Instruments a single Elysia lifecycle phase by creating a Sentry span for it,
76
- * and child spans for each individual handler within the phase.
77
- *
78
- * @param rootSpan - The root server span to parent lifecycle spans under.
79
- * Must be passed explicitly because Elysia's .trace() listener callbacks run
80
- * in a different async context where getActiveSpan() returns undefined.
81
- */
82
49
  function instrumentLifecyclePhase(phaseName, listener, rootSpan) {
83
50
  const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];
84
51
  if (!op) {
85
52
  return;
86
53
  }
87
-
88
- void listener(process => {
54
+ void listener((process) => {
89
55
  const phaseSpan = core.startInactiveSpan({
90
56
  name: phaseName,
91
57
  parentSpan: rootSpan,
92
58
  attributes: {
93
59
  [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
94
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
95
- },
60
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
61
+ }
96
62
  });
97
-
98
- // Create child spans for individual handlers within this phase.
99
- // Named functions get their name, arrow functions get 'anonymous'.
100
63
  if (process.total > 0) {
101
- void process.onEvent(child => {
102
- const handlerName = child.name || 'anonymous';
64
+ void process.onEvent((child) => {
65
+ const handlerName = child.name || "anonymous";
103
66
  const childSpan = core.startInactiveSpan({
104
67
  name: handlerName,
105
68
  parentSpan: phaseSpan,
106
69
  attributes: {
107
70
  [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
108
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
109
- },
71
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
72
+ }
110
73
  });
111
-
112
74
  void child.onStop(() => {
113
75
  childSpan.end();
114
76
  });
115
77
  });
116
78
  }
117
-
118
79
  void process.onStop(() => {
119
80
  phaseSpan.end();
120
81
  });
121
82
  });
122
83
  }
123
-
124
- /**
125
- * Integrate Sentry with an Elysia app for error handling, request context,
126
- * and tracing. Returns the app instance for chaining.
127
- *
128
- * Should be called at the **start** of the chain before defining routes.
129
- *
130
- * @param app The Elysia instance
131
- * @param options Configuration options
132
- * @returns The same Elysia instance for chaining
133
- *
134
- * @example
135
- * ```javascript
136
- * import * as Sentry from '@sentry/elysia';
137
- * import { Elysia } from 'elysia';
138
- *
139
- * Sentry.withElysia(new Elysia())
140
- * .get('/', () => 'Hello World')
141
- * .listen(3000);
142
- * ```
143
- */
144
84
  function withElysia(app, options = {}) {
145
85
  if (instrumentedApps.has(app)) {
146
86
  return app;
147
87
  }
148
88
  instrumentedApps.add(app);
149
-
150
- // Use .wrap() to capture or create the root span for each request.
151
- // This is necessary because Elysia's .trace() callbacks run in a different
152
- // async context where getActiveSpan() returns undefined. By storing the root
153
- // span in a WeakMap keyed by the Request object, we can retrieve it in .trace().
154
- // HigherOrderFunction type is not exported from elysia's main entry point,
155
- // so we type the callback parameters directly.
156
89
  app.wrap((fn, request) => {
157
90
  if (isBun()) {
158
- // On Bun there is no HTTP instrumentation, so we create a root span ourselves.
159
- // Scope setup must happen inside the returned function so that it's active
160
- // when Elysia calls the handler (not during .wrap() registration).
161
91
  return (...args) => {
162
92
  return core.withIsolationScope(() => {
163
93
  return core.continueTrace(
164
94
  {
165
- sentryTrace: request.headers.get('sentry-trace') || '',
166
- baggage: request.headers.get('baggage'),
95
+ sentryTrace: request.headers.get("sentry-trace") || "",
96
+ baggage: request.headers.get("baggage")
167
97
  },
168
98
  () => {
169
99
  return core.startSpanManual(
170
100
  {
171
- op: 'http.server',
101
+ op: "http.server",
172
102
  name: `${request.method} ${new URL(request.url).pathname}`,
173
103
  attributes: {
174
104
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
175
- [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
176
- },
105
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url"
106
+ }
177
107
  },
178
- rootSpan => {
108
+ (rootSpan) => {
179
109
  rootSpanForRequest.set(request, rootSpan);
180
110
  try {
181
111
  const result = fn(...args);
182
112
  if (result instanceof Promise) {
183
113
  return result.then(
184
- res => {
114
+ (res) => {
185
115
  rootSpanForRequest.delete(request);
186
116
  rootSpan.end();
187
117
  return res;
188
118
  },
189
- err => {
119
+ (err) => {
190
120
  rootSpanForRequest.delete(request);
191
121
  rootSpan.end();
192
122
  throw err;
193
- },
123
+ }
194
124
  );
195
125
  }
196
126
  rootSpanForRequest.delete(request);
@@ -201,97 +131,75 @@ function withElysia(app, options = {}) {
201
131
  rootSpan.end();
202
132
  throw err;
203
133
  }
204
- },
134
+ }
205
135
  );
206
- },
136
+ }
207
137
  );
208
138
  });
209
139
  };
210
140
  }
211
-
212
- // On Node.js, the HTTP instrumentation already creates a root span.
213
- // We just capture its reference so .trace() can use it.
214
141
  const activeSpan = core.getActiveSpan();
215
142
  if (activeSpan) {
216
143
  rootSpanForRequest.set(request, core.getRootSpan(activeSpan));
217
144
  }
218
145
  return fn;
219
146
  });
220
-
221
- // Use .trace() ONLY for span creation. The trace API is observational —
222
- // callbacks fire after phases complete, so they can't reliably mutate
223
- // response headers or capture errors. All SDK logic stays in real hooks.
224
- const traceHandler = lifecycle => {
147
+ const traceHandler = (lifecycle) => {
225
148
  const rootSpan = rootSpanForRequest.get(lifecycle.context.request);
226
-
227
149
  const phases = [
228
- ['Request', lifecycle.onRequest],
229
- ['Parse', lifecycle.onParse],
230
- ['Transform', lifecycle.onTransform],
231
- ['BeforeHandle', lifecycle.onBeforeHandle],
232
- ['Handle', lifecycle.onHandle],
233
- ['AfterHandle', lifecycle.onAfterHandle],
234
- ['MapResponse', lifecycle.onMapResponse],
235
- ['AfterResponse', lifecycle.onAfterResponse],
236
- ['Error', lifecycle.onError],
150
+ ["Request", lifecycle.onRequest],
151
+ ["Parse", lifecycle.onParse],
152
+ ["Transform", lifecycle.onTransform],
153
+ ["BeforeHandle", lifecycle.onBeforeHandle],
154
+ ["Handle", lifecycle.onHandle],
155
+ ["AfterHandle", lifecycle.onAfterHandle],
156
+ ["MapResponse", lifecycle.onMapResponse],
157
+ ["AfterResponse", lifecycle.onAfterResponse],
158
+ ["Error", lifecycle.onError]
237
159
  ];
238
-
239
160
  for (const [phaseName, listener] of phases) {
240
161
  if (listener) {
241
162
  instrumentLifecyclePhase(phaseName, listener, rootSpan);
242
163
  }
243
164
  }
244
165
  };
245
-
246
- app.trace({ as: 'global' }, traceHandler);
247
-
248
- // SDK logic uses real lifecycle hooks — these show up as handler spans
249
- // in the trace (named sentryOnRequest etc.), but that's the correct
250
- // tradeoff: the trace API can't reliably mutate state or capture errors.
251
-
166
+ app.trace({ as: "global" }, traceHandler);
252
167
  app.onRequest(function sentryOnRequest(context) {
253
168
  core.getIsolationScope().setSDKProcessingMetadata({
254
- normalizedRequest: core.winterCGRequestToRequestData(context.request),
169
+ normalizedRequest: core.winterCGRequestToRequestData(context.request)
255
170
  });
256
171
  });
257
-
258
- app.onAfterHandle({ as: 'global' }, function sentryOnAfterHandle(context) {
172
+ app.onAfterHandle({ as: "global" }, function sentryOnAfterHandle(context) {
259
173
  if (context.route) {
260
174
  updateRouteTransactionName(context.request, context.request.method, context.route);
261
175
  }
262
-
263
176
  const traceData = core.getTraceData();
264
- if (traceData['sentry-trace']) {
265
- context.set.headers['sentry-trace'] = traceData['sentry-trace'];
177
+ if (traceData["sentry-trace"]) {
178
+ context.set.headers["sentry-trace"] = traceData["sentry-trace"];
266
179
  }
267
180
  if (traceData.baggage) {
268
- context.set.headers['baggage'] = traceData.baggage;
181
+ context.set.headers["baggage"] = traceData.baggage;
269
182
  }
270
183
  });
271
-
272
- app.onError({ as: 'global' }, function sentryOnError(context) {
184
+ app.onError({ as: "global" }, function sentryOnError(context) {
273
185
  if (context.route) {
274
186
  updateRouteTransactionName(context.request, context.request.method, context.route);
275
187
  }
276
-
277
- // Set error status on root span
278
188
  const rootSpan = rootSpanForRequest.get(context.request);
279
189
  if (rootSpan) {
280
190
  const statusCode = parseInt(String(context.set.status), 10);
281
191
  core.setHttpStatus(rootSpan, Number.isNaN(statusCode) ? 500 : statusCode);
282
192
  }
283
-
284
193
  const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;
285
194
  if (shouldHandleError(context)) {
286
195
  core.captureException(context.error, {
287
196
  mechanism: {
288
- type: 'auto.http.elysia.on_error',
289
- handled: false,
290
- },
197
+ type: "auto.http.elysia.on_error",
198
+ handled: false
199
+ }
291
200
  });
292
201
  }
293
202
  });
294
-
295
203
  return app;
296
204
  }
297
205
 
@@ -1 +1 @@
1
- {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n} from '@sentry/core';\nimport type { Elysia, ErrorContext, TraceHandler, TraceListener } from 'elysia';\n\ninterface ElysiaHandlerOptions {\n shouldHandleError?: (context: ErrorContext) => boolean;\n}\n\nconst ELYSIA_ORIGIN = 'auto.http.elysia';\n\n/**\n * Map Elysia lifecycle phase names to Sentry span ops.\n */\nconst ELYSIA_LIFECYCLE_OP_MAP: Record<string, string> = {\n Request: 'middleware.elysia',\n Parse: 'middleware.elysia',\n Transform: 'middleware.elysia',\n BeforeHandle: 'middleware.elysia',\n Handle: 'request_handler.elysia',\n AfterHandle: 'middleware.elysia',\n MapResponse: 'middleware.elysia',\n AfterResponse: 'middleware.elysia',\n Error: 'middleware.elysia',\n};\n\nfunction isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Per-request storage for the root span reference.\n * .wrap() captures the root span and .trace() reads it.\n * This is necessary because Elysia's .trace() callbacks may run in a different\n * async context where getActiveSpan() returns undefined.\n */\nconst rootSpanForRequest = new WeakMap<Request, Span>();\n\nconst instrumentedApps = new WeakSet<Elysia>();\n\n/**\n * Updates the root span and isolation scope with the parameterized route name.\n */\nfunction updateRouteTransactionName(request: Request, method: string, route: string): void {\n const transactionName = `${method} ${route}`;\n\n // Try the stored root span first (reliable across async contexts),\n // then fall back to getActiveSpan() for cases where async context is preserved.\n const rootSpan = rootSpanForRequest.get(request);\n if (rootSpan) {\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n updateSpanName(root, transactionName);\n root.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n }\n\n getIsolationScope().setTransactionName(transactionName);\n}\n\nfunction defaultShouldHandleError(context: ErrorContext): boolean {\n const status = context.set.status;\n if (status === undefined) {\n return true;\n }\n const statusCode = parseInt(String(status), 10);\n if (Number.isNaN(statusCode)) {\n return true;\n }\n // Capture server errors (5xx) and unusual status codes (<= 299 in an error handler).\n // 3xx and 4xx are not captured by default (client errors / redirects).\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Instruments a single Elysia lifecycle phase by creating a Sentry span for it,\n * and child spans for each individual handler within the phase.\n *\n * @param rootSpan - The root server span to parent lifecycle spans under.\n * Must be passed explicitly because Elysia's .trace() listener callbacks run\n * in a different async context where getActiveSpan() returns undefined.\n */\nfunction instrumentLifecyclePhase(phaseName: string, listener: TraceListener, rootSpan: Span | undefined): void {\n const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];\n if (!op) {\n return;\n }\n\n void listener(process => {\n const phaseSpan = startInactiveSpan({\n name: phaseName,\n parentSpan: rootSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n // Create child spans for individual handlers within this phase.\n // Named functions get their name, arrow functions get 'anonymous'.\n if (process.total > 0) {\n void process.onEvent(child => {\n const handlerName = child.name || 'anonymous';\n const childSpan = startInactiveSpan({\n name: handlerName,\n parentSpan: phaseSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n void child.onStop(() => {\n childSpan.end();\n });\n });\n }\n\n void process.onStop(() => {\n phaseSpan.end();\n });\n });\n}\n\n/**\n * Integrate Sentry with an Elysia app for error handling, request context,\n * and tracing. Returns the app instance for chaining.\n *\n * Should be called at the **start** of the chain before defining routes.\n *\n * @param app The Elysia instance\n * @param options Configuration options\n * @returns The same Elysia instance for chaining\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n * import { Elysia } from 'elysia';\n *\n * Sentry.withElysia(new Elysia())\n * .get('/', () => 'Hello World')\n * .listen(3000);\n * ```\n */\nexport function withElysia<T extends Elysia>(app: T, options: ElysiaHandlerOptions = {}): T {\n if (instrumentedApps.has(app)) {\n return app;\n }\n instrumentedApps.add(app);\n\n // Use .wrap() to capture or create the root span for each request.\n // This is necessary because Elysia's .trace() callbacks run in a different\n // async context where getActiveSpan() returns undefined. By storing the root\n // span in a WeakMap keyed by the Request object, we can retrieve it in .trace().\n // HigherOrderFunction type is not exported from elysia's main entry point,\n // so we type the callback parameters directly.\n app.wrap((fn: (...args: unknown[]) => unknown, request: Request) => {\n if (isBun()) {\n // On Bun there is no HTTP instrumentation, so we create a root span ourselves.\n // Scope setup must happen inside the returned function so that it's active\n // when Elysia calls the handler (not during .wrap() registration).\n return (...args: unknown[]) => {\n return withIsolationScope(() => {\n return continueTrace(\n {\n sentryTrace: request.headers.get('sentry-trace') || '',\n baggage: request.headers.get('baggage'),\n },\n () => {\n return startSpanManual(\n {\n op: 'http.server',\n name: `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n },\n },\n rootSpan => {\n rootSpanForRequest.set(request, rootSpan);\n try {\n const result = fn(...args);\n if (result instanceof Promise) {\n return result.then(\n res => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return res;\n },\n err => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n },\n );\n }\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return result;\n } catch (err) {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n }\n },\n );\n },\n );\n });\n };\n }\n\n // On Node.js, the HTTP instrumentation already creates a root span.\n // We just capture its reference so .trace() can use it.\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n rootSpanForRequest.set(request, getRootSpan(activeSpan));\n }\n return fn;\n });\n\n // Use .trace() ONLY for span creation. The trace API is observational —\n // callbacks fire after phases complete, so they can't reliably mutate\n // response headers or capture errors. All SDK logic stays in real hooks.\n const traceHandler: TraceHandler = lifecycle => {\n const rootSpan = rootSpanForRequest.get(lifecycle.context.request);\n\n const phases: [string, TraceListener][] = [\n ['Request', lifecycle.onRequest],\n ['Parse', lifecycle.onParse],\n ['Transform', lifecycle.onTransform],\n ['BeforeHandle', lifecycle.onBeforeHandle],\n ['Handle', lifecycle.onHandle],\n ['AfterHandle', lifecycle.onAfterHandle],\n ['MapResponse', lifecycle.onMapResponse],\n ['AfterResponse', lifecycle.onAfterResponse],\n ['Error', lifecycle.onError],\n ];\n\n for (const [phaseName, listener] of phases) {\n if (listener) {\n instrumentLifecyclePhase(phaseName, listener, rootSpan);\n }\n }\n };\n\n app.trace({ as: 'global' }, traceHandler);\n\n // SDK logic uses real lifecycle hooks — these show up as handler spans\n // in the trace (named sentryOnRequest etc.), but that's the correct\n // tradeoff: the trace API can't reliably mutate state or capture errors.\n\n app.onRequest(function sentryOnRequest(context) {\n getIsolationScope().setSDKProcessingMetadata({\n normalizedRequest: winterCGRequestToRequestData(context.request),\n });\n });\n\n app.onAfterHandle({ as: 'global' }, function sentryOnAfterHandle(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n const traceData = getTraceData();\n if (traceData['sentry-trace']) {\n context.set.headers['sentry-trace'] = traceData['sentry-trace'];\n }\n if (traceData.baggage) {\n context.set.headers['baggage'] = traceData.baggage;\n }\n });\n\n app.onError({ as: 'global' }, function sentryOnError(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n // Set error status on root span\n const rootSpan = rootSpanForRequest.get(context.request);\n if (rootSpan) {\n const statusCode = parseInt(String(context.set.status), 10);\n setHttpStatus(rootSpan, Number.isNaN(statusCode) ? 500 : statusCode);\n }\n\n const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;\n if (shouldHandleError(context)) {\n captureException(context.error, {\n mechanism: {\n type: 'auto.http.elysia.on_error',\n handled: false,\n },\n });\n }\n });\n\n return app;\n}\n"],"names":["updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","getActiveSpan","getRootSpan","getIsolationScope","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","withIsolationScope","continueTrace","startSpanManual","winterCGRequestToRequestData","getTraceData","setHttpStatus","captureException"],"mappings":"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"}
1
+ {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n} from '@sentry/core';\nimport type { Elysia, ErrorContext, TraceHandler, TraceListener } from 'elysia';\n\ninterface ElysiaHandlerOptions {\n shouldHandleError?: (context: ErrorContext) => boolean;\n}\n\nconst ELYSIA_ORIGIN = 'auto.http.elysia';\n\n/**\n * Map Elysia lifecycle phase names to Sentry span ops.\n */\nconst ELYSIA_LIFECYCLE_OP_MAP: Record<string, string> = {\n Request: 'middleware.elysia',\n Parse: 'middleware.elysia',\n Transform: 'middleware.elysia',\n BeforeHandle: 'middleware.elysia',\n Handle: 'request_handler.elysia',\n AfterHandle: 'middleware.elysia',\n MapResponse: 'middleware.elysia',\n AfterResponse: 'middleware.elysia',\n Error: 'middleware.elysia',\n};\n\nfunction isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Per-request storage for the root span reference.\n * .wrap() captures the root span and .trace() reads it.\n * This is necessary because Elysia's .trace() callbacks may run in a different\n * async context where getActiveSpan() returns undefined.\n */\nconst rootSpanForRequest = new WeakMap<Request, Span>();\n\nconst instrumentedApps = new WeakSet<Elysia>();\n\n/**\n * Updates the root span and isolation scope with the parameterized route name.\n */\nfunction updateRouteTransactionName(request: Request, method: string, route: string): void {\n const transactionName = `${method} ${route}`;\n\n // Try the stored root span first (reliable across async contexts),\n // then fall back to getActiveSpan() for cases where async context is preserved.\n const rootSpan = rootSpanForRequest.get(request);\n if (rootSpan) {\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n updateSpanName(root, transactionName);\n root.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n }\n\n getIsolationScope().setTransactionName(transactionName);\n}\n\nfunction defaultShouldHandleError(context: ErrorContext): boolean {\n const status = context.set.status;\n if (status === undefined) {\n return true;\n }\n const statusCode = parseInt(String(status), 10);\n if (Number.isNaN(statusCode)) {\n return true;\n }\n // Capture server errors (5xx) and unusual status codes (<= 299 in an error handler).\n // 3xx and 4xx are not captured by default (client errors / redirects).\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Instruments a single Elysia lifecycle phase by creating a Sentry span for it,\n * and child spans for each individual handler within the phase.\n *\n * @param rootSpan - The root server span to parent lifecycle spans under.\n * Must be passed explicitly because Elysia's .trace() listener callbacks run\n * in a different async context where getActiveSpan() returns undefined.\n */\nfunction instrumentLifecyclePhase(phaseName: string, listener: TraceListener, rootSpan: Span | undefined): void {\n const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];\n if (!op) {\n return;\n }\n\n void listener(process => {\n const phaseSpan = startInactiveSpan({\n name: phaseName,\n parentSpan: rootSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n // Create child spans for individual handlers within this phase.\n // Named functions get their name, arrow functions get 'anonymous'.\n if (process.total > 0) {\n void process.onEvent(child => {\n const handlerName = child.name || 'anonymous';\n const childSpan = startInactiveSpan({\n name: handlerName,\n parentSpan: phaseSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n void child.onStop(() => {\n childSpan.end();\n });\n });\n }\n\n void process.onStop(() => {\n phaseSpan.end();\n });\n });\n}\n\n/**\n * Integrate Sentry with an Elysia app for error handling, request context,\n * and tracing. Returns the app instance for chaining.\n *\n * Should be called at the **start** of the chain before defining routes.\n *\n * @param app The Elysia instance\n * @param options Configuration options\n * @returns The same Elysia instance for chaining\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n * import { Elysia } from 'elysia';\n *\n * Sentry.withElysia(new Elysia())\n * .get('/', () => 'Hello World')\n * .listen(3000);\n * ```\n */\nexport function withElysia<T extends Elysia>(app: T, options: ElysiaHandlerOptions = {}): T {\n if (instrumentedApps.has(app)) {\n return app;\n }\n instrumentedApps.add(app);\n\n // Use .wrap() to capture or create the root span for each request.\n // This is necessary because Elysia's .trace() callbacks run in a different\n // async context where getActiveSpan() returns undefined. By storing the root\n // span in a WeakMap keyed by the Request object, we can retrieve it in .trace().\n // HigherOrderFunction type is not exported from elysia's main entry point,\n // so we type the callback parameters directly.\n app.wrap((fn: (...args: unknown[]) => unknown, request: Request) => {\n if (isBun()) {\n // On Bun there is no HTTP instrumentation, so we create a root span ourselves.\n // Scope setup must happen inside the returned function so that it's active\n // when Elysia calls the handler (not during .wrap() registration).\n return (...args: unknown[]) => {\n return withIsolationScope(() => {\n return continueTrace(\n {\n sentryTrace: request.headers.get('sentry-trace') || '',\n baggage: request.headers.get('baggage'),\n },\n () => {\n return startSpanManual(\n {\n op: 'http.server',\n name: `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n },\n },\n rootSpan => {\n rootSpanForRequest.set(request, rootSpan);\n try {\n const result = fn(...args);\n if (result instanceof Promise) {\n return result.then(\n res => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return res;\n },\n err => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n },\n );\n }\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return result;\n } catch (err) {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n }\n },\n );\n },\n );\n });\n };\n }\n\n // On Node.js, the HTTP instrumentation already creates a root span.\n // We just capture its reference so .trace() can use it.\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n rootSpanForRequest.set(request, getRootSpan(activeSpan));\n }\n return fn;\n });\n\n // Use .trace() ONLY for span creation. The trace API is observational —\n // callbacks fire after phases complete, so they can't reliably mutate\n // response headers or capture errors. All SDK logic stays in real hooks.\n const traceHandler: TraceHandler = lifecycle => {\n const rootSpan = rootSpanForRequest.get(lifecycle.context.request);\n\n const phases: [string, TraceListener][] = [\n ['Request', lifecycle.onRequest],\n ['Parse', lifecycle.onParse],\n ['Transform', lifecycle.onTransform],\n ['BeforeHandle', lifecycle.onBeforeHandle],\n ['Handle', lifecycle.onHandle],\n ['AfterHandle', lifecycle.onAfterHandle],\n ['MapResponse', lifecycle.onMapResponse],\n ['AfterResponse', lifecycle.onAfterResponse],\n ['Error', lifecycle.onError],\n ];\n\n for (const [phaseName, listener] of phases) {\n if (listener) {\n instrumentLifecyclePhase(phaseName, listener, rootSpan);\n }\n }\n };\n\n app.trace({ as: 'global' }, traceHandler);\n\n // SDK logic uses real lifecycle hooks — these show up as handler spans\n // in the trace (named sentryOnRequest etc.), but that's the correct\n // tradeoff: the trace API can't reliably mutate state or capture errors.\n\n app.onRequest(function sentryOnRequest(context) {\n getIsolationScope().setSDKProcessingMetadata({\n normalizedRequest: winterCGRequestToRequestData(context.request),\n });\n });\n\n app.onAfterHandle({ as: 'global' }, function sentryOnAfterHandle(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n const traceData = getTraceData();\n if (traceData['sentry-trace']) {\n context.set.headers['sentry-trace'] = traceData['sentry-trace'];\n }\n if (traceData.baggage) {\n context.set.headers['baggage'] = traceData.baggage;\n }\n });\n\n app.onError({ as: 'global' }, function sentryOnError(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n // Set error status on root span\n const rootSpan = rootSpanForRequest.get(context.request);\n if (rootSpan) {\n const statusCode = parseInt(String(context.set.status), 10);\n setHttpStatus(rootSpan, Number.isNaN(statusCode) ? 500 : statusCode);\n }\n\n const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;\n if (shouldHandleError(context)) {\n captureException(context.error, {\n mechanism: {\n type: 'auto.http.elysia.on_error',\n handled: false,\n },\n });\n }\n });\n\n return app;\n}\n"],"names":["updateSpanName","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","getActiveSpan","getRootSpan","getIsolationScope","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","withIsolationScope","continueTrace","startSpanManual","winterCGRequestToRequestData","getTraceData","setHttpStatus","captureException"],"mappings":"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"}
@@ -1 +1 @@
1
- {"type":"module","version":"10.53.0","sideEffects":false}
1
+ {"type":"module","version":"10.54.0","sideEffects":false}
package/build/esm/sdk.js CHANGED
@@ -2,53 +2,27 @@ import * as os from 'node:os';
2
2
  import { getDefaultIntegrations as getDefaultIntegrations$1, bunServerIntegration, makeFetchTransport, init as init$1 } from '@sentry/bun';
3
3
  import { applySdkMetadata } from '@sentry/core';
4
4
 
5
- /** Get the default integrations for the Elysia SDK. */
6
5
  function getDefaultIntegrations(_options) {
7
- // Filter out bunServerIntegration
8
- // Elysia already produces an HTTP server span, so we don't need Bun's competing root span.
9
- return getDefaultIntegrations$1(_options).filter(i => i.name !== bunServerIntegration().name);
6
+ return getDefaultIntegrations$1(_options).filter((i) => i.name !== bunServerIntegration().name);
10
7
  }
11
-
12
- /**
13
- * Get the runtime name and version.
14
- */
15
8
  function getRuntime() {
16
- if (typeof Bun !== 'undefined') {
17
- return { name: 'bun', version: Bun.version };
9
+ if (typeof Bun !== "undefined") {
10
+ return { name: "bun", version: Bun.version };
18
11
  }
19
-
20
- return { name: 'node', version: process.version };
12
+ return { name: "node", version: process.version };
21
13
  }
22
-
23
- /**
24
- * Initializes the Sentry Elysia SDK.
25
- *
26
- * @example
27
- * ```javascript
28
- * import * as Sentry from '@sentry/elysia';
29
- *
30
- * Sentry.init({
31
- * dsn: '__DSN__',
32
- * tracesSampleRate: 1.0,
33
- * });
34
- * ```
35
- */
36
14
  function init(userOptions = {}) {
37
15
  const options = {
38
16
  ...userOptions,
39
- platform: 'javascript',
17
+ platform: "javascript",
40
18
  runtime: getRuntime(),
41
- serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),
19
+ serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname()
42
20
  };
43
-
44
- applySdkMetadata(userOptions, 'elysia', ['elysia', options.runtime.name]);
45
-
21
+ applySdkMetadata(userOptions, "elysia", ["elysia", options.runtime.name]);
46
22
  options.transport = options.transport || makeFetchTransport;
47
-
48
- if (options.defaultIntegrations === undefined) {
23
+ if (options.defaultIntegrations === void 0) {
49
24
  options.defaultIntegrations = getDefaultIntegrations(options);
50
25
  }
51
-
52
26
  return init$1(options);
53
27
  }
54
28
 
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import * as os from 'node:os';\nimport {\n bunServerIntegration,\n getDefaultIntegrations as getBunDefaultIntegrations,\n makeFetchTransport,\n} from '@sentry/bun';\nimport type { Integration, Options } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport { init as initNode, type NodeClient } from '@sentry/bun';\nimport type { ElysiaOptions } from './types';\n\n/** Get the default integrations for the Elysia SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n // Filter out bunServerIntegration\n // Elysia already produces an HTTP server span, so we don't need Bun's competing root span.\n return getBunDefaultIntegrations(_options).filter(i => i.name !== bunServerIntegration().name);\n}\n\n/**\n * Get the runtime name and version.\n */\nfunction getRuntime(): { name: string; version: string } {\n if (typeof Bun !== 'undefined') {\n return { name: 'bun', version: Bun.version };\n }\n\n return { name: 'node', version: process.version };\n}\n\n/**\n * Initializes the Sentry Elysia SDK.\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n *\n * Sentry.init({\n * dsn: '__DSN__',\n * tracesSampleRate: 1.0,\n * });\n * ```\n */\nexport function init(userOptions: ElysiaOptions = {}): NodeClient | undefined {\n const options = {\n ...userOptions,\n platform: 'javascript',\n runtime: getRuntime(),\n serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),\n };\n\n applySdkMetadata(userOptions, 'elysia', ['elysia', options.runtime.name]);\n\n options.transport = options.transport || makeFetchTransport;\n\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n return initNode(options);\n}\n"],"names":["getBunDefaultIntegrations","initNode"],"mappings":";;;;AAWA;AACO,SAAS,sBAAsB,CAAC,QAAQ,EAA0B;AACzE;AACA;AACA,EAAE,OAAOA,wBAAyB,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA,IAAK,CAAC,CAAC,SAAS,oBAAoB,EAAE,CAAC,IAAI,CAAC;AAChG;;AAEA;AACA;AACA;AACA,SAAS,UAAU,GAAsC;AACzD,EAAE,IAAI,OAAO,GAAA,KAAQ,WAAW,EAAE;AAClC,IAAI,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAA,EAAS;AAChD,EAAE;;AAEF,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAA,EAAS;AACnD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,IAAI,CAAC,WAAW,GAAkB,EAAE,EAA0B;AAC9E,EAAE,MAAM,UAAU;AAClB,IAAI,GAAG,WAAW;AAClB,IAAI,QAAQ,EAAE,YAAY;AAC1B,IAAI,OAAO,EAAE,UAAU,EAAE;AACzB,IAAI,UAAU,EAAE,WAAW,CAAC,UAAA,IAAc,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAA,IAAe,EAAE,CAAC,QAAQ,EAAE;AACzF,GAAG;;AAEH,EAAE,gBAAgB,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;AAE3E,EAAE,OAAO,CAAC,SAAA,GAAY,OAAO,CAAC,SAAA,IAAa,kBAAkB;;AAE7D,EAAE,IAAI,OAAO,CAAC,mBAAA,KAAwB,SAAS,EAAE;AACjD,IAAI,OAAO,CAAC,mBAAA,GAAsB,sBAAsB,CAAC,OAAO,CAAC;AACjE,EAAE;;AAEF,EAAE,OAAOC,MAAQ,CAAC,OAAO,CAAC;AAC1B;;;;"}
1
+ {"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import * as os from 'node:os';\nimport {\n bunServerIntegration,\n getDefaultIntegrations as getBunDefaultIntegrations,\n makeFetchTransport,\n} from '@sentry/bun';\nimport type { Integration, Options } from '@sentry/core';\nimport { applySdkMetadata } from '@sentry/core';\nimport { init as initNode, type NodeClient } from '@sentry/bun';\nimport type { ElysiaOptions } from './types';\n\n/** Get the default integrations for the Elysia SDK. */\nexport function getDefaultIntegrations(_options: Options): Integration[] {\n // Filter out bunServerIntegration\n // Elysia already produces an HTTP server span, so we don't need Bun's competing root span.\n return getBunDefaultIntegrations(_options).filter(i => i.name !== bunServerIntegration().name);\n}\n\n/**\n * Get the runtime name and version.\n */\nfunction getRuntime(): { name: string; version: string } {\n if (typeof Bun !== 'undefined') {\n return { name: 'bun', version: Bun.version };\n }\n\n return { name: 'node', version: process.version };\n}\n\n/**\n * Initializes the Sentry Elysia SDK.\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n *\n * Sentry.init({\n * dsn: '__DSN__',\n * tracesSampleRate: 1.0,\n * });\n * ```\n */\nexport function init(userOptions: ElysiaOptions = {}): NodeClient | undefined {\n const options = {\n ...userOptions,\n platform: 'javascript',\n runtime: getRuntime(),\n serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),\n };\n\n applySdkMetadata(userOptions, 'elysia', ['elysia', options.runtime.name]);\n\n options.transport = options.transport || makeFetchTransport;\n\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n return initNode(options);\n}\n"],"names":["getBunDefaultIntegrations","initNode"],"mappings":";;;;AAYO,SAAS,uBAAuB,QAAA,EAAkC;AAGvE,EAAA,OAAOA,wBAAA,CAA0B,QAAQ,CAAA,CAAE,MAAA,CAAO,OAAK,CAAA,CAAE,IAAA,KAAS,oBAAA,EAAqB,CAAE,IAAI,CAAA;AAC/F;AAKA,SAAS,UAAA,GAAgD;AACvD,EAAA,IAAI,OAAO,QAAQ,WAAA,EAAa;AAC9B,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,IAAI,OAAA,EAAQ;AAAA,EAC7C;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,QAAQ,OAAA,EAAQ;AAClD;AAeO,SAAS,IAAA,CAAK,WAAA,GAA6B,EAAC,EAA2B;AAC5E,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,GAAG,WAAA;AAAA,IACH,QAAA,EAAU,YAAA;AAAA,IACV,SAAS,UAAA,EAAW;AAAA,IACpB,UAAA,EAAY,YAAY,UAAA,IAAc,MAAA,CAAO,QAAQ,GAAA,CAAI,WAAA,IAAe,GAAG,QAAA;AAAS,GACtF;AAEA,EAAA,gBAAA,CAAiB,aAAa,QAAA,EAAU,CAAC,UAAU,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAC,CAAA;AAExE,EAAA,OAAA,CAAQ,SAAA,GAAY,QAAQ,SAAA,IAAa,kBAAA;AAEzC,EAAA,IAAI,OAAA,CAAQ,wBAAwB,MAAA,EAAW;AAC7C,IAAA,OAAA,CAAQ,mBAAA,GAAsB,uBAAuB,OAAO,CAAA;AAAA,EAC9D;AAEA,EAAA,OAAOC,OAAS,OAAO,CAAA;AACzB;;;;"}
@@ -1,194 +1,124 @@
1
1
  import { withIsolationScope, continueTrace, startSpanManual, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getActiveSpan, getRootSpan, getIsolationScope, winterCGRequestToRequestData, getTraceData, setHttpStatus, captureException, updateSpanName, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core';
2
2
 
3
- const ELYSIA_ORIGIN = 'auto.http.elysia';
4
-
5
- /**
6
- * Map Elysia lifecycle phase names to Sentry span ops.
7
- */
3
+ const ELYSIA_ORIGIN = "auto.http.elysia";
8
4
  const ELYSIA_LIFECYCLE_OP_MAP = {
9
- Request: 'middleware.elysia',
10
- Parse: 'middleware.elysia',
11
- Transform: 'middleware.elysia',
12
- BeforeHandle: 'middleware.elysia',
13
- Handle: 'request_handler.elysia',
14
- AfterHandle: 'middleware.elysia',
15
- MapResponse: 'middleware.elysia',
16
- AfterResponse: 'middleware.elysia',
17
- Error: 'middleware.elysia',
5
+ Request: "middleware.elysia",
6
+ Parse: "middleware.elysia",
7
+ Transform: "middleware.elysia",
8
+ BeforeHandle: "middleware.elysia",
9
+ Handle: "request_handler.elysia",
10
+ AfterHandle: "middleware.elysia",
11
+ MapResponse: "middleware.elysia",
12
+ AfterResponse: "middleware.elysia",
13
+ Error: "middleware.elysia"
18
14
  };
19
-
20
15
  function isBun() {
21
- return typeof Bun !== 'undefined';
16
+ return typeof Bun !== "undefined";
22
17
  }
23
-
24
- /**
25
- * Per-request storage for the root span reference.
26
- * .wrap() captures the root span and .trace() reads it.
27
- * This is necessary because Elysia's .trace() callbacks may run in a different
28
- * async context where getActiveSpan() returns undefined.
29
- */
30
- const rootSpanForRequest = new WeakMap();
31
-
32
- const instrumentedApps = new WeakSet();
33
-
34
- /**
35
- * Updates the root span and isolation scope with the parameterized route name.
36
- */
18
+ const rootSpanForRequest = /* @__PURE__ */ new WeakMap();
19
+ const instrumentedApps = /* @__PURE__ */ new WeakSet();
37
20
  function updateRouteTransactionName(request, method, route) {
38
21
  const transactionName = `${method} ${route}`;
39
-
40
- // Try the stored root span first (reliable across async contexts),
41
- // then fall back to getActiveSpan() for cases where async context is preserved.
42
22
  const rootSpan = rootSpanForRequest.get(request);
43
23
  if (rootSpan) {
44
24
  updateSpanName(rootSpan, transactionName);
45
- rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
25
+ rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
46
26
  } else {
47
27
  const activeSpan = getActiveSpan();
48
28
  if (activeSpan) {
49
29
  const root = getRootSpan(activeSpan);
50
30
  updateSpanName(root, transactionName);
51
- root.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');
31
+ root.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
52
32
  }
53
33
  }
54
-
55
34
  getIsolationScope().setTransactionName(transactionName);
56
35
  }
57
-
58
36
  function defaultShouldHandleError(context) {
59
37
  const status = context.set.status;
60
- if (status === undefined) {
38
+ if (status === void 0) {
61
39
  return true;
62
40
  }
63
41
  const statusCode = parseInt(String(status), 10);
64
42
  if (Number.isNaN(statusCode)) {
65
43
  return true;
66
44
  }
67
- // Capture server errors (5xx) and unusual status codes (<= 299 in an error handler).
68
- // 3xx and 4xx are not captured by default (client errors / redirects).
69
45
  return statusCode >= 500 || statusCode <= 299;
70
46
  }
71
-
72
- /**
73
- * Instruments a single Elysia lifecycle phase by creating a Sentry span for it,
74
- * and child spans for each individual handler within the phase.
75
- *
76
- * @param rootSpan - The root server span to parent lifecycle spans under.
77
- * Must be passed explicitly because Elysia's .trace() listener callbacks run
78
- * in a different async context where getActiveSpan() returns undefined.
79
- */
80
47
  function instrumentLifecyclePhase(phaseName, listener, rootSpan) {
81
48
  const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];
82
49
  if (!op) {
83
50
  return;
84
51
  }
85
-
86
- void listener(process => {
52
+ void listener((process) => {
87
53
  const phaseSpan = startInactiveSpan({
88
54
  name: phaseName,
89
55
  parentSpan: rootSpan,
90
56
  attributes: {
91
57
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
92
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
93
- },
58
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
59
+ }
94
60
  });
95
-
96
- // Create child spans for individual handlers within this phase.
97
- // Named functions get their name, arrow functions get 'anonymous'.
98
61
  if (process.total > 0) {
99
- void process.onEvent(child => {
100
- const handlerName = child.name || 'anonymous';
62
+ void process.onEvent((child) => {
63
+ const handlerName = child.name || "anonymous";
101
64
  const childSpan = startInactiveSpan({
102
65
  name: handlerName,
103
66
  parentSpan: phaseSpan,
104
67
  attributes: {
105
68
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
106
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
107
- },
69
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
70
+ }
108
71
  });
109
-
110
72
  void child.onStop(() => {
111
73
  childSpan.end();
112
74
  });
113
75
  });
114
76
  }
115
-
116
77
  void process.onStop(() => {
117
78
  phaseSpan.end();
118
79
  });
119
80
  });
120
81
  }
121
-
122
- /**
123
- * Integrate Sentry with an Elysia app for error handling, request context,
124
- * and tracing. Returns the app instance for chaining.
125
- *
126
- * Should be called at the **start** of the chain before defining routes.
127
- *
128
- * @param app The Elysia instance
129
- * @param options Configuration options
130
- * @returns The same Elysia instance for chaining
131
- *
132
- * @example
133
- * ```javascript
134
- * import * as Sentry from '@sentry/elysia';
135
- * import { Elysia } from 'elysia';
136
- *
137
- * Sentry.withElysia(new Elysia())
138
- * .get('/', () => 'Hello World')
139
- * .listen(3000);
140
- * ```
141
- */
142
82
  function withElysia(app, options = {}) {
143
83
  if (instrumentedApps.has(app)) {
144
84
  return app;
145
85
  }
146
86
  instrumentedApps.add(app);
147
-
148
- // Use .wrap() to capture or create the root span for each request.
149
- // This is necessary because Elysia's .trace() callbacks run in a different
150
- // async context where getActiveSpan() returns undefined. By storing the root
151
- // span in a WeakMap keyed by the Request object, we can retrieve it in .trace().
152
- // HigherOrderFunction type is not exported from elysia's main entry point,
153
- // so we type the callback parameters directly.
154
87
  app.wrap((fn, request) => {
155
88
  if (isBun()) {
156
- // On Bun there is no HTTP instrumentation, so we create a root span ourselves.
157
- // Scope setup must happen inside the returned function so that it's active
158
- // when Elysia calls the handler (not during .wrap() registration).
159
89
  return (...args) => {
160
90
  return withIsolationScope(() => {
161
91
  return continueTrace(
162
92
  {
163
- sentryTrace: request.headers.get('sentry-trace') || '',
164
- baggage: request.headers.get('baggage'),
93
+ sentryTrace: request.headers.get("sentry-trace") || "",
94
+ baggage: request.headers.get("baggage")
165
95
  },
166
96
  () => {
167
97
  return startSpanManual(
168
98
  {
169
- op: 'http.server',
99
+ op: "http.server",
170
100
  name: `${request.method} ${new URL(request.url).pathname}`,
171
101
  attributes: {
172
102
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
173
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
174
- },
103
+ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url"
104
+ }
175
105
  },
176
- rootSpan => {
106
+ (rootSpan) => {
177
107
  rootSpanForRequest.set(request, rootSpan);
178
108
  try {
179
109
  const result = fn(...args);
180
110
  if (result instanceof Promise) {
181
111
  return result.then(
182
- res => {
112
+ (res) => {
183
113
  rootSpanForRequest.delete(request);
184
114
  rootSpan.end();
185
115
  return res;
186
116
  },
187
- err => {
117
+ (err) => {
188
118
  rootSpanForRequest.delete(request);
189
119
  rootSpan.end();
190
120
  throw err;
191
- },
121
+ }
192
122
  );
193
123
  }
194
124
  rootSpanForRequest.delete(request);
@@ -199,97 +129,75 @@ function withElysia(app, options = {}) {
199
129
  rootSpan.end();
200
130
  throw err;
201
131
  }
202
- },
132
+ }
203
133
  );
204
- },
134
+ }
205
135
  );
206
136
  });
207
137
  };
208
138
  }
209
-
210
- // On Node.js, the HTTP instrumentation already creates a root span.
211
- // We just capture its reference so .trace() can use it.
212
139
  const activeSpan = getActiveSpan();
213
140
  if (activeSpan) {
214
141
  rootSpanForRequest.set(request, getRootSpan(activeSpan));
215
142
  }
216
143
  return fn;
217
144
  });
218
-
219
- // Use .trace() ONLY for span creation. The trace API is observational —
220
- // callbacks fire after phases complete, so they can't reliably mutate
221
- // response headers or capture errors. All SDK logic stays in real hooks.
222
- const traceHandler = lifecycle => {
145
+ const traceHandler = (lifecycle) => {
223
146
  const rootSpan = rootSpanForRequest.get(lifecycle.context.request);
224
-
225
147
  const phases = [
226
- ['Request', lifecycle.onRequest],
227
- ['Parse', lifecycle.onParse],
228
- ['Transform', lifecycle.onTransform],
229
- ['BeforeHandle', lifecycle.onBeforeHandle],
230
- ['Handle', lifecycle.onHandle],
231
- ['AfterHandle', lifecycle.onAfterHandle],
232
- ['MapResponse', lifecycle.onMapResponse],
233
- ['AfterResponse', lifecycle.onAfterResponse],
234
- ['Error', lifecycle.onError],
148
+ ["Request", lifecycle.onRequest],
149
+ ["Parse", lifecycle.onParse],
150
+ ["Transform", lifecycle.onTransform],
151
+ ["BeforeHandle", lifecycle.onBeforeHandle],
152
+ ["Handle", lifecycle.onHandle],
153
+ ["AfterHandle", lifecycle.onAfterHandle],
154
+ ["MapResponse", lifecycle.onMapResponse],
155
+ ["AfterResponse", lifecycle.onAfterResponse],
156
+ ["Error", lifecycle.onError]
235
157
  ];
236
-
237
158
  for (const [phaseName, listener] of phases) {
238
159
  if (listener) {
239
160
  instrumentLifecyclePhase(phaseName, listener, rootSpan);
240
161
  }
241
162
  }
242
163
  };
243
-
244
- app.trace({ as: 'global' }, traceHandler);
245
-
246
- // SDK logic uses real lifecycle hooks — these show up as handler spans
247
- // in the trace (named sentryOnRequest etc.), but that's the correct
248
- // tradeoff: the trace API can't reliably mutate state or capture errors.
249
-
164
+ app.trace({ as: "global" }, traceHandler);
250
165
  app.onRequest(function sentryOnRequest(context) {
251
166
  getIsolationScope().setSDKProcessingMetadata({
252
- normalizedRequest: winterCGRequestToRequestData(context.request),
167
+ normalizedRequest: winterCGRequestToRequestData(context.request)
253
168
  });
254
169
  });
255
-
256
- app.onAfterHandle({ as: 'global' }, function sentryOnAfterHandle(context) {
170
+ app.onAfterHandle({ as: "global" }, function sentryOnAfterHandle(context) {
257
171
  if (context.route) {
258
172
  updateRouteTransactionName(context.request, context.request.method, context.route);
259
173
  }
260
-
261
174
  const traceData = getTraceData();
262
- if (traceData['sentry-trace']) {
263
- context.set.headers['sentry-trace'] = traceData['sentry-trace'];
175
+ if (traceData["sentry-trace"]) {
176
+ context.set.headers["sentry-trace"] = traceData["sentry-trace"];
264
177
  }
265
178
  if (traceData.baggage) {
266
- context.set.headers['baggage'] = traceData.baggage;
179
+ context.set.headers["baggage"] = traceData.baggage;
267
180
  }
268
181
  });
269
-
270
- app.onError({ as: 'global' }, function sentryOnError(context) {
182
+ app.onError({ as: "global" }, function sentryOnError(context) {
271
183
  if (context.route) {
272
184
  updateRouteTransactionName(context.request, context.request.method, context.route);
273
185
  }
274
-
275
- // Set error status on root span
276
186
  const rootSpan = rootSpanForRequest.get(context.request);
277
187
  if (rootSpan) {
278
188
  const statusCode = parseInt(String(context.set.status), 10);
279
189
  setHttpStatus(rootSpan, Number.isNaN(statusCode) ? 500 : statusCode);
280
190
  }
281
-
282
191
  const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;
283
192
  if (shouldHandleError(context)) {
284
193
  captureException(context.error, {
285
194
  mechanism: {
286
- type: 'auto.http.elysia.on_error',
287
- handled: false,
288
- },
195
+ type: "auto.http.elysia.on_error",
196
+ handled: false
197
+ }
289
198
  });
290
199
  }
291
200
  });
292
-
293
201
  return app;
294
202
  }
295
203
 
@@ -1 +1 @@
1
- {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n} from '@sentry/core';\nimport type { Elysia, ErrorContext, TraceHandler, TraceListener } from 'elysia';\n\ninterface ElysiaHandlerOptions {\n shouldHandleError?: (context: ErrorContext) => boolean;\n}\n\nconst ELYSIA_ORIGIN = 'auto.http.elysia';\n\n/**\n * Map Elysia lifecycle phase names to Sentry span ops.\n */\nconst ELYSIA_LIFECYCLE_OP_MAP: Record<string, string> = {\n Request: 'middleware.elysia',\n Parse: 'middleware.elysia',\n Transform: 'middleware.elysia',\n BeforeHandle: 'middleware.elysia',\n Handle: 'request_handler.elysia',\n AfterHandle: 'middleware.elysia',\n MapResponse: 'middleware.elysia',\n AfterResponse: 'middleware.elysia',\n Error: 'middleware.elysia',\n};\n\nfunction isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Per-request storage for the root span reference.\n * .wrap() captures the root span and .trace() reads it.\n * This is necessary because Elysia's .trace() callbacks may run in a different\n * async context where getActiveSpan() returns undefined.\n */\nconst rootSpanForRequest = new WeakMap<Request, Span>();\n\nconst instrumentedApps = new WeakSet<Elysia>();\n\n/**\n * Updates the root span and isolation scope with the parameterized route name.\n */\nfunction updateRouteTransactionName(request: Request, method: string, route: string): void {\n const transactionName = `${method} ${route}`;\n\n // Try the stored root span first (reliable across async contexts),\n // then fall back to getActiveSpan() for cases where async context is preserved.\n const rootSpan = rootSpanForRequest.get(request);\n if (rootSpan) {\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n updateSpanName(root, transactionName);\n root.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n }\n\n getIsolationScope().setTransactionName(transactionName);\n}\n\nfunction defaultShouldHandleError(context: ErrorContext): boolean {\n const status = context.set.status;\n if (status === undefined) {\n return true;\n }\n const statusCode = parseInt(String(status), 10);\n if (Number.isNaN(statusCode)) {\n return true;\n }\n // Capture server errors (5xx) and unusual status codes (<= 299 in an error handler).\n // 3xx and 4xx are not captured by default (client errors / redirects).\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Instruments a single Elysia lifecycle phase by creating a Sentry span for it,\n * and child spans for each individual handler within the phase.\n *\n * @param rootSpan - The root server span to parent lifecycle spans under.\n * Must be passed explicitly because Elysia's .trace() listener callbacks run\n * in a different async context where getActiveSpan() returns undefined.\n */\nfunction instrumentLifecyclePhase(phaseName: string, listener: TraceListener, rootSpan: Span | undefined): void {\n const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];\n if (!op) {\n return;\n }\n\n void listener(process => {\n const phaseSpan = startInactiveSpan({\n name: phaseName,\n parentSpan: rootSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n // Create child spans for individual handlers within this phase.\n // Named functions get their name, arrow functions get 'anonymous'.\n if (process.total > 0) {\n void process.onEvent(child => {\n const handlerName = child.name || 'anonymous';\n const childSpan = startInactiveSpan({\n name: handlerName,\n parentSpan: phaseSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n void child.onStop(() => {\n childSpan.end();\n });\n });\n }\n\n void process.onStop(() => {\n phaseSpan.end();\n });\n });\n}\n\n/**\n * Integrate Sentry with an Elysia app for error handling, request context,\n * and tracing. Returns the app instance for chaining.\n *\n * Should be called at the **start** of the chain before defining routes.\n *\n * @param app The Elysia instance\n * @param options Configuration options\n * @returns The same Elysia instance for chaining\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n * import { Elysia } from 'elysia';\n *\n * Sentry.withElysia(new Elysia())\n * .get('/', () => 'Hello World')\n * .listen(3000);\n * ```\n */\nexport function withElysia<T extends Elysia>(app: T, options: ElysiaHandlerOptions = {}): T {\n if (instrumentedApps.has(app)) {\n return app;\n }\n instrumentedApps.add(app);\n\n // Use .wrap() to capture or create the root span for each request.\n // This is necessary because Elysia's .trace() callbacks run in a different\n // async context where getActiveSpan() returns undefined. By storing the root\n // span in a WeakMap keyed by the Request object, we can retrieve it in .trace().\n // HigherOrderFunction type is not exported from elysia's main entry point,\n // so we type the callback parameters directly.\n app.wrap((fn: (...args: unknown[]) => unknown, request: Request) => {\n if (isBun()) {\n // On Bun there is no HTTP instrumentation, so we create a root span ourselves.\n // Scope setup must happen inside the returned function so that it's active\n // when Elysia calls the handler (not during .wrap() registration).\n return (...args: unknown[]) => {\n return withIsolationScope(() => {\n return continueTrace(\n {\n sentryTrace: request.headers.get('sentry-trace') || '',\n baggage: request.headers.get('baggage'),\n },\n () => {\n return startSpanManual(\n {\n op: 'http.server',\n name: `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n },\n },\n rootSpan => {\n rootSpanForRequest.set(request, rootSpan);\n try {\n const result = fn(...args);\n if (result instanceof Promise) {\n return result.then(\n res => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return res;\n },\n err => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n },\n );\n }\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return result;\n } catch (err) {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n }\n },\n );\n },\n );\n });\n };\n }\n\n // On Node.js, the HTTP instrumentation already creates a root span.\n // We just capture its reference so .trace() can use it.\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n rootSpanForRequest.set(request, getRootSpan(activeSpan));\n }\n return fn;\n });\n\n // Use .trace() ONLY for span creation. The trace API is observational —\n // callbacks fire after phases complete, so they can't reliably mutate\n // response headers or capture errors. All SDK logic stays in real hooks.\n const traceHandler: TraceHandler = lifecycle => {\n const rootSpan = rootSpanForRequest.get(lifecycle.context.request);\n\n const phases: [string, TraceListener][] = [\n ['Request', lifecycle.onRequest],\n ['Parse', lifecycle.onParse],\n ['Transform', lifecycle.onTransform],\n ['BeforeHandle', lifecycle.onBeforeHandle],\n ['Handle', lifecycle.onHandle],\n ['AfterHandle', lifecycle.onAfterHandle],\n ['MapResponse', lifecycle.onMapResponse],\n ['AfterResponse', lifecycle.onAfterResponse],\n ['Error', lifecycle.onError],\n ];\n\n for (const [phaseName, listener] of phases) {\n if (listener) {\n instrumentLifecyclePhase(phaseName, listener, rootSpan);\n }\n }\n };\n\n app.trace({ as: 'global' }, traceHandler);\n\n // SDK logic uses real lifecycle hooks — these show up as handler spans\n // in the trace (named sentryOnRequest etc.), but that's the correct\n // tradeoff: the trace API can't reliably mutate state or capture errors.\n\n app.onRequest(function sentryOnRequest(context) {\n getIsolationScope().setSDKProcessingMetadata({\n normalizedRequest: winterCGRequestToRequestData(context.request),\n });\n });\n\n app.onAfterHandle({ as: 'global' }, function sentryOnAfterHandle(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n const traceData = getTraceData();\n if (traceData['sentry-trace']) {\n context.set.headers['sentry-trace'] = traceData['sentry-trace'];\n }\n if (traceData.baggage) {\n context.set.headers['baggage'] = traceData.baggage;\n }\n });\n\n app.onError({ as: 'global' }, function sentryOnError(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n // Set error status on root span\n const rootSpan = rootSpanForRequest.get(context.request);\n if (rootSpan) {\n const statusCode = parseInt(String(context.set.status), 10);\n setHttpStatus(rootSpan, Number.isNaN(statusCode) ? 500 : statusCode);\n }\n\n const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;\n if (shouldHandleError(context)) {\n captureException(context.error, {\n mechanism: {\n type: 'auto.http.elysia.on_error',\n handled: false,\n },\n });\n }\n });\n\n return app;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n} from '@sentry/core';\nimport type { Elysia, ErrorContext, TraceHandler, TraceListener } from 'elysia';\n\ninterface ElysiaHandlerOptions {\n shouldHandleError?: (context: ErrorContext) => boolean;\n}\n\nconst ELYSIA_ORIGIN = 'auto.http.elysia';\n\n/**\n * Map Elysia lifecycle phase names to Sentry span ops.\n */\nconst ELYSIA_LIFECYCLE_OP_MAP: Record<string, string> = {\n Request: 'middleware.elysia',\n Parse: 'middleware.elysia',\n Transform: 'middleware.elysia',\n BeforeHandle: 'middleware.elysia',\n Handle: 'request_handler.elysia',\n AfterHandle: 'middleware.elysia',\n MapResponse: 'middleware.elysia',\n AfterResponse: 'middleware.elysia',\n Error: 'middleware.elysia',\n};\n\nfunction isBun(): boolean {\n return typeof Bun !== 'undefined';\n}\n\n/**\n * Per-request storage for the root span reference.\n * .wrap() captures the root span and .trace() reads it.\n * This is necessary because Elysia's .trace() callbacks may run in a different\n * async context where getActiveSpan() returns undefined.\n */\nconst rootSpanForRequest = new WeakMap<Request, Span>();\n\nconst instrumentedApps = new WeakSet<Elysia>();\n\n/**\n * Updates the root span and isolation scope with the parameterized route name.\n */\nfunction updateRouteTransactionName(request: Request, method: string, route: string): void {\n const transactionName = `${method} ${route}`;\n\n // Try the stored root span first (reliable across async contexts),\n // then fall back to getActiveSpan() for cases where async context is preserved.\n const rootSpan = rootSpanForRequest.get(request);\n if (rootSpan) {\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n updateSpanName(root, transactionName);\n root.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n }\n }\n\n getIsolationScope().setTransactionName(transactionName);\n}\n\nfunction defaultShouldHandleError(context: ErrorContext): boolean {\n const status = context.set.status;\n if (status === undefined) {\n return true;\n }\n const statusCode = parseInt(String(status), 10);\n if (Number.isNaN(statusCode)) {\n return true;\n }\n // Capture server errors (5xx) and unusual status codes (<= 299 in an error handler).\n // 3xx and 4xx are not captured by default (client errors / redirects).\n return statusCode >= 500 || statusCode <= 299;\n}\n\n/**\n * Instruments a single Elysia lifecycle phase by creating a Sentry span for it,\n * and child spans for each individual handler within the phase.\n *\n * @param rootSpan - The root server span to parent lifecycle spans under.\n * Must be passed explicitly because Elysia's .trace() listener callbacks run\n * in a different async context where getActiveSpan() returns undefined.\n */\nfunction instrumentLifecyclePhase(phaseName: string, listener: TraceListener, rootSpan: Span | undefined): void {\n const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];\n if (!op) {\n return;\n }\n\n void listener(process => {\n const phaseSpan = startInactiveSpan({\n name: phaseName,\n parentSpan: rootSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n // Create child spans for individual handlers within this phase.\n // Named functions get their name, arrow functions get 'anonymous'.\n if (process.total > 0) {\n void process.onEvent(child => {\n const handlerName = child.name || 'anonymous';\n const childSpan = startInactiveSpan({\n name: handlerName,\n parentSpan: phaseSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n },\n });\n\n void child.onStop(() => {\n childSpan.end();\n });\n });\n }\n\n void process.onStop(() => {\n phaseSpan.end();\n });\n });\n}\n\n/**\n * Integrate Sentry with an Elysia app for error handling, request context,\n * and tracing. Returns the app instance for chaining.\n *\n * Should be called at the **start** of the chain before defining routes.\n *\n * @param app The Elysia instance\n * @param options Configuration options\n * @returns The same Elysia instance for chaining\n *\n * @example\n * ```javascript\n * import * as Sentry from '@sentry/elysia';\n * import { Elysia } from 'elysia';\n *\n * Sentry.withElysia(new Elysia())\n * .get('/', () => 'Hello World')\n * .listen(3000);\n * ```\n */\nexport function withElysia<T extends Elysia>(app: T, options: ElysiaHandlerOptions = {}): T {\n if (instrumentedApps.has(app)) {\n return app;\n }\n instrumentedApps.add(app);\n\n // Use .wrap() to capture or create the root span for each request.\n // This is necessary because Elysia's .trace() callbacks run in a different\n // async context where getActiveSpan() returns undefined. By storing the root\n // span in a WeakMap keyed by the Request object, we can retrieve it in .trace().\n // HigherOrderFunction type is not exported from elysia's main entry point,\n // so we type the callback parameters directly.\n app.wrap((fn: (...args: unknown[]) => unknown, request: Request) => {\n if (isBun()) {\n // On Bun there is no HTTP instrumentation, so we create a root span ourselves.\n // Scope setup must happen inside the returned function so that it's active\n // when Elysia calls the handler (not during .wrap() registration).\n return (...args: unknown[]) => {\n return withIsolationScope(() => {\n return continueTrace(\n {\n sentryTrace: request.headers.get('sentry-trace') || '',\n baggage: request.headers.get('baggage'),\n },\n () => {\n return startSpanManual(\n {\n op: 'http.server',\n name: `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n },\n },\n rootSpan => {\n rootSpanForRequest.set(request, rootSpan);\n try {\n const result = fn(...args);\n if (result instanceof Promise) {\n return result.then(\n res => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return res;\n },\n err => {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n },\n );\n }\n rootSpanForRequest.delete(request);\n rootSpan.end();\n return result;\n } catch (err) {\n rootSpanForRequest.delete(request);\n rootSpan.end();\n throw err;\n }\n },\n );\n },\n );\n });\n };\n }\n\n // On Node.js, the HTTP instrumentation already creates a root span.\n // We just capture its reference so .trace() can use it.\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n rootSpanForRequest.set(request, getRootSpan(activeSpan));\n }\n return fn;\n });\n\n // Use .trace() ONLY for span creation. The trace API is observational —\n // callbacks fire after phases complete, so they can't reliably mutate\n // response headers or capture errors. All SDK logic stays in real hooks.\n const traceHandler: TraceHandler = lifecycle => {\n const rootSpan = rootSpanForRequest.get(lifecycle.context.request);\n\n const phases: [string, TraceListener][] = [\n ['Request', lifecycle.onRequest],\n ['Parse', lifecycle.onParse],\n ['Transform', lifecycle.onTransform],\n ['BeforeHandle', lifecycle.onBeforeHandle],\n ['Handle', lifecycle.onHandle],\n ['AfterHandle', lifecycle.onAfterHandle],\n ['MapResponse', lifecycle.onMapResponse],\n ['AfterResponse', lifecycle.onAfterResponse],\n ['Error', lifecycle.onError],\n ];\n\n for (const [phaseName, listener] of phases) {\n if (listener) {\n instrumentLifecyclePhase(phaseName, listener, rootSpan);\n }\n }\n };\n\n app.trace({ as: 'global' }, traceHandler);\n\n // SDK logic uses real lifecycle hooks — these show up as handler spans\n // in the trace (named sentryOnRequest etc.), but that's the correct\n // tradeoff: the trace API can't reliably mutate state or capture errors.\n\n app.onRequest(function sentryOnRequest(context) {\n getIsolationScope().setSDKProcessingMetadata({\n normalizedRequest: winterCGRequestToRequestData(context.request),\n });\n });\n\n app.onAfterHandle({ as: 'global' }, function sentryOnAfterHandle(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n const traceData = getTraceData();\n if (traceData['sentry-trace']) {\n context.set.headers['sentry-trace'] = traceData['sentry-trace'];\n }\n if (traceData.baggage) {\n context.set.headers['baggage'] = traceData.baggage;\n }\n });\n\n app.onError({ as: 'global' }, function sentryOnError(context) {\n if (context.route) {\n updateRouteTransactionName(context.request, context.request.method, context.route);\n }\n\n // Set error status on root span\n const rootSpan = rootSpanForRequest.get(context.request);\n if (rootSpan) {\n const statusCode = parseInt(String(context.set.status), 10);\n setHttpStatus(rootSpan, Number.isNaN(statusCode) ? 500 : statusCode);\n }\n\n const shouldHandleError = options?.shouldHandleError || defaultShouldHandleError;\n if (shouldHandleError(context)) {\n captureException(context.error, {\n mechanism: {\n type: 'auto.http.elysia.on_error',\n handled: false,\n },\n });\n }\n });\n\n return app;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/elysia",
3
- "version": "10.53.0",
3
+ "version": "10.54.0",
4
4
  "description": "Official Sentry SDK for Elysia",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/elysia",
@@ -39,8 +39,8 @@
39
39
  "access": "public"
40
40
  },
41
41
  "dependencies": {
42
- "@sentry/bun": "10.53.0",
43
- "@sentry/core": "10.53.0"
42
+ "@sentry/bun": "10.54.0",
43
+ "@sentry/core": "10.54.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "elysia": "^1.4.0"