@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
@@ -22,128 +22,128 @@ function wrapMethodWithSentry(
22
22
  callback,
23
23
  noMark,
24
24
  ) {
25
- if (instrument.isInstrumented(handler)) {
26
- return handler;
27
- }
28
-
29
- if (!noMark) {
30
- instrument.markAsInstrumented(handler);
31
- }
32
-
33
- return new Proxy(handler, {
34
- apply(target, thisArg, args) {
35
- const currentClient = core.getClient();
36
- // if a client is already set, use withScope, otherwise use withIsolationScope
37
- const sentryWithScope = currentClient ? core.withScope : core.withIsolationScope;
38
-
39
- const wrappedFunction = (scope) => {
40
- // In certain situations, the passed context can become undefined.
41
- // For example, for Astro while prerendering pages at build time.
42
- // see: https://github.com/getsentry/sentry-javascript/issues/13217
43
- const context = wrapperOptions.context ;
44
-
45
- const waitUntil = context?.waitUntil?.bind?.(context);
46
-
47
- let currentClient = scope.getClient();
48
- // Check if client exists AND is still usable (transport not disposed)
49
- // This handles the case where a previous handler disposed the client
50
- // but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)
51
- if (!currentClient?.getTransport()) {
52
- const client = sdk.init({ ...wrapperOptions.options, ctx: context });
53
- scope.setClient(client);
54
- currentClient = client;
55
- }
25
+ return instrument.ensureInstrumented(
26
+ handler,
27
+ original =>
28
+ new Proxy(original, {
29
+ apply(target, thisArg, args) {
30
+ const currentClient = core.getClient();
31
+ // if a client is already set, use withScope, otherwise use withIsolationScope
32
+ const sentryWithScope = currentClient ? core.withScope : core.withIsolationScope;
33
+
34
+ const wrappedFunction = (scope) => {
35
+ // In certain situations, the passed context can become undefined.
36
+ // For example, for Astro while prerendering pages at build time.
37
+ // see: https://github.com/getsentry/sentry-javascript/issues/13217
38
+ const context = wrapperOptions.context ;
39
+
40
+ const waitUntil = context?.waitUntil?.bind?.(context);
41
+
42
+ let currentClient = scope.getClient();
43
+ // Check if client exists AND is still usable (transport not disposed)
44
+ // This handles the case where a previous handler disposed the client
45
+ // but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)
46
+ if (!currentClient?.getTransport()) {
47
+ const client = sdk.init({
48
+ ...wrapperOptions.options,
49
+ ctx: context ,
50
+ });
51
+ scope.setClient(client);
52
+ currentClient = client;
53
+ }
56
54
 
57
- const clientToDispose = currentClient;
55
+ const clientToDispose = currentClient;
58
56
 
59
- if (!wrapperOptions.spanName) {
60
- try {
61
- if (callback) {
62
- callback(...args);
63
- }
64
- const result = Reflect.apply(target, thisArg, args);
57
+ if (!wrapperOptions.spanName) {
58
+ try {
59
+ if (callback) {
60
+ callback(...args);
61
+ }
62
+ const result = Reflect.apply(target, thisArg, args);
65
63
 
66
- if (core.isThenable(result)) {
67
- return result.then(
68
- (res) => {
69
- waitUntil?.(flush.flushAndDispose(clientToDispose));
70
- return res;
71
- },
72
- (e) => {
73
- core.captureException(e, {
74
- mechanism: {
75
- type: 'auto.faas.cloudflare.durable_object',
76
- handled: false,
64
+ if (core.isThenable(result)) {
65
+ return result.then(
66
+ (res) => {
67
+ waitUntil?.(flush.flushAndDispose(clientToDispose));
68
+ return res;
77
69
  },
78
- });
70
+ (e) => {
71
+ core.captureException(e, {
72
+ mechanism: {
73
+ type: 'auto.faas.cloudflare.durable_object',
74
+ handled: false,
75
+ },
76
+ });
77
+ waitUntil?.(flush.flushAndDispose(clientToDispose));
78
+ throw e;
79
+ },
80
+ );
81
+ } else {
79
82
  waitUntil?.(flush.flushAndDispose(clientToDispose));
80
- throw e;
81
- },
82
- );
83
- } else {
84
- waitUntil?.(flush.flushAndDispose(clientToDispose));
85
- return result;
86
- }
87
- } catch (e) {
88
- core.captureException(e, {
89
- mechanism: {
90
- type: 'auto.faas.cloudflare.durable_object',
91
- handled: false,
92
- },
93
- });
94
- waitUntil?.(flush.flushAndDispose(clientToDispose));
95
- throw e;
96
- }
97
- }
98
-
99
- const attributes = wrapperOptions.spanOp
100
- ? {
101
- [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,
102
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',
83
+ return result;
84
+ }
85
+ } catch (e) {
86
+ core.captureException(e, {
87
+ mechanism: {
88
+ type: 'auto.faas.cloudflare.durable_object',
89
+ handled: false,
90
+ },
91
+ });
92
+ waitUntil?.(flush.flushAndDispose(clientToDispose));
93
+ throw e;
94
+ }
103
95
  }
104
- : {};
105
96
 
106
- return core.startSpan({ name: wrapperOptions.spanName, attributes }, () => {
107
- try {
108
- const result = Reflect.apply(target, thisArg, args);
109
-
110
- if (core.isThenable(result)) {
111
- return result.then(
112
- (res) => {
113
- waitUntil?.(flush.flushAndDispose(clientToDispose));
114
- return res;
115
- },
116
- (e) => {
117
- core.captureException(e, {
118
- mechanism: {
119
- type: 'auto.faas.cloudflare.durable_object',
120
- handled: false,
97
+ const attributes = wrapperOptions.spanOp
98
+ ? {
99
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,
100
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',
101
+ }
102
+ : {};
103
+
104
+ return core.startSpan({ name: wrapperOptions.spanName, attributes }, () => {
105
+ try {
106
+ const result = Reflect.apply(target, thisArg, args);
107
+
108
+ if (core.isThenable(result)) {
109
+ return result.then(
110
+ (res) => {
111
+ waitUntil?.(flush.flushAndDispose(clientToDispose));
112
+ return res;
121
113
  },
122
- });
114
+ (e) => {
115
+ core.captureException(e, {
116
+ mechanism: {
117
+ type: 'auto.faas.cloudflare.durable_object',
118
+ handled: false,
119
+ },
120
+ });
121
+ waitUntil?.(flush.flushAndDispose(clientToDispose));
122
+ throw e;
123
+ },
124
+ );
125
+ } else {
123
126
  waitUntil?.(flush.flushAndDispose(clientToDispose));
124
- throw e;
125
- },
126
- );
127
- } else {
128
- waitUntil?.(flush.flushAndDispose(clientToDispose));
129
- return result;
130
- }
131
- } catch (e) {
132
- core.captureException(e, {
133
- mechanism: {
134
- type: 'auto.faas.cloudflare.durable_object',
135
- handled: false,
136
- },
127
+ return result;
128
+ }
129
+ } catch (e) {
130
+ core.captureException(e, {
131
+ mechanism: {
132
+ type: 'auto.faas.cloudflare.durable_object',
133
+ handled: false,
134
+ },
135
+ });
136
+ waitUntil?.(flush.flushAndDispose(clientToDispose));
137
+ throw e;
138
+ }
137
139
  });
138
- waitUntil?.(flush.flushAndDispose(clientToDispose));
139
- throw e;
140
- }
141
- });
142
- };
140
+ };
143
141
 
144
- return sentryWithScope(wrappedFunction);
145
- },
146
- });
142
+ return sentryWithScope(wrappedFunction);
143
+ },
144
+ }),
145
+ noMark,
146
+ );
147
147
  }
148
148
 
149
149
  exports.wrapMethodWithSentry = wrapMethodWithSentry;
@@ -1 +1 @@
1
- {"version":3,"file":"wrapMethodWithSentry.js","sources":["../../src/wrapMethodWithSentry.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport {\n captureException,\n getClient,\n isThenable,\n type Scope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { isInstrumented, markAsInstrumented } from './instrument';\nimport { init } from './sdk';\n\n/** Extended DurableObjectState with originalStorage exposed by instrumentContext */\ninterface InstrumentedDurableObjectState extends DurableObjectState {\n originalStorage?: DurableObjectStorage;\n}\n\ntype MethodWrapperOptions = {\n spanName?: string;\n spanOp?: string;\n options: CloudflareOptions;\n context: ExecutionContext | DurableObjectState;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type UncheckedMethod = (...args: any[]) => any;\ntype OriginalMethod = UncheckedMethod;\n\n/**\n * Wraps a method with Sentry tracing.\n *\n * @param wrapperOptions - The options for the wrapper.\n * @param handler - The method to wrap.\n * @param callback - The callback to call.\n * @param noMark - Whether to mark the method as instrumented.\n * @returns The wrapped method.\n */\nexport function wrapMethodWithSentry<T extends OriginalMethod>(\n wrapperOptions: MethodWrapperOptions,\n handler: T,\n callback?: (...args: Parameters<T>) => void,\n noMark?: true,\n): T {\n if (isInstrumented(handler)) {\n return handler;\n }\n\n if (!noMark) {\n markAsInstrumented(handler);\n }\n\n return new Proxy(handler, {\n apply(target, thisArg, args: Parameters<T>) {\n const currentClient = getClient();\n // if a client is already set, use withScope, otherwise use withIsolationScope\n const sentryWithScope = currentClient ? withScope : withIsolationScope;\n\n const wrappedFunction = (scope: Scope): unknown => {\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 InstrumentedDurableObjectState | undefined;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n let currentClient = scope.getClient();\n // Check if client exists AND is still usable (transport not disposed)\n // This handles the case where a previous handler disposed the client\n // but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)\n if (!currentClient?.getTransport()) {\n const client = init({ ...wrapperOptions.options, ctx: context as unknown as ExecutionContext | undefined });\n scope.setClient(client);\n currentClient = client;\n }\n\n const clientToDispose = currentClient;\n\n if (!wrapperOptions.spanName) {\n try {\n if (callback) {\n callback(...args);\n }\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(\n (res: unknown) => {\n waitUntil?.(flushAndDispose(clientToDispose));\n return res;\n },\n (e: unknown) => {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n },\n );\n } else {\n waitUntil?.(flushAndDispose(clientToDispose));\n return result;\n }\n } catch (e) {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n }\n }\n\n const attributes = wrapperOptions.spanOp\n ? {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',\n }\n : {};\n\n return startSpan({ name: wrapperOptions.spanName, attributes }, () => {\n try {\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(\n (res: unknown) => {\n waitUntil?.(flushAndDispose(clientToDispose));\n return res;\n },\n (e: unknown) => {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n },\n );\n } else {\n waitUntil?.(flushAndDispose(clientToDispose));\n return result;\n }\n } catch (e) {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n }\n });\n };\n\n return sentryWithScope(wrappedFunction);\n },\n });\n}\n"],"names":["isInstrumented","markAsInstrumented","getClient","withScope","withIsolationScope","init","isThenable","flushAndDispose","captureException","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan"],"mappings":"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"}
1
+ {"version":3,"file":"wrapMethodWithSentry.js","sources":["../../src/wrapMethodWithSentry.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport {\n captureException,\n getClient,\n isThenable,\n type Scope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { ensureInstrumented } from './instrument';\nimport { init } from './sdk';\n\n/** Extended DurableObjectState with originalStorage exposed by instrumentContext */\ninterface InstrumentedDurableObjectState extends DurableObjectState {\n originalStorage?: DurableObjectStorage;\n}\n\ntype MethodWrapperOptions = {\n spanName?: string;\n spanOp?: string;\n options: CloudflareOptions;\n context: ExecutionContext | DurableObjectState;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type UncheckedMethod = (...args: any[]) => any;\ntype OriginalMethod = UncheckedMethod;\n\n/**\n * Wraps a method with Sentry tracing.\n *\n * @param wrapperOptions - The options for the wrapper.\n * @param handler - The method to wrap.\n * @param callback - The callback to call.\n * @param noMark - Whether to mark the method as instrumented.\n * @returns The wrapped method.\n */\nexport function wrapMethodWithSentry<T extends OriginalMethod>(\n wrapperOptions: MethodWrapperOptions,\n handler: T,\n callback?: (...args: Parameters<T>) => void,\n noMark?: true,\n): T {\n return ensureInstrumented(\n handler,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args: Parameters<T>) {\n const currentClient = getClient();\n // if a client is already set, use withScope, otherwise use withIsolationScope\n const sentryWithScope = currentClient ? withScope : withIsolationScope;\n\n const wrappedFunction = (scope: Scope): unknown => {\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 InstrumentedDurableObjectState | undefined;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n let currentClient = scope.getClient();\n // Check if client exists AND is still usable (transport not disposed)\n // This handles the case where a previous handler disposed the client\n // but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)\n if (!currentClient?.getTransport()) {\n const client = init({\n ...wrapperOptions.options,\n ctx: context as unknown as ExecutionContext | undefined,\n });\n scope.setClient(client);\n currentClient = client;\n }\n\n const clientToDispose = currentClient;\n\n if (!wrapperOptions.spanName) {\n try {\n if (callback) {\n callback(...args);\n }\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(\n (res: unknown) => {\n waitUntil?.(flushAndDispose(clientToDispose));\n return res;\n },\n (e: unknown) => {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n },\n );\n } else {\n waitUntil?.(flushAndDispose(clientToDispose));\n return result;\n }\n } catch (e) {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n }\n }\n\n const attributes = wrapperOptions.spanOp\n ? {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',\n }\n : {};\n\n return startSpan({ name: wrapperOptions.spanName, attributes }, () => {\n try {\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(\n (res: unknown) => {\n waitUntil?.(flushAndDispose(clientToDispose));\n return res;\n },\n (e: unknown) => {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n },\n );\n } else {\n waitUntil?.(flushAndDispose(clientToDispose));\n return result;\n }\n } catch (e) {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(flushAndDispose(clientToDispose));\n throw e;\n }\n });\n };\n\n return sentryWithScope(wrappedFunction);\n },\n }),\n noMark,\n );\n}\n"],"names":["ensureInstrumented","getClient","withScope","withIsolationScope","init","isThenable","flushAndDispose","captureException","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan"],"mappings":";;;;;;;AAiBA;;AAgBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB;AACpC,EAAE,cAAc;AAChB,EAAE,OAAO;AACT,EAAE,QAAQ;AACV,EAAE,MAAM;AACR,EAAK;AACL,EAAE,OAAOA,6BAAkB;AAC3B,IAAI,OAAO;AACX,IAAI,QAAA;AACJ,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE;AAC1B,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAiB;AACpD,UAAU,MAAM,aAAA,GAAgBC,cAAS,EAAE;AAC3C;AACA,UAAU,MAAM,eAAA,GAAkB,gBAAgBC,cAAA,GAAYC,uBAAkB;;AAEhF,UAAU,MAAM,eAAA,GAAkB,CAAC,KAAK,KAAqB;AAC7D;AACA;AACA;AACA,YAAY,MAAM,OAAA,GAAU,cAAc,CAAC,OAAA;;AAE3C,YAAY,MAAM,SAAA,GAAY,OAAO,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC;;AAEjE,YAAY,IAAI,aAAA,GAAgB,KAAK,CAAC,SAAS,EAAE;AACjD;AACA;AACA;AACA,YAAY,IAAI,CAAC,aAAa,EAAE,YAAY,EAAE,EAAE;AAChD,cAAc,MAAM,MAAA,GAASC,QAAI,CAAC;AAClC,gBAAgB,GAAG,cAAc,CAAC,OAAO;AACzC,gBAAgB,GAAG,EAAE,OAAA;AACrB,eAAe,CAAC;AAChB,cAAc,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;AACrC,cAAc,aAAA,GAAgB,MAAM;AACpC,YAAY;;AAEZ,YAAY,MAAM,eAAA,GAAkB,aAAa;;AAEjD,YAAY,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE;AAC1C,cAAc,IAAI;AAClB,gBAAgB,IAAI,QAAQ,EAAE;AAC9B,kBAAkB,QAAQ,CAAC,GAAG,IAAI,CAAC;AACnC,gBAAgB;AAChB,gBAAgB,MAAM,MAAA,GAAS,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;;AAEnE,gBAAgB,IAAIC,eAAU,CAAC,MAAM,CAAC,EAAE;AACxC,kBAAkB,OAAO,MAAM,CAAC,IAAI;AACpC,oBAAoB,CAAC,GAAG,KAAc;AACtC,sBAAsB,SAAS,GAAGC,qBAAe,CAAC,eAAe,CAAC,CAAC;AACnE,sBAAsB,OAAO,GAAG;AAChC,oBAAoB,CAAC;AACrB,oBAAoB,CAAC,CAAC,KAAc;AACpC,sBAAsBC,qBAAgB,CAAC,CAAC,EAAE;AAC1C,wBAAwB,SAAS,EAAE;AACnC,0BAA0B,IAAI,EAAE,qCAAqC;AACrE,0BAA0B,OAAO,EAAE,KAAK;AACxC,yBAAyB;AACzB,uBAAuB,CAAC;AACxB,sBAAsB,SAAS,GAAGD,qBAAe,CAAC,eAAe,CAAC,CAAC;AACnE,sBAAsB,MAAM,CAAC;AAC7B,oBAAoB,CAAC;AACrB,mBAAmB;AACnB,gBAAgB,OAAO;AACvB,kBAAkB,SAAS,GAAGA,qBAAe,CAAC,eAAe,CAAC,CAAC;AAC/D,kBAAkB,OAAO,MAAM;AAC/B,gBAAgB;AAChB,cAAc,CAAA,CAAE,OAAO,CAAC,EAAE;AAC1B,gBAAgBC,qBAAgB,CAAC,CAAC,EAAE;AACpC,kBAAkB,SAAS,EAAE;AAC7B,oBAAoB,IAAI,EAAE,qCAAqC;AAC/D,oBAAoB,OAAO,EAAE,KAAK;AAClC,mBAAmB;AACnB,iBAAiB,CAAC;AAClB,gBAAgB,SAAS,GAAGD,qBAAe,CAAC,eAAe,CAAC,CAAC;AAC7D,gBAAgB,MAAM,CAAC;AACvB,cAAc;AACd,YAAY;;AAEZ,YAAY,MAAM,UAAA,GAAa,cAAc,CAAC;AAC9C,gBAAgB;AAChB,kBAAkB,CAACE,iCAA4B,GAAG,cAAc,CAAC,MAAM;AACvE,kBAAkB,CAACC,qCAAgC,GAAG,qCAAqC;AAC3F;AACA,gBAAgB,EAAE;;AAElB,YAAY,OAAOC,cAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,QAAQ,EAAE,UAAA,EAAY,EAAE,MAAM;AAClF,cAAc,IAAI;AAClB,gBAAgB,MAAM,MAAA,GAAS,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;;AAEnE,gBAAgB,IAAIL,eAAU,CAAC,MAAM,CAAC,EAAE;AACxC,kBAAkB,OAAO,MAAM,CAAC,IAAI;AACpC,oBAAoB,CAAC,GAAG,KAAc;AACtC,sBAAsB,SAAS,GAAGC,qBAAe,CAAC,eAAe,CAAC,CAAC;AACnE,sBAAsB,OAAO,GAAG;AAChC,oBAAoB,CAAC;AACrB,oBAAoB,CAAC,CAAC,KAAc;AACpC,sBAAsBC,qBAAgB,CAAC,CAAC,EAAE;AAC1C,wBAAwB,SAAS,EAAE;AACnC,0BAA0B,IAAI,EAAE,qCAAqC;AACrE,0BAA0B,OAAO,EAAE,KAAK;AACxC,yBAAyB;AACzB,uBAAuB,CAAC;AACxB,sBAAsB,SAAS,GAAGD,qBAAe,CAAC,eAAe,CAAC,CAAC;AACnE,sBAAsB,MAAM,CAAC;AAC7B,oBAAoB,CAAC;AACrB,mBAAmB;AACnB,gBAAgB,OAAO;AACvB,kBAAkB,SAAS,GAAGA,qBAAe,CAAC,eAAe,CAAC,CAAC;AAC/D,kBAAkB,OAAO,MAAM;AAC/B,gBAAgB;AAChB,cAAc,CAAA,CAAE,OAAO,CAAC,EAAE;AAC1B,gBAAgBC,qBAAgB,CAAC,CAAC,EAAE;AACpC,kBAAkB,SAAS,EAAE;AAC7B,oBAAoB,IAAI,EAAE,qCAAqC;AAC/D,oBAAoB,OAAO,EAAE,KAAK;AAClC,mBAAmB;AACnB,iBAAiB,CAAC;AAClB,gBAAgB,SAAS,GAAGD,qBAAe,CAAC,eAAe,CAAC,CAAC;AAC7D,gBAAgB,MAAM,CAAC;AACvB,cAAc;AACd,YAAY,CAAC,CAAC;AACd,UAAU,CAAC;;AAEX,UAAU,OAAO,eAAe,CAAC,eAAe,CAAC;AACjD,QAAQ,CAAC;AACT,OAAO,CAAC;AACR,IAAI,MAAM;AACV,GAAG;AACH;;;;"}
@@ -1,6 +1,6 @@
1
1
  import { captureException } from '@sentry/core';
2
2
  import { setAsyncLocalStorageAsyncContextStrategy } from './async.js';
3
- import { isInstrumented, markAsInstrumented } from './instrument.js';
3
+ import { ensureInstrumented, getInstrumented, markAsInstrumented } from './instrument.js';
4
4
  import { getFinalOptions } from './options.js';
5
5
  import { wrapRequestHandler } from './request.js';
6
6
  import { instrumentContext } from './utils/instrumentContext.js';
@@ -63,16 +63,18 @@ function instrumentDurableObjectWithSentry
63
63
 
64
64
  // Any other public methods on the Durable Object instance are RPC calls.
65
65
 
66
- if (obj.fetch && typeof obj.fetch === 'function' && !isInstrumented(obj.fetch)) {
67
- obj.fetch = new Proxy(obj.fetch, {
68
- apply(target, thisArg, args) {
69
- return wrapRequestHandler({ options, request: args[0], context }, () =>
70
- Reflect.apply(target, thisArg, args),
71
- );
72
- },
73
- });
74
-
75
- markAsInstrumented(obj.fetch);
66
+ if (obj.fetch && typeof obj.fetch === 'function') {
67
+ obj.fetch = ensureInstrumented(
68
+ obj.fetch,
69
+ original =>
70
+ new Proxy(original, {
71
+ apply(target, thisArg, args) {
72
+ return wrapRequestHandler({ options, request: args[0], context }, () => {
73
+ return Reflect.apply(target, thisArg, args);
74
+ });
75
+ },
76
+ }),
77
+ );
76
78
  }
77
79
 
78
80
  if (obj.alarm && typeof obj.alarm === 'function') {
@@ -173,7 +175,18 @@ function instrumentPrototype(target, methodsToInstrument) {
173
175
  methodNames.forEach(methodName => {
174
176
  const originalMethod = (proto )[methodName];
175
177
 
176
- if (!originalMethod || isInstrumented(originalMethod)) {
178
+ if (!originalMethod) {
179
+ return;
180
+ }
181
+
182
+ const existingInstrumented = getInstrumented(originalMethod);
183
+ if (existingInstrumented) {
184
+ Object.defineProperty(proto, methodName, {
185
+ value: existingInstrumented,
186
+ enumerable: false,
187
+ writable: true,
188
+ configurable: true,
189
+ });
177
190
  return;
178
191
  }
179
192
 
@@ -211,6 +224,11 @@ function instrumentPrototype(target, methodsToInstrument) {
211
224
  return wrapper.apply(this, args);
212
225
  };
213
226
 
227
+ // Only mark wrappedMethod as instrumented (not originalMethod → wrappedMethod).
228
+ // originalMethod must stay unmapped because wrappedMethod calls
229
+ // wrapMethodWithSentry(options, originalMethod) on each invocation to create
230
+ // a per-instance proxy. If originalMethod mapped to wrappedMethod, that call
231
+ // would return wrappedMethod itself, causing infinite recursion.
214
232
  markAsInstrumented(wrappedMethod);
215
233
 
216
234
  // Replace the prototype method
@@ -1 +1 @@
1
- {"version":3,"file":"durableobject.js","sources":["../../src/durableobject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport { captureException } from '@sentry/core';\nimport type { DurableObject } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { isInstrumented, markAsInstrumented } from './instrument';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport type { UncheckedMethod } from './wrapMethodWithSentry';\nimport { wrapMethodWithSentry } from './wrapMethodWithSentry';\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * as well as any other public RPC methods on the Durable Object instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param DurableObjectClass The Durable Object class to instrument.\n * @returns The instrumented Durable Object class.\n *\n * @example\n * ```ts\n * class MyDurableObjectBase extends DurableObject {\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env);\n * }\n * }\n *\n * export const MyDurableObject = instrumentDurableObjectWithSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyDurableObjectBase,\n * );\n * ```\n */\nexport function instrumentDurableObjectWithSentry<\n E,\n T extends DurableObject<E>,\n C extends new (state: DurableObjectState, env: E) => T,\n>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {\n return new Proxy(DurableObjectClass, {\n construct(target, [ctx, env]) {\n setAsyncLocalStorageAsyncContextStrategy();\n const context = instrumentContext(ctx);\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n const obj = new target(context, env);\n\n // These are the methods that are available on a Durable Object\n // ref: https://developers.cloudflare.com/durable-objects/api/base/\n // obj.alarm\n // obj.fetch\n // obj.webSocketError\n // obj.webSocketClose\n // obj.webSocketMessage\n\n // Any other public methods on the Durable Object instance are RPC calls.\n\n if (obj.fetch && typeof obj.fetch === 'function' && !isInstrumented(obj.fetch)) {\n obj.fetch = new Proxy(obj.fetch, {\n apply(target, thisArg, args) {\n return wrapRequestHandler({ options, request: args[0], context }, () =>\n Reflect.apply(target, thisArg, args),\n );\n },\n });\n\n markAsInstrumented(obj.fetch);\n }\n\n if (obj.alarm && typeof obj.alarm === 'function') {\n obj.alarm = wrapMethodWithSentry({ options, context, spanName: 'alarm' }, obj.alarm);\n }\n\n if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {\n obj.webSocketMessage = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketMessage' },\n obj.webSocketMessage,\n );\n }\n\n if (obj.webSocketClose && typeof obj.webSocketClose === 'function') {\n obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);\n }\n\n if (obj.webSocketError && typeof obj.webSocketError === 'function') {\n obj.webSocketError = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketError' },\n obj.webSocketError,\n (_, error) =>\n captureException(error, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object_websocket',\n handled: false,\n },\n }),\n );\n }\n\n for (const method of Object.getOwnPropertyNames(obj)) {\n if (\n method === 'fetch' ||\n method === 'alarm' ||\n method === 'webSocketError' ||\n method === 'webSocketClose' ||\n method === 'webSocketMessage'\n ) {\n continue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n const value = (obj as any)[method] as unknown;\n if (typeof value === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n (obj as any)[method] = wrapMethodWithSentry(\n { options, context, spanName: method, spanOp: 'rpc' },\n value as UncheckedMethod,\n );\n }\n }\n\n // Store context and options on the instance for prototype methods to access\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n if (options?.instrumentPrototypeMethods) {\n instrumentPrototype(target, options.instrumentPrototypeMethods);\n }\n\n return obj;\n },\n });\n}\n\nfunction instrumentPrototype<T extends NewableFunction>(target: T, methodsToInstrument: boolean | string[]): void {\n const proto = target.prototype;\n\n // Get all methods from the prototype chain\n const methodNames = new Set<string>();\n let current = proto;\n\n while (current && current !== Object.prototype) {\n Object.getOwnPropertyNames(current).forEach(name => {\n if (name !== 'constructor' && typeof (current as Record<string, unknown>)[name] === 'function') {\n methodNames.add(name);\n }\n });\n current = Object.getPrototypeOf(current);\n }\n\n // Create a set for efficient lookups when methodsToInstrument is an array\n const methodsToInstrumentSet = Array.isArray(methodsToInstrument) ? new Set(methodsToInstrument) : null;\n\n // Instrument each method on the prototype\n methodNames.forEach(methodName => {\n const originalMethod = (proto as Record<string, unknown>)[methodName];\n\n if (!originalMethod || isInstrumented(originalMethod)) {\n return;\n }\n\n // If methodsToInstrument is an array, only instrument methods in that set\n if (methodsToInstrumentSet && !methodsToInstrumentSet.has(methodName)) {\n return;\n }\n\n // Create a wrapper that gets context/options from the instance at runtime\n const wrappedMethod = function (this: unknown, ...args: unknown[]): unknown {\n const thisWithSentry = this as {\n __SENTRY_CONTEXT__: DurableObjectState;\n __SENTRY_OPTIONS__: CloudflareOptions;\n };\n const instanceContext = thisWithSentry.__SENTRY_CONTEXT__;\n const instanceOptions = thisWithSentry.__SENTRY_OPTIONS__;\n\n if (!instanceOptions) {\n // Fallback to original method if no Sentry data found\n return (originalMethod as UncheckedMethod).apply(this, args);\n }\n\n // Use the existing wrapper but with instance-specific context/options\n const wrapper = wrapMethodWithSentry(\n {\n options: instanceOptions,\n context: instanceContext,\n spanName: methodName,\n spanOp: 'rpc',\n },\n originalMethod as UncheckedMethod,\n undefined,\n true, // noMark = true since we'll mark the prototype method\n );\n\n return wrapper.apply(this, args);\n };\n\n markAsInstrumented(wrappedMethod);\n\n // Replace the prototype method\n Object.defineProperty(proto, methodName, {\n value: wrappedMethod,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"durableobject.js","sources":["../../src/durableobject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport { captureException } from '@sentry/core';\nimport type { DurableObject } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { ensureInstrumented, getInstrumented, markAsInstrumented } from './instrument';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport type { UncheckedMethod } from './wrapMethodWithSentry';\nimport { wrapMethodWithSentry } from './wrapMethodWithSentry';\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * as well as any other public RPC methods on the Durable Object instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param DurableObjectClass The Durable Object class to instrument.\n * @returns The instrumented Durable Object class.\n *\n * @example\n * ```ts\n * class MyDurableObjectBase extends DurableObject {\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env);\n * }\n * }\n *\n * export const MyDurableObject = instrumentDurableObjectWithSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyDurableObjectBase,\n * );\n * ```\n */\nexport function instrumentDurableObjectWithSentry<\n E,\n T extends DurableObject<E>,\n C extends new (state: DurableObjectState, env: E) => T,\n>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {\n return new Proxy(DurableObjectClass, {\n construct(target, [ctx, env]) {\n setAsyncLocalStorageAsyncContextStrategy();\n const context = instrumentContext(ctx);\n\n const options = getFinalOptions(optionsCallback(env), env);\n\n const obj = new target(context, env);\n\n // These are the methods that are available on a Durable Object\n // ref: https://developers.cloudflare.com/durable-objects/api/base/\n // obj.alarm\n // obj.fetch\n // obj.webSocketError\n // obj.webSocketClose\n // obj.webSocketMessage\n\n // Any other public methods on the Durable Object instance are RPC calls.\n\n if (obj.fetch && typeof obj.fetch === 'function') {\n obj.fetch = ensureInstrumented(\n obj.fetch,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args) {\n return wrapRequestHandler({ options, request: args[0], context }, () => {\n return Reflect.apply(target, thisArg, args);\n });\n },\n }),\n );\n }\n\n if (obj.alarm && typeof obj.alarm === 'function') {\n obj.alarm = wrapMethodWithSentry({ options, context, spanName: 'alarm' }, obj.alarm);\n }\n\n if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {\n obj.webSocketMessage = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketMessage' },\n obj.webSocketMessage,\n );\n }\n\n if (obj.webSocketClose && typeof obj.webSocketClose === 'function') {\n obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);\n }\n\n if (obj.webSocketError && typeof obj.webSocketError === 'function') {\n obj.webSocketError = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketError' },\n obj.webSocketError,\n (_, error) =>\n captureException(error, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object_websocket',\n handled: false,\n },\n }),\n );\n }\n\n for (const method of Object.getOwnPropertyNames(obj)) {\n if (\n method === 'fetch' ||\n method === 'alarm' ||\n method === 'webSocketError' ||\n method === 'webSocketClose' ||\n method === 'webSocketMessage'\n ) {\n continue;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n const value = (obj as any)[method] as unknown;\n if (typeof value === 'function') {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n (obj as any)[method] = wrapMethodWithSentry(\n { options, context, spanName: method, spanOp: 'rpc' },\n value as UncheckedMethod,\n );\n }\n }\n\n // Store context and options on the instance for prototype methods to access\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n if (options?.instrumentPrototypeMethods) {\n instrumentPrototype(target, options.instrumentPrototypeMethods);\n }\n\n return obj;\n },\n });\n}\n\nfunction instrumentPrototype<T extends NewableFunction>(target: T, methodsToInstrument: boolean | string[]): void {\n const proto = target.prototype;\n\n // Get all methods from the prototype chain\n const methodNames = new Set<string>();\n let current = proto;\n\n while (current && current !== Object.prototype) {\n Object.getOwnPropertyNames(current).forEach(name => {\n if (name !== 'constructor' && typeof (current as Record<string, unknown>)[name] === 'function') {\n methodNames.add(name);\n }\n });\n current = Object.getPrototypeOf(current);\n }\n\n // Create a set for efficient lookups when methodsToInstrument is an array\n const methodsToInstrumentSet = Array.isArray(methodsToInstrument) ? new Set(methodsToInstrument) : null;\n\n // Instrument each method on the prototype\n methodNames.forEach(methodName => {\n const originalMethod = (proto as Record<string, unknown>)[methodName];\n\n if (!originalMethod) {\n return;\n }\n\n const existingInstrumented = getInstrumented(originalMethod);\n if (existingInstrumented) {\n Object.defineProperty(proto, methodName, {\n value: existingInstrumented,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n return;\n }\n\n // If methodsToInstrument is an array, only instrument methods in that set\n if (methodsToInstrumentSet && !methodsToInstrumentSet.has(methodName)) {\n return;\n }\n\n // Create a wrapper that gets context/options from the instance at runtime\n const wrappedMethod = function (this: unknown, ...args: unknown[]): unknown {\n const thisWithSentry = this as {\n __SENTRY_CONTEXT__: DurableObjectState;\n __SENTRY_OPTIONS__: CloudflareOptions;\n };\n const instanceContext = thisWithSentry.__SENTRY_CONTEXT__;\n const instanceOptions = thisWithSentry.__SENTRY_OPTIONS__;\n\n if (!instanceOptions) {\n // Fallback to original method if no Sentry data found\n return (originalMethod as UncheckedMethod).apply(this, args);\n }\n\n // Use the existing wrapper but with instance-specific context/options\n const wrapper = wrapMethodWithSentry(\n {\n options: instanceOptions,\n context: instanceContext,\n spanName: methodName,\n spanOp: 'rpc',\n },\n originalMethod as UncheckedMethod,\n undefined,\n true, // noMark = true since we'll mark the prototype method\n );\n\n return wrapper.apply(this, args);\n };\n\n // Only mark wrappedMethod as instrumented (not originalMethod → wrappedMethod).\n // originalMethod must stay unmapped because wrappedMethod calls\n // wrapMethodWithSentry(options, originalMethod) on each invocation to create\n // a per-instance proxy. If originalMethod mapped to wrappedMethod, that call\n // would return wrappedMethod itself, causing infinite recursion.\n markAsInstrumented(wrappedMethod);\n\n // Replace the prototype method\n Object.defineProperty(proto, methodName, {\n value: wrappedMethod,\n enumerable: false,\n writable: true,\n configurable: true,\n });\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createLangChainCallbackHandler, createTransport, dedupeIntegration, eventFiltersIntegration, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, growthbookIntegration, inboundFiltersIntegration, instrumentAnthropicAiClient, instrumentGoogleGenAIClient, instrumentLangGraph, instrumentOpenAiClient, instrumentPostgresJsSql, instrumentSupabaseClient, isEnabled, isInitialized, lastEventId, linkedErrorsIntegration, logger, metrics, moduleMetadataIntegration, requestDataIntegration, rewriteFramesIntegration, setContext, setConversationId, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, spanToBaggageHeader, spanToJSON, spanToTraceHeader, startInactiveSpan, startNewTrace, startSpan, startSpanManual, supabaseIntegration, suppressTracing, trpcMiddleware, updateSpanName, withActiveSpan, withIsolationScope, withMonitor, withScope, wrapMcpServerWithSentry, zodErrorsIntegration } from '@sentry/core';
1
+ export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createLangChainCallbackHandler, createTransport, dedupeIntegration, eventFiltersIntegration, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, growthbookIntegration, inboundFiltersIntegration, instrumentAnthropicAiClient, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentLangGraph, instrumentOpenAiClient, instrumentPostgresJsSql, instrumentSupabaseClient, isEnabled, isInitialized, lastEventId, linkedErrorsIntegration, logger, metrics, moduleMetadataIntegration, requestDataIntegration, rewriteFramesIntegration, setContext, setConversationId, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, spanToBaggageHeader, spanToJSON, spanToTraceHeader, startInactiveSpan, startNewTrace, startSpan, startSpanManual, supabaseIntegration, suppressTracing, trpcMiddleware, updateSpanName, withActiveSpan, withIsolationScope, withMonitor, withScope, withStreamedSpan, wrapMcpServerWithSentry, zodErrorsIntegration } from '@sentry/core';
2
2
  export { withSentry } from './withSentry.js';
3
3
  export { instrumentDurableObjectWithSentry } from './durableobject.js';
4
4
  export { sentryPagesPlugin } from './pages-plugin.js';
@@ -1,24 +1,87 @@
1
+ // Use a global WeakMap to track instrumented objects across module instances.
2
+ // This is important for Cloudflare Workers where the module may be bundled
3
+ // separately for workers and Durable Objects, but they share the same global scope.
4
+ // The WeakMap stores original -> instrumented mappings so we can retrieve the
5
+ // instrumented version even if we only have a reference to the original.
6
+ const GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' ;
7
+
8
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
9
+ function getInstrumentedMap() {
10
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
11
+ const globalObj = globalThis ;
12
+ if (!globalObj[GLOBAL_KEY]) {
13
+ globalObj[GLOBAL_KEY] = new WeakMap();
14
+ }
15
+ return globalObj[GLOBAL_KEY];
16
+ }
17
+
18
+ /**
19
+ * Check if a value can be used as a WeakMap key.
20
+ * WeakMap keys must be objects or non-registered symbols.
21
+ */
22
+ function isWeakMapKey(value) {
23
+ return (typeof value === 'object' && value !== null) || typeof value === 'function';
24
+ }
25
+
1
26
  /**
2
- * Mark an object as instrumented.
27
+ * Mark an object as instrumented, storing the instrumented version.
28
+ * @param original The original uninstrumented object
29
+ * @param instrumented The instrumented version (defaults to original if not provided)
3
30
  */
4
- function markAsInstrumented(obj) {
31
+ function markAsInstrumented(original, instrumented) {
5
32
  try {
6
- (obj ).__SENTRY_INSTRUMENTED__ = true;
33
+ if (isWeakMapKey(original)) {
34
+ // Store mapping from original to instrumented version
35
+ // If instrumented is not provided, store original (for backwards compat)
36
+ getInstrumentedMap().set(original, instrumented ?? original);
37
+ }
38
+ // Also mark the instrumented version itself so we recognize it
39
+ if (isWeakMapKey(instrumented) && instrumented !== original) {
40
+ getInstrumentedMap().set(instrumented, instrumented);
41
+ }
7
42
  } catch {
8
43
  // ignore errors here
9
44
  }
10
45
  }
11
46
 
12
47
  /**
13
- * Check if an object is instrumented.
48
+ * Get the instrumented version of an object, if available.
49
+ * Returns the instrumented version if the object was previously instrumented,
50
+ * or undefined if not found.
14
51
  */
15
- function isInstrumented(obj) {
52
+ function getInstrumented(obj) {
16
53
  try {
17
- return (obj ).__SENTRY_INSTRUMENTED__;
54
+ if (isWeakMapKey(obj)) {
55
+ return getInstrumentedMap().get(obj) ;
56
+ }
57
+
58
+ return undefined;
18
59
  } catch {
19
- return false;
60
+ return undefined;
20
61
  }
21
62
  }
22
63
 
23
- export { isInstrumented, markAsInstrumented };
64
+ /**
65
+ * Returns the already-instrumented version of `original` if one exists,
66
+ * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.
67
+ *
68
+ * @param noMark - If true, skips storing the original→instrumented mapping.
69
+ */
70
+ function ensureInstrumented(original, instrumentFn, noMark) {
71
+ const existing = getInstrumented(original);
72
+
73
+ if (existing) {
74
+ return existing;
75
+ }
76
+
77
+ const instrumented = instrumentFn(original);
78
+
79
+ if (!noMark) {
80
+ markAsInstrumented(original, instrumented);
81
+ }
82
+
83
+ return instrumented;
84
+ }
85
+
86
+ export { ensureInstrumented, getInstrumented, markAsInstrumented };
24
87
  //# sourceMappingURL=instrument.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instrument.js","sources":["../../src/instrument.ts"],"sourcesContent":["type SentryInstrumented<T> = T & {\n __SENTRY_INSTRUMENTED__?: boolean;\n};\n\n/**\n * Mark an object as instrumented.\n */\nexport function markAsInstrumented<T>(obj: T): void {\n try {\n (obj as SentryInstrumented<T>).__SENTRY_INSTRUMENTED__ = true;\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Check if an object is instrumented.\n */\nexport function isInstrumented<T>(obj: T): boolean | undefined {\n try {\n return (obj as SentryInstrumented<T>).__SENTRY_INSTRUMENTED__;\n } catch {\n return false;\n }\n}\n"],"names":[],"mappings":"AAIA;AACA;AACA;AACO,SAAS,kBAAkB,CAAI,GAAG,EAAW;AACpD,EAAE,IAAI;AACN,IAAI,CAAC,GAAA,GAA8B,uBAAA,GAA0B,IAAI;AACjE,EAAE,EAAE,MAAM;AACV;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACO,SAAS,cAAc,CAAI,GAAG,EAA0B;AAC/D,EAAE,IAAI;AACN,IAAI,OAAO,CAAC,GAAA,GAA8B,uBAAuB;AACjE,EAAE,EAAE,MAAM;AACV,IAAI,OAAO,KAAK;AAChB,EAAE;AACF;;;;"}
1
+ {"version":3,"file":"instrument.js","sources":["../../src/instrument.ts"],"sourcesContent":["// Use a global WeakMap to track instrumented objects across module instances.\n// This is important for Cloudflare Workers where the module may be bundled\n// separately for workers and Durable Objects, but they share the same global scope.\n// The WeakMap stores original -> instrumented mappings so we can retrieve the\n// instrumented version even if we only have a reference to the original.\nconst GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getInstrumentedMap(): WeakMap<any, any> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObj = globalThis as typeof globalThis & { [GLOBAL_KEY]?: WeakMap<any, any> };\n if (!globalObj[GLOBAL_KEY]) {\n globalObj[GLOBAL_KEY] = new WeakMap();\n }\n return globalObj[GLOBAL_KEY];\n}\n\n/**\n * Check if a value can be used as a WeakMap key.\n * WeakMap keys must be objects or non-registered symbols.\n */\nfunction isWeakMapKey(value: unknown): value is object {\n return (typeof value === 'object' && value !== null) || typeof value === 'function';\n}\n\n/**\n * Mark an object as instrumented, storing the instrumented version.\n * @param original The original uninstrumented object\n * @param instrumented The instrumented version (defaults to original if not provided)\n */\nexport function markAsInstrumented<T>(original: T, instrumented?: T): void {\n try {\n if (isWeakMapKey(original)) {\n // Store mapping from original to instrumented version\n // If instrumented is not provided, store original (for backwards compat)\n getInstrumentedMap().set(original, instrumented ?? original);\n }\n // Also mark the instrumented version itself so we recognize it\n if (isWeakMapKey(instrumented) && instrumented !== original) {\n getInstrumentedMap().set(instrumented, instrumented);\n }\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Get the instrumented version of an object, if available.\n * Returns the instrumented version if the object was previously instrumented,\n * or undefined if not found.\n */\nexport function getInstrumented<T>(obj: T): T | undefined {\n try {\n if (isWeakMapKey(obj)) {\n return getInstrumentedMap().get(obj) as T | undefined;\n }\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns the already-instrumented version of `original` if one exists,\n * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.\n *\n * @param noMark - If true, skips storing the original→instrumented mapping.\n */\nexport function ensureInstrumented<T>(original: T, instrumentFn: (original: T) => T, noMark?: boolean): T {\n const existing = getInstrumented(original);\n\n if (existing) {\n return existing;\n }\n\n const instrumented = instrumentFn(original);\n\n if (!noMark) {\n markAsInstrumented(original, instrumented);\n }\n\n return instrumented;\n}\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA,MAAM,UAAA,GAAa,6BAAA;;AAEnB;AACA,SAAS,kBAAkB,GAAsB;AACjD;AACA,EAAE,MAAM,SAAA,GAAY,UAAA;AACpB,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;AAC9B,IAAI,SAAS,CAAC,UAAU,CAAA,GAAI,IAAI,OAAO,EAAE;AACzC,EAAE;AACF,EAAE,OAAO,SAAS,CAAC,UAAU,CAAC;AAC9B;;AAEA;AACA;AACA;AACA;AACA,SAAS,YAAY,CAAC,KAAK,EAA4B;AACvD,EAAE,OAAO,CAAC,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAI,KAAK,OAAO,KAAA,KAAU,UAAU;AACrF;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAI,QAAQ,EAAK,YAAY,EAAY;AAC3E,EAAE,IAAI;AACN,IAAI,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE;AAChC;AACA;AACA,MAAM,kBAAkB,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,YAAA,IAAgB,QAAQ,CAAC;AAClE,IAAI;AACJ;AACA,IAAI,IAAI,YAAY,CAAC,YAAY,KAAK,YAAA,KAAiB,QAAQ,EAAE;AACjE,MAAM,kBAAkB,EAAE,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;AAC1D,IAAI;AACJ,EAAE,EAAE,MAAM;AACV;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA;AACO,SAAS,eAAe,CAAI,GAAG,EAAoB;AAC1D,EAAE,IAAI;AACN,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,EAAE;AAC3B,MAAM,OAAO,kBAAkB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAA;AACzC,IAAI;;AAEJ,IAAI,OAAO,SAAS;AACpB,EAAE,EAAE,MAAM;AACV,IAAI,OAAO,SAAS;AACpB,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,kBAAkB,CAAI,QAAQ,EAAK,YAAY,EAAsB,MAAM,EAAe;AAC1G,EAAE,MAAM,QAAA,GAAW,eAAe,CAAC,QAAQ,CAAC;;AAE5C,EAAE,IAAI,QAAQ,EAAE;AAChB,IAAI,OAAO,QAAQ;AACnB,EAAE;;AAEF,EAAE,MAAM,YAAA,GAAe,YAAY,CAAC,QAAQ,CAAC;;AAE7C,EAAE,IAAI,CAAC,MAAM,EAAE;AACf,IAAI,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC;AAC9C,EAAE;;AAEF,EAAE,OAAO,YAAY;AACrB;;;;"}