@sentry/cloudflare 10.47.0 → 10.48.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.
Files changed (92) hide show
  1. package/build/cjs/durableobject.js +29 -11
  2. package/build/cjs/durableobject.js.map +1 -1
  3. package/build/cjs/index.js +2 -0
  4. package/build/cjs/index.js.map +1 -1
  5. package/build/cjs/instrument.js +72 -8
  6. package/build/cjs/instrument.js.map +1 -1
  7. package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js +101 -0
  8. package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -0
  9. package/build/cjs/instrumentations/worker/instrumentEmail.js +14 -12
  10. package/build/cjs/instrumentations/worker/instrumentEmail.js.map +1 -1
  11. package/build/cjs/instrumentations/worker/instrumentFetch.js +35 -10
  12. package/build/cjs/instrumentations/worker/instrumentFetch.js.map +1 -1
  13. package/build/cjs/instrumentations/worker/instrumentQueue.js +35 -10
  14. package/build/cjs/instrumentations/worker/instrumentQueue.js.map +1 -1
  15. package/build/cjs/instrumentations/worker/instrumentScheduled.js +35 -13
  16. package/build/cjs/instrumentations/worker/instrumentScheduled.js.map +1 -1
  17. package/build/cjs/instrumentations/worker/instrumentTail.js +33 -10
  18. package/build/cjs/instrumentations/worker/instrumentTail.js.map +1 -1
  19. package/build/cjs/request.js +5 -6
  20. package/build/cjs/request.js.map +1 -1
  21. package/build/cjs/scope-utils.js.map +1 -1
  22. package/build/cjs/utils/isCloudflareClass.js +29 -0
  23. package/build/cjs/utils/isCloudflareClass.js.map +1 -0
  24. package/build/cjs/withSentry.js +31 -20
  25. package/build/cjs/withSentry.js.map +1 -1
  26. package/build/cjs/wrapMethodWithSentry.js +111 -111
  27. package/build/cjs/wrapMethodWithSentry.js.map +1 -1
  28. package/build/esm/durableobject.js +30 -12
  29. package/build/esm/durableobject.js.map +1 -1
  30. package/build/esm/index.js +1 -1
  31. package/build/esm/instrument.js +71 -8
  32. package/build/esm/instrument.js.map +1 -1
  33. package/build/esm/instrumentations/instrumentWorkerEntrypoint.js +99 -0
  34. package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -0
  35. package/build/esm/instrumentations/worker/instrumentEmail.js +15 -13
  36. package/build/esm/instrumentations/worker/instrumentEmail.js.map +1 -1
  37. package/build/esm/instrumentations/worker/instrumentFetch.js +36 -12
  38. package/build/esm/instrumentations/worker/instrumentFetch.js.map +1 -1
  39. package/build/esm/instrumentations/worker/instrumentQueue.js +36 -12
  40. package/build/esm/instrumentations/worker/instrumentQueue.js.map +1 -1
  41. package/build/esm/instrumentations/worker/instrumentScheduled.js +36 -15
  42. package/build/esm/instrumentations/worker/instrumentScheduled.js.map +1 -1
  43. package/build/esm/instrumentations/worker/instrumentTail.js +34 -12
  44. package/build/esm/instrumentations/worker/instrumentTail.js.map +1 -1
  45. package/build/esm/package.json +1 -1
  46. package/build/esm/request.js +5 -6
  47. package/build/esm/request.js.map +1 -1
  48. package/build/esm/scope-utils.js.map +1 -1
  49. package/build/esm/utils/isCloudflareClass.js +27 -0
  50. package/build/esm/utils/isCloudflareClass.js.map +1 -0
  51. package/build/esm/withSentry.js +32 -21
  52. package/build/esm/withSentry.js.map +1 -1
  53. package/build/esm/wrapMethodWithSentry.js +107 -107
  54. package/build/esm/wrapMethodWithSentry.js.map +1 -1
  55. package/build/types/durableobject.d.ts.map +1 -1
  56. package/build/types/index.d.ts +1 -1
  57. package/build/types/index.d.ts.map +1 -1
  58. package/build/types/instrument.d.ts +15 -4
  59. package/build/types/instrument.d.ts.map +1 -1
  60. package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts +42 -0
  61. package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts.map +1 -0
  62. package/build/types/instrumentations/worker/instrumentEmail.d.ts +2 -1
  63. package/build/types/instrumentations/worker/instrumentEmail.d.ts.map +1 -1
  64. package/build/types/instrumentations/worker/instrumentFetch.d.ts +6 -1
  65. package/build/types/instrumentations/worker/instrumentFetch.d.ts.map +1 -1
  66. package/build/types/instrumentations/worker/instrumentQueue.d.ts +6 -1
  67. package/build/types/instrumentations/worker/instrumentQueue.d.ts.map +1 -1
  68. package/build/types/instrumentations/worker/instrumentScheduled.d.ts +6 -1
  69. package/build/types/instrumentations/worker/instrumentScheduled.d.ts.map +1 -1
  70. package/build/types/instrumentations/worker/instrumentTail.d.ts +6 -1
  71. package/build/types/instrumentations/worker/instrumentTail.d.ts.map +1 -1
  72. package/build/types/request.d.ts +3 -3
  73. package/build/types/request.d.ts.map +1 -1
  74. package/build/types/scope-utils.d.ts +2 -2
  75. package/build/types/scope-utils.d.ts.map +1 -1
  76. package/build/types/utils/isCloudflareClass.d.ts +30 -0
  77. package/build/types/utils/isCloudflareClass.d.ts.map +1 -0
  78. package/build/types/withSentry.d.ts +3 -2
  79. package/build/types/withSentry.d.ts.map +1 -1
  80. package/build/types-ts3.8/index.d.ts +1 -1
  81. package/build/types-ts3.8/instrument.d.ts +15 -4
  82. package/build/types-ts3.8/instrumentations/instrumentWorkerEntrypoint.d.ts +42 -0
  83. package/build/types-ts3.8/instrumentations/worker/instrumentEmail.d.ts +2 -1
  84. package/build/types-ts3.8/instrumentations/worker/instrumentFetch.d.ts +6 -1
  85. package/build/types-ts3.8/instrumentations/worker/instrumentQueue.d.ts +6 -1
  86. package/build/types-ts3.8/instrumentations/worker/instrumentScheduled.d.ts +6 -1
  87. package/build/types-ts3.8/instrumentations/worker/instrumentTail.d.ts +6 -1
  88. package/build/types-ts3.8/request.d.ts +3 -3
  89. package/build/types-ts3.8/scope-utils.d.ts +2 -2
  90. package/build/types-ts3.8/utils/isCloudflareClass.d.ts +30 -0
  91. package/build/types-ts3.8/withSentry.d.ts +3 -2
  92. package/package.json +2 -2
@@ -8,9 +8,6 @@ const scopeUtils = require('../../scope-utils.js');
8
8
  const sdk = require('../../sdk.js');
9
9
  const instrumentContext = require('../../utils/instrumentContext.js');
10
10
 
11
- /**
12
- * Core scheduled handler logic - wraps execution with Sentry instrumentation.
13
- */
14
11
  function wrapScheduledHandler(
15
12
  controller,
16
13
  options,
@@ -59,24 +56,49 @@ function instrumentExportedHandlerScheduled(
59
56
  handler,
60
57
  optionsCallback,
61
58
  ) {
62
- if (!('scheduled' in handler) || typeof handler.scheduled !== 'function' || instrument.isInstrumented(handler.scheduled)) {
59
+ if (!('scheduled' in handler) || typeof handler.scheduled !== 'function') {
63
60
  return;
64
61
  }
65
62
 
66
- handler.scheduled = new Proxy(handler.scheduled, {
67
- apply(target, thisArg, args) {
68
- const [controller, env, ctx] = args;
69
- const context = instrumentContext.instrumentContext(ctx);
70
- args[2] = context;
63
+ handler.scheduled = instrument.ensureInstrumented(
64
+ handler.scheduled,
65
+ original =>
66
+ new Proxy(original, {
67
+ apply(target, thisArg, args) {
68
+ const [controller, env, ctx] = args;
69
+ const context = instrumentContext.instrumentContext(ctx);
70
+ args[2] = context;
71
71
 
72
- const options$1 = options.getFinalOptions(optionsCallback(env), env);
72
+ const options$1 = options.getFinalOptions(optionsCallback(env), env);
73
73
 
74
- return wrapScheduledHandler(controller, options$1, context, () => target.apply(thisArg, args));
74
+ return wrapScheduledHandler(controller, options$1, context, () => target.apply(thisArg, args));
75
+ },
76
+ }),
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Instruments a scheduled method for WorkerEntrypoint (options/context already available).
82
+ */
83
+ function instrumentWorkerEntrypointScheduled(
84
+ instance,
85
+ options,
86
+ context,
87
+ ) {
88
+ if (!instance.scheduled) {
89
+ return;
90
+ }
91
+
92
+ const original = instance.scheduled.bind(instance);
93
+ instance.scheduled = new Proxy(original, {
94
+ apply(target, thisArg, args) {
95
+ const [controller] = args;
96
+
97
+ return wrapScheduledHandler(controller, options, context, () => Reflect.apply(target, thisArg, args));
75
98
  },
76
99
  });
77
-
78
- instrument.markAsInstrumented(handler.scheduled);
79
100
  }
80
101
 
81
102
  exports.instrumentExportedHandlerScheduled = instrumentExportedHandlerScheduled;
103
+ exports.instrumentWorkerEntrypointScheduled = instrumentWorkerEntrypointScheduled;
82
104
  //# sourceMappingURL=instrumentScheduled.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentScheduled.js","sources":["../../../../src/instrumentations/worker/instrumentScheduled.ts"],"sourcesContent":["import type { ExportedHandler, ScheduledController } from '@cloudflare/workers-types';\nimport {\n captureException,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n withIsolationScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { flushAndDispose } from '../../flush';\nimport { isInstrumented, markAsInstrumented } from '../../instrument';\nimport { getFinalOptions } from '../../options';\nimport { addCloudResourceContext } from '../../scope-utils';\nimport { init } from '../../sdk';\nimport { instrumentContext } from '../../utils/instrumentContext';\n\n/**\n * Core scheduled handler logic - wraps execution with Sentry instrumentation.\n */\nfunction wrapScheduledHandler(\n controller: ScheduledController,\n options: CloudflareOptions,\n context: ExecutionContext,\n fn: () => unknown,\n): unknown {\n return withIsolationScope(isolationScope => {\n const waitUntil = context.waitUntil.bind(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return startSpan(\n {\n op: 'faas.cron',\n name: `Scheduled Cron ${controller.cron}`,\n attributes: {\n 'faas.cron': controller.cron,\n 'faas.time': new Date(controller.scheduledTime).toISOString(),\n 'faas.trigger': 'timer',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.scheduled',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task',\n },\n },\n async () => {\n try {\n return await fn();\n } catch (e) {\n captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' } });\n throw e;\n } finally {\n waitUntil(flushAndDispose(client));\n }\n },\n );\n });\n}\n\n/**\n * Instruments a scheduled handler for ExportedHandler (env/ctx come from args).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function instrumentExportedHandlerScheduled<T extends ExportedHandler<any, any, any>>(\n handler: T,\n optionsCallback: (env: Parameters<NonNullable<T['scheduled']>>[1]) => CloudflareOptions | undefined,\n): void {\n if (!('scheduled' in handler) || typeof handler.scheduled !== 'function' || isInstrumented(handler.scheduled)) {\n return;\n }\n\n handler.scheduled = new Proxy(handler.scheduled, {\n apply(target, thisArg, args: Parameters<NonNullable<T['scheduled']>>) {\n const [controller, env, ctx] = args;\n const context = instrumentContext(ctx);\n args[2] = context;\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n return wrapScheduledHandler(controller, options, context, () => target.apply(thisArg, args));\n },\n });\n\n markAsInstrumented(handler.scheduled);\n}\n"],"names":["withIsolationScope","init","addCloudResourceContext","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","captureException","flushAndDispose","isInstrumented","instrumentContext","options","getFinalOptions","markAsInstrumented"],"mappings":";;;;;;;;;;AAgBA;AACA;AACA;AACA,SAAS,oBAAoB;AAC7B,EAAE,UAAU;AACZ,EAAE,OAAO;AACT,EAAE,OAAO;AACT,EAAE,EAAE;AACJ,EAAW;AACX,EAAE,OAAOA,uBAAkB,CAAC,cAAA,IAAkB;AAC9C,IAAI,MAAM,SAAA,GAAY,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;;AAErD,IAAI,MAAM,MAAA,GAASC,QAAI,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,OAAA,EAAS,CAAC;AACrD,IAAI,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;;AAEpC,IAAIC,kCAAuB,CAAC,cAAc,CAAC;;AAE3C,IAAI,OAAOC,cAAS;AACpB,MAAM;AACN,QAAQ,EAAE,EAAE,WAAW;AACvB,QAAQ,IAAI,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC,IAAI,CAAC,CAAA;AACA,QAAA,UAAA,EAAA;AACA,UAAA,WAAA,EAAA,UAAA,CAAA,IAAA;AACA,UAAA,WAAA,EAAA,IAAA,IAAA,CAAA,UAAA,CAAA,aAAA,CAAA,CAAA,WAAA,EAAA;AACA,UAAA,cAAA,EAAA,OAAA;AACA,UAAA,CAAAC,qCAAA,GAAA,gCAAA;AACA,UAAA,CAAAC,qCAAA,GAAA,MAAA;AACA,SAAA;AACA,OAAA;AACA,MAAA,YAAA;AACA,QAAA,IAAA;AACA,UAAA,OAAA,MAAA,EAAA,EAAA;AACA,QAAA,CAAA,CAAA,OAAA,CAAA,EAAA;AACA,UAAAC,qBAAA,CAAA,CAAA,EAAA,EAAA,SAAA,EAAA,EAAA,OAAA,EAAA,KAAA,EAAA,IAAA,EAAA,gCAAA,EAAA,EAAA,CAAA;AACA,UAAA,MAAA,CAAA;AACA,QAAA,CAAA,SAAA;AACA,UAAA,SAAA,CAAAC,qBAAA,CAAA,MAAA,CAAA,CAAA;AACA,QAAA;AACA,MAAA,CAAA;AACA,KAAA;AACA,EAAA,CAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAA,kCAAA;AACA,EAAA,OAAA;AACA,EAAA,eAAA;AACA,EAAA;AACA,EAAA,IAAA,EAAA,WAAA,IAAA,OAAA,CAAA,IAAA,OAAA,OAAA,CAAA,SAAA,KAAA,UAAA,IAAAC,yBAAA,CAAA,OAAA,CAAA,SAAA,CAAA,EAAA;AACA,IAAA;AACA,EAAA;;AAEA,EAAA,OAAA,CAAA,SAAA,GAAA,IAAA,KAAA,CAAA,OAAA,CAAA,SAAA,EAAA;AACA,IAAA,KAAA,CAAA,MAAA,EAAA,OAAA,EAAA,IAAA,EAAA;AACA,MAAA,MAAA,CAAA,UAAA,EAAA,GAAA,EAAA,GAAA,CAAA,GAAA,IAAA;AACA,MAAA,MAAA,OAAA,GAAAC,mCAAA,CAAA,GAAA,CAAA;AACA,MAAA,IAAA,CAAA,CAAA,CAAA,GAAA,OAAA;;AAEA,MAAA,MAAAC,SAAA,GAAAC,uBAAA,CAAA,eAAA,CAAA,GAAA,CAAA,EAAA,GAAA,CAAA;;AAEA,MAAA,OAAA,oBAAA,CAAA,UAAA,EAAAD,SAAA,EAAA,OAAA,EAAA,MAAA,MAAA,CAAA,KAAA,CAAA,OAAA,EAAA,IAAA,CAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;;AAEA,EAAAE,6BAAA,CAAA,OAAA,CAAA,SAAA,CAAA;AACA;;;;"}
1
+ {"version":3,"file":"instrumentScheduled.js","sources":["../../../../src/instrumentations/worker/instrumentScheduled.ts"],"sourcesContent":["import type { ExportedHandler, ScheduledController } from '@cloudflare/workers-types';\nimport type { env as cloudflareEnv, WorkerEntrypoint } from 'cloudflare:workers';\nimport {\n captureException,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n withIsolationScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { flushAndDispose } from '../../flush';\nimport { ensureInstrumented } from '../../instrument';\nimport { getFinalOptions } from '../../options';\nimport { addCloudResourceContext } from '../../scope-utils';\nimport { init } from '../../sdk';\nimport { instrumentContext } from '../../utils/instrumentContext';\n\nfunction wrapScheduledHandler(\n controller: ScheduledController,\n options: CloudflareOptions,\n context: ExecutionContext,\n fn: () => unknown,\n): unknown {\n return withIsolationScope(isolationScope => {\n const waitUntil = context.waitUntil.bind(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return startSpan(\n {\n op: 'faas.cron',\n name: `Scheduled Cron ${controller.cron}`,\n attributes: {\n 'faas.cron': controller.cron,\n 'faas.time': new Date(controller.scheduledTime).toISOString(),\n 'faas.trigger': 'timer',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.scheduled',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task',\n },\n },\n async () => {\n try {\n return await fn();\n } catch (e) {\n captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' } });\n throw e;\n } finally {\n waitUntil(flushAndDispose(client));\n }\n },\n );\n });\n}\n\n/**\n * Instruments a scheduled handler for ExportedHandler (env/ctx come from args).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function instrumentExportedHandlerScheduled<T extends ExportedHandler<any, any, any>>(\n handler: T,\n optionsCallback: (env: typeof cloudflareEnv) => CloudflareOptions | undefined,\n): void {\n if (!('scheduled' in handler) || typeof handler.scheduled !== 'function') {\n return;\n }\n\n handler.scheduled = ensureInstrumented(\n handler.scheduled,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args: Parameters<NonNullable<T['scheduled']>>) {\n const [controller, env, ctx] = args;\n const context = instrumentContext(ctx);\n args[2] = context;\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n return wrapScheduledHandler(controller, options, context, () => target.apply(thisArg, args));\n },\n }),\n );\n}\n\n/**\n * Instruments a scheduled method for WorkerEntrypoint (options/context already available).\n */\nexport function instrumentWorkerEntrypointScheduled<T extends WorkerEntrypoint>(\n instance: T,\n options: CloudflareOptions,\n context: ExecutionContext,\n): void {\n if (!instance.scheduled) {\n return;\n }\n\n const original = instance.scheduled.bind(instance);\n instance.scheduled = new Proxy(original, {\n apply(target, thisArg, args: [ScheduledController]) {\n const [controller] = args;\n\n return wrapScheduledHandler(controller, options, context, () => Reflect.apply(target, thisArg, args));\n },\n });\n}\n"],"names":["withIsolationScope","init","addCloudResourceContext","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","captureException","flushAndDispose","ensureInstrumented","instrumentContext","options","getFinalOptions"],"mappings":"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"}
@@ -40,24 +40,47 @@ function instrumentExportedHandlerTail(
40
40
  handler,
41
41
  optionsCallback,
42
42
  ) {
43
- if (!('tail' in handler) || typeof handler.tail !== 'function' || instrument.isInstrumented(handler.tail)) {
43
+ if (!('tail' in handler) || typeof handler.tail !== 'function') {
44
44
  return;
45
45
  }
46
46
 
47
- handler.tail = new Proxy(handler.tail, {
48
- apply(target, thisArg, args) {
49
- const [, env, ctx] = args;
50
- const context = instrumentContext.instrumentContext(ctx);
51
- args[2] = context;
47
+ handler.tail = instrument.ensureInstrumented(
48
+ handler.tail,
49
+ original =>
50
+ new Proxy(original, {
51
+ apply(target, thisArg, args) {
52
+ const [, env, ctx] = args;
53
+ const context = instrumentContext.instrumentContext(ctx);
54
+ args[2] = context;
55
+
56
+ const options$1 = options.getFinalOptions(optionsCallback(env), env);
52
57
 
53
- const options$1 = options.getFinalOptions(optionsCallback(env), env);
58
+ return wrapTailHandler(options$1, context, () => target.apply(thisArg, args));
59
+ },
60
+ }),
61
+ );
62
+ }
54
63
 
55
- return wrapTailHandler(options$1, context, () => target.apply(thisArg, args));
64
+ /**
65
+ * Instruments a tail method for WorkerEntrypoint (options/context already available).
66
+ */
67
+ function instrumentWorkerEntrypointTail(
68
+ instance,
69
+ options,
70
+ context,
71
+ ) {
72
+ if (!instance.tail) {
73
+ return;
74
+ }
75
+
76
+ const original = instance.tail.bind(instance);
77
+ instance.tail = new Proxy(original, {
78
+ apply(target, thisArg, args) {
79
+ return wrapTailHandler(options, context, () => Reflect.apply(target, thisArg, args));
56
80
  },
57
81
  });
58
-
59
- instrument.markAsInstrumented(handler.tail);
60
82
  }
61
83
 
62
84
  exports.instrumentExportedHandlerTail = instrumentExportedHandlerTail;
85
+ exports.instrumentWorkerEntrypointTail = instrumentWorkerEntrypointTail;
63
86
  //# sourceMappingURL=instrumentTail.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentTail.js","sources":["../../../../src/instrumentations/worker/instrumentTail.ts"],"sourcesContent":["import type { ExportedHandler } from '@cloudflare/workers-types';\nimport { captureException, withIsolationScope } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { flushAndDispose } from '../../flush';\nimport { isInstrumented, markAsInstrumented } from '../../instrument';\nimport { getFinalOptions } from '../../options';\nimport { addCloudResourceContext } from '../../scope-utils';\nimport { init } from '../../sdk';\nimport { instrumentContext } from '../../utils/instrumentContext';\n\n/**\n * Core tail handler logic - wraps execution with Sentry instrumentation.\n * Note: tail handlers don't create spans, just error capture.\n */\nfunction wrapTailHandler(options: CloudflareOptions, context: ExecutionContext, fn: () => unknown): unknown {\n return withIsolationScope(async isolationScope => {\n const waitUntil = context.waitUntil.bind(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n try {\n return await fn();\n } catch (e) {\n captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.tail' } });\n throw e;\n } finally {\n waitUntil(flushAndDispose(client));\n }\n });\n}\n\n/**\n * Instruments a tail handler for ExportedHandler (env/ctx come from args).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function instrumentExportedHandlerTail<T extends ExportedHandler<any, any, any>>(\n handler: T,\n optionsCallback: (env: Parameters<NonNullable<T['tail']>>[1]) => CloudflareOptions | undefined,\n): void {\n if (!('tail' in handler) || typeof handler.tail !== 'function' || isInstrumented(handler.tail)) {\n return;\n }\n\n handler.tail = new Proxy(handler.tail, {\n apply(target, thisArg, args: Parameters<NonNullable<T['tail']>>) {\n const [, env, ctx] = args;\n const context = instrumentContext(ctx);\n args[2] = context;\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n return wrapTailHandler(options, context, () => target.apply(thisArg, args));\n },\n });\n\n markAsInstrumented(handler.tail);\n}\n"],"names":["withIsolationScope","init","addCloudResourceContext","captureException","flushAndDispose","isInstrumented","instrumentContext","options","getFinalOptions","markAsInstrumented"],"mappings":";;;;;;;;;;AAUA;AACA;AACA;AACA;AACA,SAAS,eAAe,CAAC,OAAO,EAAqB,OAAO,EAAoB,EAAE,EAA0B;AAC5G,EAAE,OAAOA,uBAAkB,CAAC,MAAM,kBAAkB;AACpD,IAAI,MAAM,SAAA,GAAY,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;;AAErD,IAAI,MAAM,MAAA,GAASC,QAAI,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,OAAA,EAAS,CAAC;AACrD,IAAI,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;;AAEpC,IAAIC,kCAAuB,CAAC,cAAc,CAAC;;AAE3C,IAAI,IAAI;AACR,MAAM,OAAO,MAAM,EAAE,EAAE;AACvB,IAAI,CAAA,CAAE,OAAO,CAAC,EAAE;AAChB,MAAMC,qBAAgB,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,2BAAA,EAA4B,EAAG,CAAC;AAC/F,MAAM,MAAM,CAAC;AACb,IAAI,UAAU;AACd,MAAM,SAAS,CAACC,qBAAe,CAAC,MAAM,CAAC,CAAC;AACxC,IAAI;AACJ,EAAE,CAAC,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACO,SAAS,6BAA6B;AAC7C,EAAE,OAAO;AACT,EAAE,eAAe;AACjB,EAAQ;AACR,EAAE,IAAI,EAAE,UAAU,OAAO,CAAA,IAAK,OAAO,OAAO,CAAC,IAAA,KAAS,cAAcC,yBAAc,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AAClG,IAAI;AACJ,EAAE;;AAEF,EAAE,OAAO,CAAC,IAAA,GAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE;AACzC,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAsC;AACrE,MAAM,MAAM,GAAG,GAAG,EAAE,GAAG,CAAA,GAAI,IAAI;AAC/B,MAAM,MAAM,OAAA,GAAUC,mCAAiB,CAAC,GAAG,CAAC;AAC5C,MAAM,IAAI,CAAC,CAAC,CAAA,GAAI,OAAO;;AAEvB,MAAM,MAAMC,SAAA,GAAUC,uBAAe,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;;AAEhE,MAAM,OAAO,eAAe,CAACD,SAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACjF,IAAI,CAAC;AACL,GAAG,CAAC;;AAEJ,EAAEE,6BAAkB,CAAC,OAAO,CAAC,IAAI,CAAC;AAClC;;;;"}
1
+ {"version":3,"file":"instrumentTail.js","sources":["../../../../src/instrumentations/worker/instrumentTail.ts"],"sourcesContent":["import type { ExportedHandler, TraceItem } from '@cloudflare/workers-types';\nimport type { env as cloudflareEnv, WorkerEntrypoint } from 'cloudflare:workers';\nimport { captureException, withIsolationScope } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { flushAndDispose } from '../../flush';\nimport { ensureInstrumented } from '../../instrument';\nimport { getFinalOptions } from '../../options';\nimport { addCloudResourceContext } from '../../scope-utils';\nimport { init } from '../../sdk';\nimport { instrumentContext } from '../../utils/instrumentContext';\n\n/**\n * Core tail handler logic - wraps execution with Sentry instrumentation.\n * Note: tail handlers don't create spans, just error capture.\n */\nfunction wrapTailHandler(options: CloudflareOptions, context: ExecutionContext, fn: () => unknown): unknown {\n return withIsolationScope(async isolationScope => {\n const waitUntil = context.waitUntil.bind(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n try {\n return await fn();\n } catch (e) {\n captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.tail' } });\n throw e;\n } finally {\n waitUntil(flushAndDispose(client));\n }\n });\n}\n\n/**\n * Instruments a tail handler for ExportedHandler (env/ctx come from args).\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function instrumentExportedHandlerTail<T extends ExportedHandler<any, any, any>>(\n handler: T,\n optionsCallback: (env: typeof cloudflareEnv) => CloudflareOptions | undefined,\n): void {\n if (!('tail' in handler) || typeof handler.tail !== 'function') {\n return;\n }\n\n handler.tail = ensureInstrumented(\n handler.tail,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args: Parameters<NonNullable<T['tail']>>) {\n const [, env, ctx] = args;\n const context = instrumentContext(ctx);\n args[2] = context;\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n return wrapTailHandler(options, context, () => target.apply(thisArg, args));\n },\n }),\n );\n}\n\n/**\n * Instruments a tail method for WorkerEntrypoint (options/context already available).\n */\nexport function instrumentWorkerEntrypointTail<T extends WorkerEntrypoint>(\n instance: T,\n options: CloudflareOptions,\n context: ExecutionContext,\n): void {\n if (!instance.tail) {\n return;\n }\n\n const original = instance.tail.bind(instance);\n instance.tail = new Proxy(original, {\n apply(target, thisArg, args: [TraceItem[]]) {\n return wrapTailHandler(options, context, () => Reflect.apply(target, thisArg, args));\n },\n });\n}\n"],"names":["withIsolationScope","init","addCloudResourceContext","captureException","flushAndDispose","ensureInstrumented","instrumentContext","options","getFinalOptions"],"mappings":";;;;;;;;;;AAWA;AACA;AACA;AACA;AACA,SAAS,eAAe,CAAC,OAAO,EAAqB,OAAO,EAAoB,EAAE,EAA0B;AAC5G,EAAE,OAAOA,uBAAkB,CAAC,MAAM,kBAAkB;AACpD,IAAI,MAAM,SAAA,GAAY,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;;AAErD,IAAI,MAAM,MAAA,GAASC,QAAI,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,OAAA,EAAS,CAAC;AACrD,IAAI,cAAc,CAAC,SAAS,CAAC,MAAM,CAAC;;AAEpC,IAAIC,kCAAuB,CAAC,cAAc,CAAC;;AAE3C,IAAI,IAAI;AACR,MAAM,OAAO,MAAM,EAAE,EAAE;AACvB,IAAI,CAAA,CAAE,OAAO,CAAC,EAAE;AAChB,MAAMC,qBAAgB,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,2BAAA,EAA4B,EAAG,CAAC;AAC/F,MAAM,MAAM,CAAC;AACb,IAAI,UAAU;AACd,MAAM,SAAS,CAACC,qBAAe,CAAC,MAAM,CAAC,CAAC;AACxC,IAAI;AACJ,EAAE,CAAC,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACO,SAAS,6BAA6B;AAC7C,EAAE,OAAO;AACT,EAAE,eAAe;AACjB,EAAQ;AACR,EAAE,IAAI,EAAE,UAAU,OAAO,CAAA,IAAK,OAAO,OAAO,CAAC,IAAA,KAAS,UAAU,EAAE;AAClE,IAAI;AACJ,EAAE;;AAEF,EAAE,OAAO,CAAC,IAAA,GAAOC,6BAAkB;AACnC,IAAI,OAAO,CAAC,IAAI;AAChB,IAAI,QAAA;AACJ,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE;AAC1B,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAsC;AACzE,UAAU,MAAM,GAAG,GAAG,EAAE,GAAG,CAAA,GAAI,IAAI;AACnC,UAAU,MAAM,OAAA,GAAUC,mCAAiB,CAAC,GAAG,CAAC;AAChD,UAAU,IAAI,CAAC,CAAC,CAAA,GAAI,OAAO;;AAE3B,UAAU,MAAMC,SAAA,GAAUC,uBAAe,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;;AAEpE,UAAU,OAAO,eAAe,CAACD,SAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AACrF,QAAQ,CAAC;AACT,OAAO,CAAC;AACR,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,8BAA8B;AAC9C,EAAE,QAAQ;AACV,EAAE,OAAO;AACT,EAAE,OAAO;AACT,EAAQ;AACR,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;AACtB,IAAI;AACJ,EAAE;;AAEF,EAAE,MAAM,QAAA,GAAW,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;AAC/C,EAAE,QAAQ,CAAC,IAAA,GAAO,IAAI,KAAK,CAAC,QAAQ,EAAE;AACtC,IAAI,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAiB;AAChD,MAAM,OAAO,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;AAC1F,IAAI,CAAC;AACL,GAAG,CAAC;AACJ;;;;;"}
@@ -15,11 +15,7 @@ function wrapRequestHandler(
15
15
  ) {
16
16
  return core.withIsolationScope(async isolationScope => {
17
17
  const { options, request, captureErrors = true } = wrapperOptions;
18
-
19
- // In certain situations, the passed context can become undefined.
20
- // For example, for Astro while prerendering pages at build time.
21
- // see: https://github.com/getsentry/sentry-javascript/issues/13217
22
- const context = wrapperOptions.context ;
18
+ const context = wrapperOptions.context;
23
19
 
24
20
  const waitUntil = context?.waitUntil?.bind?.(context);
25
21
 
@@ -53,7 +49,10 @@ function wrapRequestHandler(
53
49
  scopeUtils.addRequest(isolationScope, request);
54
50
  if (request.cf) {
55
51
  scopeUtils.addCultureContext(isolationScope, request.cf);
56
- attributes['network.protocol.name'] = request.cf.httpProtocol;
52
+
53
+ if (typeof request.cf.httpProtocol === 'string') {
54
+ attributes['network.protocol.name'] = request.cf.httpProtocol;
55
+ }
57
56
  }
58
57
 
59
58
  // Do not capture spans for OPTIONS and HEAD requests
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown>>;\n context: ExecutionContext;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n\n // In certain situations, the passed context can become undefined.\n // For example, for Astro while prerendering pages at build time.\n // see: https://github.com/getsentry/sentry-javascript/issues/13217\n const context = wrapperOptions.context as ExecutionContext | undefined;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n // Streaming response detected - monitor consumption to keep span alive\n try {\n const [clientStream, monitorStream] = res.body.tee();\n\n // Monitor stream consumption and end span when complete\n const streamMonitor = (async () => {\n const reader = monitorStream.getReader();\n\n try {\n let done = false;\n while (!done) {\n const result = await reader.read();\n done = result.done;\n }\n } catch {\n // Stream error or cancellation - will end span in finally\n } finally {\n reader.releaseLock();\n span.end();\n waitUntil?.(flushAndDispose(client));\n }\n })();\n\n // Keep worker alive until stream monitoring completes (otherwise span won't end)\n waitUntil?.(streamMonitor);\n\n // Return response with client stream\n return new Response(clientStream, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch (_e) {\n // tee() failed (e.g stream already locked) - fall back to non-streaming handling\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":["withIsolationScope","init","parseStringToURLObject","getHttpSpanDetailsFromUrlObject","httpHeadersToSpanAttributes","winterCGHeadersToDict","getClient","SEMANTIC_ATTRIBUTE_SENTRY_OP","addCloudResourceContext","addRequest","addCultureContext","captureException","flushAndDispose","continueTrace","startSpanManual","setHttpStatus","classifyResponseStreaming"],"mappings":"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"}
1
+ {"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;\n context: ExecutionContext | undefined;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n const context = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n\n if (typeof request.cf.httpProtocol === 'string') {\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n // Streaming response detected - monitor consumption to keep span alive\n try {\n const [clientStream, monitorStream] = res.body.tee();\n\n // Monitor stream consumption and end span when complete\n const streamMonitor = (async () => {\n const reader = monitorStream.getReader();\n\n try {\n let done = false;\n while (!done) {\n const result = await reader.read();\n done = result.done;\n }\n } catch {\n // Stream error or cancellation - will end span in finally\n } finally {\n reader.releaseLock();\n span.end();\n waitUntil?.(flushAndDispose(client));\n }\n })();\n\n // Keep worker alive until stream monitoring completes (otherwise span won't end)\n waitUntil?.(streamMonitor);\n\n // Return response with client stream\n return new Response(clientStream, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch (_e) {\n // tee() failed (e.g stream already locked) - fall back to non-streaming handling\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":["withIsolationScope","init","parseStringToURLObject","getHttpSpanDetailsFromUrlObject","httpHeadersToSpanAttributes","winterCGHeadersToDict","getClient","SEMANTIC_ATTRIBUTE_SENTRY_OP","addCloudResourceContext","addRequest","addCultureContext","captureException","flushAndDispose","continueTrace","startSpanManual","setHttpStatus","classifyResponseStreaming"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scope-utils.js","sources":["../../src/scope-utils.ts"],"sourcesContent":["import type { IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport type { Scope } from '@sentry/core';\nimport { winterCGRequestToRequestData } from '@sentry/core';\n\n/**\n * Set cloud resource context on scope.\n */\nexport function addCloudResourceContext(scope: Scope): void {\n scope.setContext('cloud_resource', {\n 'cloud.provider': 'cloudflare',\n });\n}\n\n/**\n * Set culture context on scope\n */\nexport function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties): void {\n scope.setContext('culture', {\n timezone: cf.timezone,\n });\n}\n\n/**\n * Set request data on scope\n */\nexport function addRequest(scope: Scope, request: Request): void {\n scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });\n}\n"],"names":["winterCGRequestToRequestData"],"mappings":";;;;AAIA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,KAAK,EAAe;AAC5D,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACrC,IAAI,gBAAgB,EAAE,YAAY;AAClC,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAS,EAAE,EAAqC;AACvF,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE;AAC9B,IAAI,QAAQ,EAAE,EAAE,CAAC,QAAQ;AACzB,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,UAAU,CAAC,KAAK,EAAS,OAAO,EAAiB;AACjE,EAAE,KAAK,CAAC,wBAAwB,CAAC,EAAE,iBAAiB,EAAEA,iCAA4B,CAAC,OAAO,CAAA,EAAG,CAAC;AAC9F;;;;;;"}
1
+ {"version":3,"file":"scope-utils.js","sources":["../../src/scope-utils.ts"],"sourcesContent":["import type { CfProperties, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport type { Scope } from '@sentry/core';\nimport { winterCGRequestToRequestData } from '@sentry/core';\n\n/**\n * Set cloud resource context on scope.\n */\nexport function addCloudResourceContext(scope: Scope): void {\n scope.setContext('cloud_resource', {\n 'cloud.provider': 'cloudflare',\n });\n}\n\n/**\n * Set culture context on scope\n */\nexport function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties | CfProperties): void {\n scope.setContext('culture', {\n timezone: cf.timezone,\n });\n}\n\n/**\n * Set request data on scope\n */\nexport function addRequest(scope: Scope, request: Request): void {\n scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });\n}\n"],"names":["winterCGRequestToRequestData"],"mappings":";;;;AAIA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,KAAK,EAAe;AAC5D,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACrC,IAAI,gBAAgB,EAAE,YAAY;AAClC,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAS,EAAE,EAAoD;AACtG,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE;AAC9B,IAAI,QAAQ,EAAE,EAAE,CAAC,QAAQ;AACzB,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,UAAU,CAAC,KAAK,EAAS,OAAO,EAAiB;AACjE,EAAE,KAAK,CAAC,wBAAwB,CAAC,EAAE,iBAAiB,EAAEA,iCAA4B,CAAC,OAAO,CAAA,EAAG,CAAC;AAC9F;;;;;;"}
@@ -0,0 +1,29 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ function isCloudflareClass(value, className) {
4
+ if (!value || typeof value !== 'function') {
5
+ return false;
6
+ }
7
+
8
+ if (value.name === className) {
9
+ return false;
10
+ }
11
+
12
+ let proto = value.prototype;
13
+
14
+ while (proto) {
15
+ const ctor = (proto ).constructor;
16
+ const constructorName = ctor?.name;
17
+
18
+ if (constructorName === className) {
19
+ return true;
20
+ }
21
+
22
+ proto = Object.getPrototypeOf(proto);
23
+ }
24
+
25
+ return false;
26
+ }
27
+
28
+ exports.isCloudflareClass = isCloudflareClass;
29
+ //# sourceMappingURL=isCloudflareClass.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isCloudflareClass.js","sources":["../../../src/utils/isCloudflareClass.ts"],"sourcesContent":["import type { DurableObject, WorkflowEntrypoint } from 'cloudflare:workers';\nimport type { WorkerEntrypointConstructor } from '../instrumentations/instrumentWorkerEntrypoint';\ntype CloudflareClassName = 'WorkerEntrypoint' | 'DurableObject' | 'WorkflowEntrypoint';\n\n/**\n * Checks if a class constructor extends a specific Cloudflare base class.\n *\n * Uses prototype chain walking with constructor names rather than instanceof,\n * so it works in Node at build time without requiring the cloudflare:workers\n * module (which only exists in the Workers runtime).\n *\n * This is used to differentiate between different Cloudflare worker types:\n * - WorkerEntrypoint: Class-based workers (used with instrumentWorkerEntrypoint)\n * - DurableObject: Durable Object classes\n * - Workflow: Workflow classes\n *\n * For ExportedHandler (plain objects), this will return false for all types.\n *\n * @param value - The value to check (typically a class constructor)\n * @param className - The Cloudflare base class name to check against\n * @returns true if the value is a class that extends the specified Cloudflare class\n *\n * @example\n * ```ts\n * isCloudflareClass(MyWorker, 'WorkerEntrypoint') // true if MyWorker extends WorkerEntrypoint\n * isCloudflareClass(MyDO, 'DurableObject') // true if MyDO extends DurableObject\n * ```\n */\nexport function isCloudflareClass(value: unknown, className: 'WorkerEntrypoint'): value is WorkerEntrypointConstructor;\nexport function isCloudflareClass(\n value: unknown,\n className: 'DurableObject',\n): value is new (...args: unknown[]) => DurableObject;\nexport function isCloudflareClass(\n value: unknown,\n className: 'WorkflowEntrypoint',\n): value is new (...args: unknown[]) => WorkflowEntrypoint;\nexport function isCloudflareClass(value: unknown, className: CloudflareClassName): boolean {\n if (!value || typeof value !== 'function') {\n return false;\n }\n\n if (value.name === className) {\n return false;\n }\n\n let proto: object | null = value.prototype;\n\n while (proto) {\n const ctor = (proto as { constructor?: { name?: string } }).constructor;\n const constructorName = ctor?.name;\n\n if (constructorName === className) {\n return true;\n }\n\n proto = Object.getPrototypeOf(proto);\n }\n\n return false;\n}\n"],"names":[],"mappings":";;AAqCO,SAAS,iBAAiB,CAAC,KAAK,EAAW,SAAS,EAAgC;AAC3F,EAAE,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,EAAE;AAC7C,IAAI,OAAO,KAAK;AAChB,EAAE;;AAEF,EAAE,IAAI,KAAK,CAAC,IAAA,KAAS,SAAS,EAAE;AAChC,IAAI,OAAO,KAAK;AAChB,EAAE;;AAEF,EAAE,IAAI,KAAK,GAAkB,KAAK,CAAC,SAAS;;AAE5C,EAAE,OAAO,KAAK,EAAE;AAChB,IAAI,MAAM,IAAA,GAAO,CAAC,KAAA,GAA8C,WAAW;AAC3E,IAAI,MAAM,eAAA,GAAkB,IAAI,EAAE,IAAI;;AAEtC,IAAI,IAAI,eAAA,KAAoB,SAAS,EAAE;AACvC,MAAM,OAAO,IAAI;AACjB,IAAI;;AAEJ,IAAI,QAAQ,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC;AACxC,EAAE;;AAEF,EAAE,OAAO,KAAK;AACd;;;;"}
@@ -8,6 +8,8 @@ const instrumentQueue = require('./instrumentations/worker/instrumentQueue.js');
8
8
  const instrumentScheduled = require('./instrumentations/worker/instrumentScheduled.js');
9
9
  const instrumentTail = require('./instrumentations/worker/instrumentTail.js');
10
10
  const hono = require('./integrations/hono.js');
11
+ const isCloudflareClass = require('./utils/isCloudflareClass.js');
12
+ const instrumentWorkerEntrypoint = require('./instrumentations/instrumentWorkerEntrypoint.js');
11
13
 
12
14
  /**
13
15
  * Wrapper for Cloudflare handlers.
@@ -20,18 +22,30 @@ const hono = require('./integrations/hono.js');
20
22
  * @param handler {ExportedHandler} The handler to wrap.
21
23
  * @returns The wrapped handler.
22
24
  */
25
+ // TODO(v11): The generic types need to be rewritten to following to improve type safety:
26
+ // T extends ExportedHandler<any, any, any> | WorkerEntrypointConstructor<any, any>
23
27
  function withSentry
24
28
 
25
29
  (optionsCallback, handler) {
30
+ if (isCloudflareClass.isCloudflareClass(handler, 'WorkerEntrypoint')) {
31
+ // oxlint-disable-next-line typescript/no-explicit-any
32
+ return instrumentWorkerEntrypoint.instrumentWorkerEntrypoint(optionsCallback , handler);
33
+ }
34
+
26
35
  async.setAsyncLocalStorageAsyncContextStrategy();
27
36
 
28
37
  try {
29
- instrumentFetch.instrumentExportedHandlerFetch(handler, optionsCallback);
38
+ // oxlint-disable-next-line typescript/no-explicit-any
39
+ instrumentFetch.instrumentExportedHandlerFetch(handler, optionsCallback );
30
40
  instrumentHonoErrorHandler(handler);
31
- instrumentScheduled.instrumentExportedHandlerScheduled(handler, optionsCallback);
32
- instrumentEmail.instrumentExportedHandlerEmail(handler, optionsCallback);
33
- instrumentQueue.instrumentExportedHandlerQueue(handler, optionsCallback);
34
- instrumentTail.instrumentExportedHandlerTail(handler, optionsCallback);
41
+ // oxlint-disable-next-line typescript/no-explicit-any
42
+ instrumentScheduled.instrumentExportedHandlerScheduled(handler, optionsCallback );
43
+ // oxlint-disable-next-line typescript/no-explicit-any
44
+ instrumentEmail.instrumentExportedHandlerEmail(handler, optionsCallback );
45
+ // oxlint-disable-next-line typescript/no-explicit-any
46
+ instrumentQueue.instrumentExportedHandlerQueue(handler, optionsCallback );
47
+ // oxlint-disable-next-line typescript/no-explicit-any
48
+ instrumentTail.instrumentExportedHandlerTail(handler, optionsCallback );
35
49
  // This is here because Miniflare sometimes cannot get instrumented
36
50
  } catch {
37
51
  // Do not console anything here, we don't want to spam the console with errors
@@ -42,23 +56,20 @@ function withSentry
42
56
 
43
57
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
58
  function instrumentHonoErrorHandler(handler) {
45
- if (
46
- 'onError' in handler &&
47
- 'errorHandler' in handler &&
48
- typeof handler.errorHandler === 'function' &&
49
- !instrument.isInstrumented(handler.errorHandler)
50
- ) {
51
- handler.errorHandler = new Proxy(handler.errorHandler, {
52
- apply(target, thisArg, args) {
53
- const [err, context] = args;
54
-
55
- hono.getHonoIntegration()?.handleHonoException(err, context);
59
+ if ('onError' in handler && 'errorHandler' in handler && typeof handler.errorHandler === 'function') {
60
+ handler.errorHandler = instrument.ensureInstrumented(
61
+ handler.errorHandler,
62
+ original =>
63
+ new Proxy(original, {
64
+ apply(target, thisArg, args) {
65
+ const [err, context] = args;
56
66
 
57
- return Reflect.apply(target, thisArg, args);
58
- },
59
- });
67
+ hono.getHonoIntegration()?.handleHonoException(err, context);
60
68
 
61
- instrument.markAsInstrumented(handler.errorHandler);
69
+ return Reflect.apply(target, thisArg, args);
70
+ },
71
+ }),
72
+ );
62
73
  }
63
74
  }
64
75
 
@@ -1 +1 @@
1
- {"version":3,"file":"withSentry.js","sources":["../../src/withSentry.ts"],"sourcesContent":["import type { env } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { isInstrumented, markAsInstrumented } from './instrument';\nimport { instrumentExportedHandlerEmail } from './instrumentations/worker/instrumentEmail';\nimport { instrumentExportedHandlerFetch } from './instrumentations/worker/instrumentFetch';\nimport { instrumentExportedHandlerQueue } from './instrumentations/worker/instrumentQueue';\nimport { instrumentExportedHandlerScheduled } from './instrumentations/worker/instrumentScheduled';\nimport { instrumentExportedHandlerTail } from './instrumentations/worker/instrumentTail';\nimport { getHonoIntegration } from './integrations/hono';\n\n/**\n * Wrapper for Cloudflare handlers.\n *\n * Initializes the SDK and wraps the handler with Sentry instrumentation.\n *\n * Automatically instruments the `fetch` method of the handler.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param handler {ExportedHandler} The handler to wrap.\n * @returns The wrapped handler.\n */\nexport function withSentry<\n Env = typeof env,\n QueueHandlerMessage = unknown,\n CfHostMetadata = unknown,\n T extends ExportedHandler<Env, QueueHandlerMessage, CfHostMetadata> = ExportedHandler<\n Env,\n QueueHandlerMessage,\n CfHostMetadata\n >,\n>(optionsCallback: (env: Env) => CloudflareOptions | undefined, handler: T): T {\n setAsyncLocalStorageAsyncContextStrategy();\n\n try {\n instrumentExportedHandlerFetch(handler, optionsCallback);\n instrumentHonoErrorHandler(handler);\n instrumentExportedHandlerScheduled(handler, optionsCallback);\n instrumentExportedHandlerEmail(handler, optionsCallback);\n instrumentExportedHandlerQueue(handler, optionsCallback);\n instrumentExportedHandlerTail(handler, optionsCallback);\n // This is here because Miniflare sometimes cannot get instrumented\n } catch {\n // Do not console anything here, we don't want to spam the console with errors\n }\n\n return handler;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction instrumentHonoErrorHandler<T extends ExportedHandler<any, any, any>>(handler: T): void {\n if (\n 'onError' in handler &&\n 'errorHandler' in handler &&\n typeof handler.errorHandler === 'function' &&\n !isInstrumented(handler.errorHandler)\n ) {\n handler.errorHandler = new Proxy(handler.errorHandler, {\n apply(target, thisArg, args) {\n const [err, context] = args;\n\n getHonoIntegration()?.handleHonoException(err, context);\n\n return Reflect.apply(target, thisArg, args);\n },\n });\n\n markAsInstrumented(handler.errorHandler);\n }\n}\n"],"names":["setAsyncLocalStorageAsyncContextStrategy","instrumentExportedHandlerFetch","instrumentExportedHandlerScheduled","instrumentExportedHandlerEmail","instrumentExportedHandlerQueue","instrumentExportedHandlerTail","isInstrumented","getHonoIntegration","markAsInstrumented"],"mappings":";;;;;;;;;;;AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS;;AAShB,CAAE,eAAe,EAA+C,OAAO,EAAQ;AAC/E,EAAEA,8CAAwC,EAAE;;AAE5C,EAAE,IAAI;AACN,IAAIC,8CAA8B,CAAC,OAAO,EAAE,eAAe,CAAC;AAC5D,IAAI,0BAA0B,CAAC,OAAO,CAAC;AACvC,IAAIC,sDAAkC,CAAC,OAAO,EAAE,eAAe,CAAC;AAChE,IAAIC,8CAA8B,CAAC,OAAO,EAAE,eAAe,CAAC;AAC5D,IAAIC,8CAA8B,CAAC,OAAO,EAAE,eAAe,CAAC;AAC5D,IAAIC,4CAA6B,CAAC,OAAO,EAAE,eAAe,CAAC;AAC3D;AACA,EAAE,EAAE,MAAM;AACV;AACA,EAAE;;AAEF,EAAE,OAAO,OAAO;AAChB;;AAEA;AACA,SAAS,0BAA0B,CAA2C,OAAO,EAAW;AAChG,EAAE;AACF,IAAI,SAAA,IAAa,OAAA;AACjB,IAAI,cAAA,IAAkB,OAAA;AACtB,IAAI,OAAO,OAAO,CAAC,YAAA,KAAiB,UAAA;AACpC,IAAI,CAACC,yBAAc,CAAC,OAAO,CAAC,YAAY;AACxC,IAAI;AACJ,IAAI,OAAO,CAAC,YAAA,GAAe,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE;AAC3D,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AACnC,QAAQ,MAAM,CAAC,GAAG,EAAE,OAAO,CAAA,GAAI,IAAI;;AAEnC,QAAQC,uBAAkB,EAAE,EAAE,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC;;AAE/D,QAAQ,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AACnD,MAAM,CAAC;AACP,KAAK,CAAC;;AAEN,IAAIC,6BAAkB,CAAC,OAAO,CAAC,YAAY,CAAC;AAC5C,EAAE;AACF;;;;"}
1
+ {"version":3,"file":"withSentry.js","sources":["../../src/withSentry.ts"],"sourcesContent":["import type { env as cloudflareEnv } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { ensureInstrumented } from './instrument';\nimport { instrumentExportedHandlerEmail } from './instrumentations/worker/instrumentEmail';\nimport { instrumentExportedHandlerFetch } from './instrumentations/worker/instrumentFetch';\nimport { instrumentExportedHandlerQueue } from './instrumentations/worker/instrumentQueue';\nimport { instrumentExportedHandlerScheduled } from './instrumentations/worker/instrumentScheduled';\nimport { instrumentExportedHandlerTail } from './instrumentations/worker/instrumentTail';\nimport { getHonoIntegration } from './integrations/hono';\nimport { isCloudflareClass } from './utils/isCloudflareClass';\nimport {\n instrumentWorkerEntrypoint,\n type WorkerEntrypointConstructor,\n} from './instrumentations/instrumentWorkerEntrypoint';\n\n/**\n * Wrapper for Cloudflare handlers.\n *\n * Initializes the SDK and wraps the handler with Sentry instrumentation.\n *\n * Automatically instruments the `fetch` method of the handler.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param handler {ExportedHandler} The handler to wrap.\n * @returns The wrapped handler.\n */\n// TODO(v11): The generic types need to be rewritten to following to improve type safety:\n// T extends ExportedHandler<any, any, any> | WorkerEntrypointConstructor<any, any>\nexport function withSentry<\n Env = typeof cloudflareEnv,\n QueueHandlerMessage = unknown,\n CfHostMetadata = unknown,\n T extends ExportedHandler<Env, QueueHandlerMessage, CfHostMetadata> | WorkerEntrypointConstructor = ExportedHandler<\n Env,\n QueueHandlerMessage,\n CfHostMetadata\n >,\n>(optionsCallback: (env: Env) => CloudflareOptions | undefined, handler: T): T {\n if (isCloudflareClass(handler, 'WorkerEntrypoint')) {\n // oxlint-disable-next-line typescript/no-explicit-any\n return instrumentWorkerEntrypoint(optionsCallback as any, handler);\n }\n\n setAsyncLocalStorageAsyncContextStrategy();\n\n try {\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerFetch(handler, optionsCallback as any);\n instrumentHonoErrorHandler(handler);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerScheduled(handler, optionsCallback as any);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerEmail(handler, optionsCallback as any);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerQueue(handler, optionsCallback as any);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerTail(handler, optionsCallback as any);\n // This is here because Miniflare sometimes cannot get instrumented\n } catch {\n // Do not console anything here, we don't want to spam the console with errors\n }\n\n return handler;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction instrumentHonoErrorHandler<T extends ExportedHandler<any, any, any>>(handler: T): void {\n if ('onError' in handler && 'errorHandler' in handler && typeof handler.errorHandler === 'function') {\n handler.errorHandler = ensureInstrumented(\n handler.errorHandler,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args) {\n const [err, context] = args;\n\n getHonoIntegration()?.handleHonoException(err, context);\n\n return Reflect.apply(target, thisArg, args);\n },\n }),\n );\n }\n}\n"],"names":["isCloudflareClass","instrumentWorkerEntrypoint","setAsyncLocalStorageAsyncContextStrategy","instrumentExportedHandlerFetch","instrumentExportedHandlerScheduled","instrumentExportedHandlerEmail","instrumentExportedHandlerQueue","instrumentExportedHandlerTail","ensureInstrumented","getHonoIntegration"],"mappings":";;;;;;;;;;;;;AAgBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS;;AAShB,CAAE,eAAe,EAA+C,OAAO,EAAQ;AAC/E,EAAE,IAAIA,mCAAiB,CAAC,OAAO,EAAE,kBAAkB,CAAC,EAAE;AACtD;AACA,IAAI,OAAOC,qDAA0B,CAAC,eAAA,GAAwB,OAAO,CAAC;AACtE,EAAE;;AAEF,EAAEC,8CAAwC,EAAE;;AAE5C,EAAE,IAAI;AACN;AACA,IAAIC,8CAA8B,CAAC,OAAO,EAAE,iBAAuB;AACnE,IAAI,0BAA0B,CAAC,OAAO,CAAC;AACvC;AACA,IAAIC,sDAAkC,CAAC,OAAO,EAAE,iBAAuB;AACvE;AACA,IAAIC,8CAA8B,CAAC,OAAO,EAAE,iBAAuB;AACnE;AACA,IAAIC,8CAA8B,CAAC,OAAO,EAAE,iBAAuB;AACnE;AACA,IAAIC,4CAA6B,CAAC,OAAO,EAAE,iBAAuB;AAClE;AACA,EAAE,EAAE,MAAM;AACV;AACA,EAAE;;AAEF,EAAE,OAAO,OAAO;AAChB;;AAEA;AACA,SAAS,0BAA0B,CAA2C,OAAO,EAAW;AAChG,EAAE,IAAI,SAAA,IAAa,OAAA,IAAW,cAAA,IAAkB,OAAA,IAAW,OAAO,OAAO,CAAC,YAAA,KAAiB,UAAU,EAAE;AACvG,IAAI,OAAO,CAAC,YAAA,GAAeC,6BAAkB;AAC7C,MAAM,OAAO,CAAC,YAAY;AAC1B,MAAM,QAAA;AACN,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE;AAC5B,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AACvC,YAAY,MAAM,CAAC,GAAG,EAAE,OAAO,CAAA,GAAI,IAAI;;AAEvC,YAAYC,uBAAkB,EAAE,EAAE,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC;;AAEnE,YAAY,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AACvD,UAAU,CAAC;AACX,SAAS,CAAC;AACV,KAAK;AACL,EAAE;AACF;;;;"}