@sentry/elysia 11.0.0-alpha.2 → 11.0.0-beta.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.
@@ -10,8 +10,7 @@ const ELYSIA_LIFECYCLE_OP_MAP = {
10
10
  Parse: op.MIDDLEWARE,
11
11
  Transform: op.MIDDLEWARE,
12
12
  BeforeHandle: op.MIDDLEWARE,
13
- // TODO(conventions): Replace with the `handler` span op constant once it is released in `@sentry/conventions`.
14
- Handle: "handler",
13
+ Handle: op.HANDLER,
15
14
  AfterHandle: op.MIDDLEWARE,
16
15
  MapResponse: op.MIDDLEWARE,
17
16
  AfterResponse: op.MIDDLEWARE,
@@ -54,29 +53,39 @@ function defaultShouldHandleError(context) {
54
53
  }
55
54
  return statusCode >= 500 || statusCode <= 299;
56
55
  }
57
- function instrumentLifecyclePhase(phaseName, listener, rootSpan) {
58
- const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];
59
- if (!op) {
56
+ function instrumentLifecyclePhase(phaseName, listener, rootSpan, context) {
57
+ const op$1 = ELYSIA_LIFECYCLE_OP_MAP[phaseName];
58
+ if (!op$1) {
60
59
  return;
61
60
  }
62
61
  void listener((process) => {
62
+ const client = core.getClient();
63
+ const isRequestHandlerSpan = op$1 === op.HANDLER;
64
+ const isStreamedRequestHandlerSpan = isRequestHandlerSpan && !!client && core.hasSpanStreamingEnabled(client);
65
+ const routeAttribute = isRequestHandlerSpan && context.route ? { [attributes.HTTP_ROUTE]: context.route } : {};
63
66
  const phaseSpan = core.startInactiveSpan({
64
- name: phaseName,
67
+ name: isStreamedRequestHandlerSpan ? context.route || core.REQUEST_HANDLER_SPAN_NAME_FALLBACK : phaseName,
65
68
  parentSpan: rootSpan,
66
69
  attributes: {
67
- [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
68
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
70
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op$1,
71
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
72
+ ...routeAttribute
69
73
  }
70
74
  });
71
75
  if (process.total > 0) {
72
76
  void process.onEvent((child) => {
73
77
  const handlerName = child.name || "anonymous";
74
78
  const childSpan = core.startInactiveSpan({
75
- name: handlerName,
79
+ name: isStreamedRequestHandlerSpan ? context.route || core.REQUEST_HANDLER_SPAN_NAME_FALLBACK : handlerName,
76
80
  parentSpan: phaseSpan,
77
81
  attributes: {
78
- [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
79
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
82
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op$1,
83
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
84
+ ...routeAttribute,
85
+ // Streamed request handler spans are named after the route, so the
86
+ // handler name has no other place to go. Anonymous handlers have no
87
+ // name to record.
88
+ ...isRequestHandlerSpan && child.name ? { [attributes.CODE_FUNCTION_NAME]: child.name } : {}
80
89
  }
81
90
  });
82
91
  void child.onStop(() => {
@@ -107,11 +116,11 @@ function withElysia(app, options = {}) {
107
116
  const client = core.getClient();
108
117
  return core.startSpanManual(
109
118
  {
110
- op: "http.server",
111
119
  // With span streaming, span names have to be low cardinality, so we can't fall back to the
112
120
  // URL path. `updateRouteTransactionName` renames the span once Elysia resolves the route.
113
121
  name: client && core.hasSpanStreamingEnabled(client) ? request.method?.toUpperCase() || core.HTTP_SPAN_NAME_FALLBACK : `${request.method} ${new URL(request.url).pathname}`,
114
122
  attributes: {
123
+ [attributes.SENTRY_OP]: op.HTTP_SERVER,
115
124
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
116
125
  [attributes.SENTRY_SEGMENT_NAME_SOURCE]: "url",
117
126
  [attributes.URL_FULL]: core.filterCollectedUrl(request.url),
@@ -172,7 +181,7 @@ function withElysia(app, options = {}) {
172
181
  ];
173
182
  for (const [phaseName, listener] of phases) {
174
183
  if (listener) {
175
- instrumentLifecyclePhase(phaseName, listener, rootSpan);
184
+ instrumentLifecyclePhase(phaseName, listener, rootSpan, lifecycle.context);
176
185
  }
177
186
  }
178
187
  };
@@ -1 +1 @@
1
- {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import { SENTRY_SEGMENT_NAME_SOURCE, HTTP_ROUTE, URL_FULL, URL_PATH } from '@sentry/conventions/attributes';\nimport { MIDDLEWARE } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n filterCollectedUrl,\n hasSpanStreamingEnabled,\n HTTP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport type { AnyElysia, 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,\n Parse: MIDDLEWARE,\n Transform: MIDDLEWARE,\n BeforeHandle: MIDDLEWARE,\n // TODO(conventions): Replace with the `handler` span op constant once it is released in `@sentry/conventions`.\n Handle: 'handler',\n AfterHandle: MIDDLEWARE,\n MapResponse: MIDDLEWARE,\n AfterResponse: MIDDLEWARE,\n Error: MIDDLEWARE,\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 function applyRouteToSpan(span: Span): void {\n updateSpanName(span, transactionName);\n span.setAttributes({\n [SENTRY_SEGMENT_NAME_SOURCE]: 'route',\n [HTTP_ROUTE]: route,\n });\n }\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 applyRouteToSpan(rootSpan);\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n applyRouteToSpan(root);\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 */\n// Using the AnyElysia type here to allow users to pass in the full set of Elysia\n// options without type errors. The `T extends Elysia` type is too narrow to allow\n// users to pass in dynamic options like `prefix` without breaking the type system.\n// See Elysia type definition and its usage of `const in out` which forces the string\n// template literals to be fully consistent for e.g. `prefix`.\nexport function withElysia<T extends AnyElysia>(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 const client = getClient();\n return startSpanManual(\n {\n op: 'http.server',\n // With span streaming, span names have to be low cardinality, so we can't fall back to the\n // URL path. `updateRouteTransactionName` renames the span once Elysia resolves the route.\n name:\n client && hasSpanStreamingEnabled(client)\n ? request.method?.toUpperCase() || HTTP_SPAN_NAME_FALLBACK\n : `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [URL_FULL]: filterCollectedUrl(request.url),\n [URL_PATH]: new URL(request.url).pathname,\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 // The app is typed as `AnyElysia`, whose `Singleton` is `any`; `.trace()` expects the handler's\n // singleton to match, and `TraceHandler`'s generics are invariant, so the annotation has to use `any` too.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const traceHandler: TraceHandler<{}, any> = 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 // Cast from AnyElysia to Elysia so that onAfterHandle/onError callback\n // parameters resolve to typed contexts (e.g. ErrorContext for shouldHandleError).\n // `AnyElysia` is needed on the user-facing `app` type to accept user instances with\n // arbitrary generic args.\n // The cast is safe because AnyElysia IS Elysia<any, any, ...>.\n const elysiaApp = app as unknown as Elysia;\n\n elysiaApp.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 elysiaApp.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":["MIDDLEWARE","updateSpanName","SENTRY_SEGMENT_NAME_SOURCE","HTTP_ROUTE","getActiveSpan","getRootSpan","getIsolationScope","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","withIsolationScope","continueTrace","getClient","startSpanManual","hasSpanStreamingEnabled","HTTP_SPAN_NAME_FALLBACK","URL_FULL","filterCollectedUrl","URL_PATH","winterCGRequestToRequestData","getTraceData","setHttpStatus","captureException"],"mappings":"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"}
1
+ {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import {\n CODE_FUNCTION_NAME,\n HTTP_ROUTE,\n SENTRY_OP,\n SENTRY_SEGMENT_NAME_SOURCE,\n URL_FULL,\n URL_PATH,\n} from '@sentry/conventions/attributes';\nimport { HANDLER, HTTP_SERVER, MIDDLEWARE } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n hasSpanStreamingEnabled,\n REQUEST_HANDLER_SPAN_NAME_FALLBACK,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n filterCollectedUrl,\n HTTP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport type { AnyElysia, Elysia, ErrorContext, TraceHandler, TraceListener } from 'elysia';\n\n/**\n * The part of Elysia's request context that the lifecycle spans read. Elysia types\n * `.trace()`'s context as an index signature, which a required property would reject.\n */\ninterface LifecycleContext {\n route?: string;\n}\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,\n Parse: MIDDLEWARE,\n Transform: MIDDLEWARE,\n BeforeHandle: MIDDLEWARE,\n Handle: HANDLER,\n AfterHandle: MIDDLEWARE,\n MapResponse: MIDDLEWARE,\n AfterResponse: MIDDLEWARE,\n Error: MIDDLEWARE,\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 function applyRouteToSpan(span: Span): void {\n updateSpanName(span, transactionName);\n span.setAttributes({\n [SENTRY_SEGMENT_NAME_SOURCE]: 'route',\n [HTTP_ROUTE]: route,\n });\n }\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 applyRouteToSpan(rootSpan);\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n applyRouteToSpan(root);\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 * @param context - The request context. Read `route` off it inside the listener:\n * Elysia assigns the route when the request enters the compiled handler, which\n * is after `.trace()` hands out its listeners.\n */\nfunction instrumentLifecyclePhase(\n phaseName: string,\n listener: TraceListener,\n rootSpan: Span | undefined,\n context: LifecycleContext,\n): void {\n const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];\n if (!op) {\n return;\n }\n\n void listener(process => {\n const client = getClient();\n const isRequestHandlerSpan = op === HANDLER;\n // With span streaming, span names have to be low cardinality, so request handler\n // spans are named after their route.\n const isStreamedRequestHandlerSpan = isRequestHandlerSpan && !!client && hasSpanStreamingEnabled(client);\n // The route describes the span in both trace lifecycles, and the other server\n // integrations put it on their request handler spans too.\n const routeAttribute = isRequestHandlerSpan && context.route ? { [HTTP_ROUTE]: context.route } : {};\n\n const phaseSpan = startInactiveSpan({\n name: isStreamedRequestHandlerSpan ? context.route || REQUEST_HANDLER_SPAN_NAME_FALLBACK : phaseName,\n parentSpan: rootSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n ...routeAttribute,\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: isStreamedRequestHandlerSpan ? context.route || REQUEST_HANDLER_SPAN_NAME_FALLBACK : handlerName,\n parentSpan: phaseSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n ...routeAttribute,\n // Streamed request handler spans are named after the route, so the\n // handler name has no other place to go. Anonymous handlers have no\n // name to record.\n ...(isRequestHandlerSpan && child.name ? { [CODE_FUNCTION_NAME]: child.name } : {}),\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 */\n// Using the AnyElysia type here to allow users to pass in the full set of Elysia\n// options without type errors. The `T extends Elysia` type is too narrow to allow\n// users to pass in dynamic options like `prefix` without breaking the type system.\n// See Elysia type definition and its usage of `const in out` which forces the string\n// template literals to be fully consistent for e.g. `prefix`.\nexport function withElysia<T extends AnyElysia>(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 const client = getClient();\n return startSpanManual(\n {\n // With span streaming, span names have to be low cardinality, so we can't fall back to the\n // URL path. `updateRouteTransactionName` renames the span once Elysia resolves the route.\n name:\n client && hasSpanStreamingEnabled(client)\n ? request.method?.toUpperCase() || HTTP_SPAN_NAME_FALLBACK\n : `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SENTRY_OP]: HTTP_SERVER,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [URL_FULL]: filterCollectedUrl(request.url),\n [URL_PATH]: new URL(request.url).pathname,\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 // The app is typed as `AnyElysia`, whose `Singleton` is `any`; `.trace()` expects the handler's\n // singleton to match, and `TraceHandler`'s generics are invariant, so the annotation has to use `any` too.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const traceHandler: TraceHandler<{}, any> = 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, lifecycle.context);\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 // Cast from AnyElysia to Elysia so that onAfterHandle/onError callback\n // parameters resolve to typed contexts (e.g. ErrorContext for shouldHandleError).\n // `AnyElysia` is needed on the user-facing `app` type to accept user instances with\n // arbitrary generic args.\n // The cast is safe because AnyElysia IS Elysia<any, any, ...>.\n const elysiaApp = app as unknown as Elysia;\n\n elysiaApp.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 elysiaApp.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":["MIDDLEWARE","HANDLER","updateSpanName","SENTRY_SEGMENT_NAME_SOURCE","HTTP_ROUTE","getActiveSpan","getRootSpan","getIsolationScope","op","getClient","hasSpanStreamingEnabled","startInactiveSpan","REQUEST_HANDLER_SPAN_NAME_FALLBACK","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","CODE_FUNCTION_NAME","withIsolationScope","continueTrace","startSpanManual","HTTP_SPAN_NAME_FALLBACK","SENTRY_OP","HTTP_SERVER","URL_FULL","filterCollectedUrl","URL_PATH","winterCGRequestToRequestData","getTraceData","setHttpStatus","captureException"],"mappings":"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"}
@@ -1 +1 @@
1
- {"type":"module","version":"11.0.0-alpha.2","sideEffects":false}
1
+ {"type":"module","version":"11.0.0-beta.0","sideEffects":false}
@@ -1,6 +1,6 @@
1
- import { URL_PATH, URL_FULL, SENTRY_SEGMENT_NAME_SOURCE, HTTP_ROUTE } from '@sentry/conventions/attributes';
2
- import { MIDDLEWARE } from '@sentry/conventions/op';
3
- import { withIsolationScope, continueTrace, getClient, startSpanManual, HTTP_SPAN_NAME_FALLBACK, filterCollectedUrl, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, hasSpanStreamingEnabled, getActiveSpan, getRootSpan, getIsolationScope, winterCGRequestToRequestData, getTraceData, setHttpStatus, captureException, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, updateSpanName } from '@sentry/core';
1
+ import { URL_PATH, URL_FULL, SENTRY_SEGMENT_NAME_SOURCE, SENTRY_OP, HTTP_ROUTE, CODE_FUNCTION_NAME } from '@sentry/conventions/attributes';
2
+ import { HTTP_SERVER, MIDDLEWARE, HANDLER } from '@sentry/conventions/op';
3
+ import { withIsolationScope, continueTrace, getClient, startSpanManual, HTTP_SPAN_NAME_FALLBACK, filterCollectedUrl, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, hasSpanStreamingEnabled, getActiveSpan, getRootSpan, getIsolationScope, winterCGRequestToRequestData, getTraceData, setHttpStatus, captureException, startInactiveSpan, REQUEST_HANDLER_SPAN_NAME_FALLBACK, SEMANTIC_ATTRIBUTE_SENTRY_OP, updateSpanName } from '@sentry/core';
4
4
 
5
5
  const ELYSIA_ORIGIN = "auto.http.elysia";
6
6
  const ELYSIA_LIFECYCLE_OP_MAP = {
@@ -8,8 +8,7 @@ const ELYSIA_LIFECYCLE_OP_MAP = {
8
8
  Parse: MIDDLEWARE,
9
9
  Transform: MIDDLEWARE,
10
10
  BeforeHandle: MIDDLEWARE,
11
- // TODO(conventions): Replace with the `handler` span op constant once it is released in `@sentry/conventions`.
12
- Handle: "handler",
11
+ Handle: HANDLER,
13
12
  AfterHandle: MIDDLEWARE,
14
13
  MapResponse: MIDDLEWARE,
15
14
  AfterResponse: MIDDLEWARE,
@@ -52,29 +51,39 @@ function defaultShouldHandleError(context) {
52
51
  }
53
52
  return statusCode >= 500 || statusCode <= 299;
54
53
  }
55
- function instrumentLifecyclePhase(phaseName, listener, rootSpan) {
54
+ function instrumentLifecyclePhase(phaseName, listener, rootSpan, context) {
56
55
  const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];
57
56
  if (!op) {
58
57
  return;
59
58
  }
60
59
  void listener((process) => {
60
+ const client = getClient();
61
+ const isRequestHandlerSpan = op === HANDLER;
62
+ const isStreamedRequestHandlerSpan = isRequestHandlerSpan && !!client && hasSpanStreamingEnabled(client);
63
+ const routeAttribute = isRequestHandlerSpan && context.route ? { [HTTP_ROUTE]: context.route } : {};
61
64
  const phaseSpan = startInactiveSpan({
62
- name: phaseName,
65
+ name: isStreamedRequestHandlerSpan ? context.route || REQUEST_HANDLER_SPAN_NAME_FALLBACK : phaseName,
63
66
  parentSpan: rootSpan,
64
67
  attributes: {
65
68
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
66
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
69
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
70
+ ...routeAttribute
67
71
  }
68
72
  });
69
73
  if (process.total > 0) {
70
74
  void process.onEvent((child) => {
71
75
  const handlerName = child.name || "anonymous";
72
76
  const childSpan = startInactiveSpan({
73
- name: handlerName,
77
+ name: isStreamedRequestHandlerSpan ? context.route || REQUEST_HANDLER_SPAN_NAME_FALLBACK : handlerName,
74
78
  parentSpan: phaseSpan,
75
79
  attributes: {
76
80
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
77
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN
81
+ [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
82
+ ...routeAttribute,
83
+ // Streamed request handler spans are named after the route, so the
84
+ // handler name has no other place to go. Anonymous handlers have no
85
+ // name to record.
86
+ ...isRequestHandlerSpan && child.name ? { [CODE_FUNCTION_NAME]: child.name } : {}
78
87
  }
79
88
  });
80
89
  void child.onStop(() => {
@@ -105,11 +114,11 @@ function withElysia(app, options = {}) {
105
114
  const client = getClient();
106
115
  return startSpanManual(
107
116
  {
108
- op: "http.server",
109
117
  // With span streaming, span names have to be low cardinality, so we can't fall back to the
110
118
  // URL path. `updateRouteTransactionName` renames the span once Elysia resolves the route.
111
119
  name: client && hasSpanStreamingEnabled(client) ? request.method?.toUpperCase() || HTTP_SPAN_NAME_FALLBACK : `${request.method} ${new URL(request.url).pathname}`,
112
120
  attributes: {
121
+ [SENTRY_OP]: HTTP_SERVER,
113
122
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,
114
123
  [SENTRY_SEGMENT_NAME_SOURCE]: "url",
115
124
  [URL_FULL]: filterCollectedUrl(request.url),
@@ -170,7 +179,7 @@ function withElysia(app, options = {}) {
170
179
  ];
171
180
  for (const [phaseName, listener] of phases) {
172
181
  if (listener) {
173
- instrumentLifecyclePhase(phaseName, listener, rootSpan);
182
+ instrumentLifecyclePhase(phaseName, listener, rootSpan, lifecycle.context);
174
183
  }
175
184
  }
176
185
  };
@@ -1 +1 @@
1
- {"version":3,"file":"withElysia.js","sources":["../../src/withElysia.ts"],"sourcesContent":["import { SENTRY_SEGMENT_NAME_SOURCE, HTTP_ROUTE, URL_FULL, URL_PATH } from '@sentry/conventions/attributes';\nimport { MIDDLEWARE } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n filterCollectedUrl,\n hasSpanStreamingEnabled,\n HTTP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport type { AnyElysia, 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,\n Parse: MIDDLEWARE,\n Transform: MIDDLEWARE,\n BeforeHandle: MIDDLEWARE,\n // TODO(conventions): Replace with the `handler` span op constant once it is released in `@sentry/conventions`.\n Handle: 'handler',\n AfterHandle: MIDDLEWARE,\n MapResponse: MIDDLEWARE,\n AfterResponse: MIDDLEWARE,\n Error: MIDDLEWARE,\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 function applyRouteToSpan(span: Span): void {\n updateSpanName(span, transactionName);\n span.setAttributes({\n [SENTRY_SEGMENT_NAME_SOURCE]: 'route',\n [HTTP_ROUTE]: route,\n });\n }\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 applyRouteToSpan(rootSpan);\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n applyRouteToSpan(root);\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 */\n// Using the AnyElysia type here to allow users to pass in the full set of Elysia\n// options without type errors. The `T extends Elysia` type is too narrow to allow\n// users to pass in dynamic options like `prefix` without breaking the type system.\n// See Elysia type definition and its usage of `const in out` which forces the string\n// template literals to be fully consistent for e.g. `prefix`.\nexport function withElysia<T extends AnyElysia>(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 const client = getClient();\n return startSpanManual(\n {\n op: 'http.server',\n // With span streaming, span names have to be low cardinality, so we can't fall back to the\n // URL path. `updateRouteTransactionName` renames the span once Elysia resolves the route.\n name:\n client && hasSpanStreamingEnabled(client)\n ? request.method?.toUpperCase() || HTTP_SPAN_NAME_FALLBACK\n : `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [URL_FULL]: filterCollectedUrl(request.url),\n [URL_PATH]: new URL(request.url).pathname,\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 // The app is typed as `AnyElysia`, whose `Singleton` is `any`; `.trace()` expects the handler's\n // singleton to match, and `TraceHandler`'s generics are invariant, so the annotation has to use `any` too.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const traceHandler: TraceHandler<{}, any> = 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 // Cast from AnyElysia to Elysia so that onAfterHandle/onError callback\n // parameters resolve to typed contexts (e.g. ErrorContext for shouldHandleError).\n // `AnyElysia` is needed on the user-facing `app` type to accept user instances with\n // arbitrary generic args.\n // The cast is safe because AnyElysia IS Elysia<any, any, ...>.\n const elysiaApp = app as unknown as Elysia;\n\n elysiaApp.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 elysiaApp.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 {\n CODE_FUNCTION_NAME,\n HTTP_ROUTE,\n SENTRY_OP,\n SENTRY_SEGMENT_NAME_SOURCE,\n URL_FULL,\n URL_PATH,\n} from '@sentry/conventions/attributes';\nimport { HANDLER, HTTP_SERVER, MIDDLEWARE } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getActiveSpan,\n getClient,\n getIsolationScope,\n getRootSpan,\n getTraceData,\n hasSpanStreamingEnabled,\n REQUEST_HANDLER_SPAN_NAME_FALLBACK,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n setHttpStatus,\n startInactiveSpan,\n startSpanManual,\n updateSpanName,\n winterCGRequestToRequestData,\n withIsolationScope,\n filterCollectedUrl,\n HTTP_SPAN_NAME_FALLBACK,\n} from '@sentry/core';\nimport type { AnyElysia, Elysia, ErrorContext, TraceHandler, TraceListener } from 'elysia';\n\n/**\n * The part of Elysia's request context that the lifecycle spans read. Elysia types\n * `.trace()`'s context as an index signature, which a required property would reject.\n */\ninterface LifecycleContext {\n route?: string;\n}\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,\n Parse: MIDDLEWARE,\n Transform: MIDDLEWARE,\n BeforeHandle: MIDDLEWARE,\n Handle: HANDLER,\n AfterHandle: MIDDLEWARE,\n MapResponse: MIDDLEWARE,\n AfterResponse: MIDDLEWARE,\n Error: MIDDLEWARE,\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 function applyRouteToSpan(span: Span): void {\n updateSpanName(span, transactionName);\n span.setAttributes({\n [SENTRY_SEGMENT_NAME_SOURCE]: 'route',\n [HTTP_ROUTE]: route,\n });\n }\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 applyRouteToSpan(rootSpan);\n } else {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const root = getRootSpan(activeSpan);\n applyRouteToSpan(root);\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 * @param context - The request context. Read `route` off it inside the listener:\n * Elysia assigns the route when the request enters the compiled handler, which\n * is after `.trace()` hands out its listeners.\n */\nfunction instrumentLifecyclePhase(\n phaseName: string,\n listener: TraceListener,\n rootSpan: Span | undefined,\n context: LifecycleContext,\n): void {\n const op = ELYSIA_LIFECYCLE_OP_MAP[phaseName];\n if (!op) {\n return;\n }\n\n void listener(process => {\n const client = getClient();\n const isRequestHandlerSpan = op === HANDLER;\n // With span streaming, span names have to be low cardinality, so request handler\n // spans are named after their route.\n const isStreamedRequestHandlerSpan = isRequestHandlerSpan && !!client && hasSpanStreamingEnabled(client);\n // The route describes the span in both trace lifecycles, and the other server\n // integrations put it on their request handler spans too.\n const routeAttribute = isRequestHandlerSpan && context.route ? { [HTTP_ROUTE]: context.route } : {};\n\n const phaseSpan = startInactiveSpan({\n name: isStreamedRequestHandlerSpan ? context.route || REQUEST_HANDLER_SPAN_NAME_FALLBACK : phaseName,\n parentSpan: rootSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n ...routeAttribute,\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: isStreamedRequestHandlerSpan ? context.route || REQUEST_HANDLER_SPAN_NAME_FALLBACK : handlerName,\n parentSpan: phaseSpan,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n ...routeAttribute,\n // Streamed request handler spans are named after the route, so the\n // handler name has no other place to go. Anonymous handlers have no\n // name to record.\n ...(isRequestHandlerSpan && child.name ? { [CODE_FUNCTION_NAME]: child.name } : {}),\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 */\n// Using the AnyElysia type here to allow users to pass in the full set of Elysia\n// options without type errors. The `T extends Elysia` type is too narrow to allow\n// users to pass in dynamic options like `prefix` without breaking the type system.\n// See Elysia type definition and its usage of `const in out` which forces the string\n// template literals to be fully consistent for e.g. `prefix`.\nexport function withElysia<T extends AnyElysia>(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 const client = getClient();\n return startSpanManual(\n {\n // With span streaming, span names have to be low cardinality, so we can't fall back to the\n // URL path. `updateRouteTransactionName` renames the span once Elysia resolves the route.\n name:\n client && hasSpanStreamingEnabled(client)\n ? request.method?.toUpperCase() || HTTP_SPAN_NAME_FALLBACK\n : `${request.method} ${new URL(request.url).pathname}`,\n attributes: {\n [SENTRY_OP]: HTTP_SERVER,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ELYSIA_ORIGIN,\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [URL_FULL]: filterCollectedUrl(request.url),\n [URL_PATH]: new URL(request.url).pathname,\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 // The app is typed as `AnyElysia`, whose `Singleton` is `any`; `.trace()` expects the handler's\n // singleton to match, and `TraceHandler`'s generics are invariant, so the annotation has to use `any` too.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const traceHandler: TraceHandler<{}, any> = 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, lifecycle.context);\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 // Cast from AnyElysia to Elysia so that onAfterHandle/onError callback\n // parameters resolve to typed contexts (e.g. ErrorContext for shouldHandleError).\n // `AnyElysia` is needed on the user-facing `app` type to accept user instances with\n // arbitrary generic args.\n // The cast is safe because AnyElysia IS Elysia<any, any, ...>.\n const elysiaApp = app as unknown as Elysia;\n\n elysiaApp.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 elysiaApp.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 +1 @@
1
- {"version":3,"file":"withElysia.d.ts","sourceRoot":"","sources":["../../src/withElysia.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,SAAS,EAAU,YAAY,EAA+B,MAAM,QAAQ,CAAC;AAE3F,UAAU,oBAAoB;IAC5B,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC;CACxD;AAgID;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,GAAE,oBAAyB,GAAG,CAAC,CA0K7F"}
1
+ {"version":3,"file":"withElysia.d.ts","sourceRoot":"","sources":["../../src/withElysia.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,SAAS,EAAU,YAAY,EAA+B,MAAM,QAAQ,CAAC;AAU3F,UAAU,oBAAoB;IAC5B,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,OAAO,CAAC;CACxD;AAsJD;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,GAAE,oBAAyB,GAAG,CAAC,CA0K7F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/elysia",
3
- "version": "11.0.0-alpha.2",
3
+ "version": "11.0.0-beta.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",
@@ -32,8 +32,8 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@sentry/bun": "11.0.0-alpha.2",
36
- "@sentry/core": "11.0.0-alpha.2",
35
+ "@sentry/bun": "11.0.0-beta.0",
36
+ "@sentry/core": "11.0.0-beta.0",
37
37
  "@sentry/conventions": "^0.20.0"
38
38
  },
39
39
  "peerDependencies": {