@sentry/cloudflare 10.53.1 → 10.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/async.js +4 -30
- package/build/cjs/async.js.map +1 -1
- package/build/cjs/client.js +31 -58
- package/build/cjs/client.js.map +1 -1
- package/build/cjs/d1.js +26 -80
- package/build/cjs/d1.js.map +1 -1
- package/build/cjs/debug-build.js +0 -5
- package/build/cjs/debug-build.js.map +1 -1
- package/build/cjs/durableobject.js +44 -131
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/flush.js +53 -34
- package/build/cjs/flush.js.map +1 -1
- package/build/cjs/instrument.js +7 -48
- package/build/cjs/instrument.js.map +1 -1
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js +9 -34
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js +20 -54
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js +12 -66
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEmail.js +21 -43
- package/build/cjs/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEnv.js +12 -42
- package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentFetch.js +20 -34
- package/build/cjs/instrumentations/worker/instrumentFetch.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentFetcher.js +5 -19
- package/build/cjs/instrumentations/worker/instrumentFetcher.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentQueue.js +30 -62
- package/build/cjs/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentQueueProducer.js +31 -57
- package/build/cjs/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentScheduled.js +25 -54
- package/build/cjs/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentTail.js +16 -43
- package/build/cjs/instrumentations/worker/instrumentTail.js.map +1 -1
- package/build/cjs/integrations/fetch.js +24 -56
- package/build/cjs/integrations/fetch.js.map +1 -1
- package/build/cjs/integrations/hono.js +7 -38
- package/build/cjs/integrations/hono.js.map +1 -1
- package/build/cjs/integrations/httpServer.js +6 -39
- package/build/cjs/integrations/httpServer.js.map +1 -1
- package/build/cjs/integrations/tracing/vercelai.js +3 -31
- package/build/cjs/integrations/tracing/vercelai.js.map +1 -1
- package/build/cjs/opentelemetry/tracer.js +17 -45
- package/build/cjs/opentelemetry/tracer.js.map +1 -1
- package/build/cjs/options.js +10 -46
- package/build/cjs/options.js.map +1 -1
- package/build/cjs/pages-plugin.js +9 -42
- package/build/cjs/pages-plugin.js.map +1 -1
- package/build/cjs/request.js +22 -68
- package/build/cjs/request.js.map +1 -1
- package/build/cjs/scope-utils.js +4 -15
- package/build/cjs/scope-utils.js.map +1 -1
- package/build/cjs/sdk.js +8 -25
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/transport.js +14 -48
- package/build/cjs/transport.js.map +1 -1
- package/build/cjs/utils/instrumentContext.js +16 -52
- package/build/cjs/utils/instrumentContext.js.map +1 -1
- package/build/cjs/utils/isBinding.js +3 -23
- package/build/cjs/utils/isBinding.js.map +1 -1
- package/build/cjs/utils/isCloudflareClass.js +2 -8
- package/build/cjs/utils/isCloudflareClass.js.map +1 -1
- package/build/cjs/utils/rpcMeta.js +8 -32
- package/build/cjs/utils/rpcMeta.js.map +1 -1
- package/build/cjs/utils/rpcOptions.js +9 -32
- package/build/cjs/utils/rpcOptions.js.map +1 -1
- package/build/cjs/utils/streaming.js +3 -29
- package/build/cjs/utils/streaming.js.map +1 -1
- package/build/cjs/utils/traceLinks.js +8 -33
- package/build/cjs/utils/traceLinks.js.map +1 -1
- package/build/cjs/vendor/stacktrace.js +6 -27
- package/build/cjs/vendor/stacktrace.js.map +1 -1
- package/build/cjs/withSentry.js +16 -47
- package/build/cjs/withSentry.js.map +1 -1
- package/build/cjs/workflows.js +40 -100
- package/build/cjs/workflows.js.map +1 -1
- package/build/cjs/wrapMethodWithSentry.js +110 -167
- package/build/cjs/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/async.js +4 -30
- package/build/esm/async.js.map +1 -1
- package/build/esm/client.js +31 -58
- package/build/esm/client.js.map +1 -1
- package/build/esm/d1.js +26 -80
- package/build/esm/d1.js.map +1 -1
- package/build/esm/debug-build.js +0 -5
- package/build/esm/debug-build.js.map +1 -1
- package/build/esm/durableobject.js +44 -131
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/flush.js +53 -35
- package/build/esm/flush.js.map +1 -1
- package/build/esm/instrument.js +7 -48
- package/build/esm/instrument.js.map +1 -1
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js +9 -34
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js +20 -54
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js +12 -66
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEmail.js +21 -43
- package/build/esm/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEnv.js +12 -42
- package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentFetch.js +20 -34
- package/build/esm/instrumentations/worker/instrumentFetch.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentFetcher.js +5 -19
- package/build/esm/instrumentations/worker/instrumentFetcher.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentQueue.js +30 -62
- package/build/esm/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentQueueProducer.js +31 -57
- package/build/esm/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentScheduled.js +25 -54
- package/build/esm/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentTail.js +16 -43
- package/build/esm/instrumentations/worker/instrumentTail.js.map +1 -1
- package/build/esm/integrations/fetch.js +24 -56
- package/build/esm/integrations/fetch.js.map +1 -1
- package/build/esm/integrations/hono.js +7 -38
- package/build/esm/integrations/hono.js.map +1 -1
- package/build/esm/integrations/httpServer.js +6 -39
- package/build/esm/integrations/httpServer.js.map +1 -1
- package/build/esm/integrations/tracing/vercelai.js +3 -31
- package/build/esm/integrations/tracing/vercelai.js.map +1 -1
- package/build/esm/opentelemetry/tracer.js +17 -45
- package/build/esm/opentelemetry/tracer.js.map +1 -1
- package/build/esm/options.js +10 -46
- package/build/esm/options.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/pages-plugin.js +9 -42
- package/build/esm/pages-plugin.js.map +1 -1
- package/build/esm/request.js +23 -69
- package/build/esm/request.js.map +1 -1
- package/build/esm/scope-utils.js +4 -15
- package/build/esm/scope-utils.js.map +1 -1
- package/build/esm/sdk.js +8 -25
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/transport.js +14 -48
- package/build/esm/transport.js.map +1 -1
- package/build/esm/utils/instrumentContext.js +16 -52
- package/build/esm/utils/instrumentContext.js.map +1 -1
- package/build/esm/utils/isBinding.js +3 -23
- package/build/esm/utils/isBinding.js.map +1 -1
- package/build/esm/utils/isCloudflareClass.js +2 -8
- package/build/esm/utils/isCloudflareClass.js.map +1 -1
- package/build/esm/utils/rpcMeta.js +8 -32
- package/build/esm/utils/rpcMeta.js.map +1 -1
- package/build/esm/utils/rpcOptions.js +9 -32
- package/build/esm/utils/rpcOptions.js.map +1 -1
- package/build/esm/utils/streaming.js +3 -29
- package/build/esm/utils/streaming.js.map +1 -1
- package/build/esm/utils/traceLinks.js +8 -33
- package/build/esm/utils/traceLinks.js.map +1 -1
- package/build/esm/vendor/stacktrace.js +6 -27
- package/build/esm/vendor/stacktrace.js.map +1 -1
- package/build/esm/withSentry.js +16 -47
- package/build/esm/withSentry.js.map +1 -1
- package/build/esm/workflows.js +40 -100
- package/build/esm/workflows.js.map +1 -1
- package/build/esm/wrapMethodWithSentry.js +110 -167
- package/build/esm/wrapMethodWithSentry.js.map +1 -1
- package/build/types/client.d.ts.map +1 -1
- package/build/types/flush.d.ts +15 -0
- package/build/types/flush.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentFetch.d.ts.map +1 -1
- package/build/types/integrations/hono.d.ts +3 -0
- package/build/types/integrations/hono.d.ts.map +1 -1
- package/build/types/pages-plugin.d.ts.map +1 -1
- package/build/types/request.d.ts.map +1 -1
- package/build/types-ts3.8/flush.d.ts +15 -0
- package/build/types-ts3.8/integrations/hono.d.ts +3 -0
- package/package.json +2 -2
|
@@ -8,182 +8,95 @@ import { instrumentContext } from './utils/instrumentContext.js';
|
|
|
8
8
|
import { getEffectiveRpcPropagation } from './utils/rpcOptions.js';
|
|
9
9
|
import { wrapMethodWithSentry } from './wrapMethodWithSentry.js';
|
|
10
10
|
|
|
11
|
-
/*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
'webSocketClose',
|
|
19
|
-
'webSocketMessage',
|
|
11
|
+
const BUILT_IN_DO_METHODS = /* @__PURE__ */ new Set([
|
|
12
|
+
"constructor",
|
|
13
|
+
"fetch",
|
|
14
|
+
"alarm",
|
|
15
|
+
"webSocketError",
|
|
16
|
+
"webSocketClose",
|
|
17
|
+
"webSocketMessage"
|
|
20
18
|
]);
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Instruments a Durable Object class to capture errors and performance data.
|
|
24
|
-
*
|
|
25
|
-
* Instruments the following methods by default:
|
|
26
|
-
* - fetch
|
|
27
|
-
* - alarm
|
|
28
|
-
* - webSocketMessage
|
|
29
|
-
* - webSocketClose
|
|
30
|
-
* - webSocketError
|
|
31
|
-
*
|
|
32
|
-
* To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option.
|
|
33
|
-
*
|
|
34
|
-
* @param optionsCallback Function that returns the options for the SDK initialization.
|
|
35
|
-
* @param DurableObjectClass The Durable Object class to instrument.
|
|
36
|
-
* @returns The instrumented Durable Object class.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* class MyDurableObjectBase extends DurableObject {
|
|
41
|
-
* constructor(ctx: DurableObjectState, env: Env) {
|
|
42
|
-
* super(ctx, env);
|
|
43
|
-
* }
|
|
44
|
-
* }
|
|
45
|
-
*
|
|
46
|
-
* export const MyDurableObject = instrumentDurableObjectWithSentry(
|
|
47
|
-
* env => ({
|
|
48
|
-
* dsn: env.SENTRY_DSN,
|
|
49
|
-
* tracesSampleRate: 1.0,
|
|
50
|
-
* }),
|
|
51
|
-
* MyDurableObjectBase,
|
|
52
|
-
* );
|
|
53
|
-
* ```
|
|
54
|
-
*/
|
|
55
|
-
function instrumentDurableObjectWithSentry
|
|
56
|
-
|
|
57
|
-
(optionsCallback, DurableObjectClass) {
|
|
19
|
+
function instrumentDurableObjectWithSentry(optionsCallback, DurableObjectClass) {
|
|
58
20
|
return new Proxy(DurableObjectClass, {
|
|
59
21
|
construct(target, [ctx, env]) {
|
|
60
22
|
setAsyncLocalStorageAsyncContextStrategy();
|
|
61
23
|
const context = instrumentContext(ctx);
|
|
62
24
|
const options = getFinalOptions(optionsCallback(env), env);
|
|
63
25
|
const instrumentedEnv = instrumentEnv(env, options);
|
|
64
|
-
|
|
65
26
|
const obj = new target(context, instrumentedEnv);
|
|
66
|
-
|
|
67
|
-
// These are the methods that are available on a Durable Object
|
|
68
|
-
// ref: https://developers.cloudflare.com/durable-objects/api/base/
|
|
69
|
-
// obj.alarm
|
|
70
|
-
// obj.fetch
|
|
71
|
-
// obj.webSocketError
|
|
72
|
-
// obj.webSocketClose
|
|
73
|
-
// obj.webSocketMessage
|
|
74
|
-
|
|
75
|
-
// Any other public methods on the Durable Object instance are RPC calls.
|
|
76
|
-
|
|
77
|
-
if (obj.fetch && typeof obj.fetch === 'function') {
|
|
27
|
+
if (obj.fetch && typeof obj.fetch === "function") {
|
|
78
28
|
obj.fetch = ensureInstrumented(
|
|
79
29
|
obj.fetch,
|
|
80
|
-
original =>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}),
|
|
30
|
+
(original) => new Proxy(original, {
|
|
31
|
+
apply(target2, thisArg, args) {
|
|
32
|
+
return wrapRequestHandler({ options, request: args[0], context }, () => {
|
|
33
|
+
return Reflect.apply(target2, thisArg, args);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
})
|
|
88
37
|
);
|
|
89
38
|
}
|
|
90
|
-
|
|
91
|
-
if (obj.alarm && typeof obj.alarm === 'function') {
|
|
92
|
-
// Alarms are independent invocations, so we start a new trace and link to the previous alarm
|
|
39
|
+
if (obj.alarm && typeof obj.alarm === "function") {
|
|
93
40
|
obj.alarm = wrapMethodWithSentry(
|
|
94
|
-
{ options, context, spanName:
|
|
95
|
-
obj.alarm
|
|
41
|
+
{ options, context, spanName: "alarm", spanOp: "function", startNewTrace: true },
|
|
42
|
+
obj.alarm
|
|
96
43
|
);
|
|
97
44
|
}
|
|
98
|
-
|
|
99
|
-
if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {
|
|
45
|
+
if (obj.webSocketMessage && typeof obj.webSocketMessage === "function") {
|
|
100
46
|
obj.webSocketMessage = wrapMethodWithSentry(
|
|
101
|
-
{ options, context, spanName:
|
|
102
|
-
obj.webSocketMessage
|
|
47
|
+
{ options, context, spanName: "webSocketMessage" },
|
|
48
|
+
obj.webSocketMessage
|
|
103
49
|
);
|
|
104
50
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);
|
|
51
|
+
if (obj.webSocketClose && typeof obj.webSocketClose === "function") {
|
|
52
|
+
obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: "webSocketClose" }, obj.webSocketClose);
|
|
108
53
|
}
|
|
109
|
-
|
|
110
|
-
if (obj.webSocketError && typeof obj.webSocketError === 'function') {
|
|
54
|
+
if (obj.webSocketError && typeof obj.webSocketError === "function") {
|
|
111
55
|
obj.webSocketError = wrapMethodWithSentry(
|
|
112
|
-
{ options, context, spanName:
|
|
56
|
+
{ options, context, spanName: "webSocketError" },
|
|
113
57
|
obj.webSocketError,
|
|
114
|
-
(_, error) =>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}),
|
|
58
|
+
(_, error) => captureException(error, {
|
|
59
|
+
mechanism: {
|
|
60
|
+
type: "auto.faas.cloudflare.durable_object_websocket",
|
|
61
|
+
handled: false
|
|
62
|
+
}
|
|
63
|
+
})
|
|
121
64
|
);
|
|
122
65
|
}
|
|
123
|
-
|
|
124
|
-
// Get effective RPC propagation setting (handles deprecation of instrumentPrototypeMethods)
|
|
125
66
|
const rpcPropagation = getEffectiveRpcPropagation(options);
|
|
126
|
-
|
|
127
|
-
// Skip RPC instrumentation if not enabled
|
|
128
67
|
if (!rpcPropagation) {
|
|
129
68
|
return obj;
|
|
130
69
|
}
|
|
131
|
-
|
|
132
|
-
// If `instrumentPrototypeMethods` was passed as an array (deprecated),
|
|
133
|
-
// only the listed method names should be instrumented.
|
|
134
|
-
const instrumentPrototypeMethods = Array.isArray(options.instrumentPrototypeMethods)
|
|
135
|
-
? options.instrumentPrototypeMethods
|
|
136
|
-
: undefined;
|
|
70
|
+
const instrumentPrototypeMethods = Array.isArray(options.instrumentPrototypeMethods) ? options.instrumentPrototypeMethods : void 0;
|
|
137
71
|
const allowSet = instrumentPrototypeMethods ? new Set(instrumentPrototypeMethods) : null;
|
|
138
|
-
|
|
139
|
-
// Return a Proxy that lazily wraps prototype methods on access.
|
|
140
|
-
// This avoids iterating the prototype chain at construction time —
|
|
141
|
-
// we only check if a property is an RPC method when it's accessed.
|
|
142
|
-
const rpcMethodCache = new Map();
|
|
143
|
-
|
|
72
|
+
const rpcMethodCache = /* @__PURE__ */ new Map();
|
|
144
73
|
return new Proxy(obj, {
|
|
145
74
|
get(proxyTarget, prop, receiver) {
|
|
146
75
|
const value = Reflect.get(proxyTarget, prop, receiver);
|
|
147
|
-
|
|
148
|
-
if (typeof prop !== 'string' || BUILT_IN_DO_METHODS.has(prop)) {
|
|
76
|
+
if (typeof prop !== "string" || BUILT_IN_DO_METHODS.has(prop)) {
|
|
149
77
|
return value;
|
|
150
78
|
}
|
|
151
|
-
|
|
152
79
|
const cached = rpcMethodCache.get(prop);
|
|
153
|
-
|
|
154
80
|
if (cached) {
|
|
155
81
|
return cached;
|
|
156
82
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
Object.prototype.hasOwnProperty.call(proxyTarget, prop) ||
|
|
161
|
-
(allowSet && !allowSet.has(prop)) ||
|
|
162
|
-
// Exclude inherited Object.prototype methods (toString, valueOf, etc.)
|
|
163
|
-
// These are not RPC methods and should not create spans
|
|
164
|
-
prop in Object.prototype
|
|
165
|
-
) {
|
|
83
|
+
if (typeof value !== "function" || Object.prototype.hasOwnProperty.call(proxyTarget, prop) || allowSet && !allowSet.has(prop) || // Exclude inherited Object.prototype methods (toString, valueOf, etc.)
|
|
84
|
+
// These are not RPC methods and should not create spans
|
|
85
|
+
prop in Object.prototype) {
|
|
166
86
|
return value;
|
|
167
87
|
}
|
|
168
|
-
|
|
169
|
-
// Bind the method to the original object to ensure private fields work correctly.
|
|
170
|
-
// When called via the Proxy, `this` would be the Proxy, but private fields require
|
|
171
|
-
// the original object. Bound functions ignore the thisArg passed via Reflect.apply.
|
|
172
|
-
const boundValue = (value ).bind(proxyTarget);
|
|
173
|
-
|
|
88
|
+
const boundValue = value.bind(proxyTarget);
|
|
174
89
|
const wrapped = wrapMethodWithSentry(
|
|
175
|
-
{ options, context, spanName: prop, spanOp:
|
|
90
|
+
{ options, context, spanName: prop, spanOp: "rpc" },
|
|
176
91
|
boundValue,
|
|
177
|
-
|
|
178
|
-
true
|
|
92
|
+
void 0,
|
|
93
|
+
true
|
|
179
94
|
);
|
|
180
|
-
|
|
181
95
|
rpcMethodCache.set(prop, wrapped);
|
|
182
|
-
|
|
183
96
|
return wrapped;
|
|
184
|
-
}
|
|
97
|
+
}
|
|
185
98
|
});
|
|
186
|
-
}
|
|
99
|
+
}
|
|
187
100
|
});
|
|
188
101
|
}
|
|
189
102
|
|
|
@@ -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 { ensureInstrumented } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport { getEffectiveRpcPropagation } from './utils/rpcOptions';\nimport { type UncheckedMethod, wrapMethodWithSentry } from './wrapMethodWithSentry';\n\nconst BUILT_IN_DO_METHODS = new Set([\n 'constructor',\n 'fetch',\n 'alarm',\n 'webSocketError',\n 'webSocketClose',\n 'webSocketMessage',\n]);\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods by default:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option.\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 const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n\n const obj = new target(context, instrumentedEnv);\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 // Alarms are independent invocations, so we start a new trace and link to the previous alarm\n obj.alarm = wrapMethodWithSentry(\n { options, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },\n obj.alarm,\n );\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 // Get effective RPC propagation setting (handles deprecation of instrumentPrototypeMethods)\n const rpcPropagation = getEffectiveRpcPropagation(options);\n\n // Skip RPC instrumentation if not enabled\n if (!rpcPropagation) {\n return obj;\n }\n\n // If `instrumentPrototypeMethods` was passed as an array (deprecated),\n // only the listed method names should be instrumented.\n const instrumentPrototypeMethods = Array.isArray(options.instrumentPrototypeMethods)\n ? options.instrumentPrototypeMethods\n : undefined;\n const allowSet = instrumentPrototypeMethods ? new Set(instrumentPrototypeMethods) : null;\n\n // Return a Proxy that lazily wraps prototype methods on access.\n // This avoids iterating the prototype chain at construction time —\n // we only check if a property is an RPC method when it's accessed.\n const rpcMethodCache = new Map<string, UncheckedMethod>();\n\n return new Proxy(obj, {\n get(proxyTarget, prop, receiver) {\n const value = Reflect.get(proxyTarget, prop, receiver);\n\n if (typeof prop !== 'string' || BUILT_IN_DO_METHODS.has(prop)) {\n return value;\n }\n\n const cached = rpcMethodCache.get(prop);\n\n if (cached) {\n return cached;\n }\n\n if (\n typeof value !== 'function' ||\n Object.prototype.hasOwnProperty.call(proxyTarget, prop) ||\n (allowSet && !allowSet.has(prop)) ||\n // Exclude inherited Object.prototype methods (toString, valueOf, etc.)\n // These are not RPC methods and should not create spans\n prop in Object.prototype\n ) {\n return value;\n }\n\n // Bind the method to the original object to ensure private fields work correctly.\n // When called via the Proxy, `this` would be the Proxy, but private fields require\n // the original object. Bound functions ignore the thisArg passed via Reflect.apply.\n const boundValue = (value as UncheckedMethod).bind(proxyTarget);\n\n const wrapped = wrapMethodWithSentry(\n { options, context, spanName: prop, spanOp: 'rpc' },\n boundValue,\n undefined,\n true,\n );\n\n rpcMethodCache.set(prop, wrapped);\n\n return wrapped;\n },\n });\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 } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport { getEffectiveRpcPropagation } from './utils/rpcOptions';\nimport { type UncheckedMethod, wrapMethodWithSentry } from './wrapMethodWithSentry';\n\nconst BUILT_IN_DO_METHODS = new Set([\n 'constructor',\n 'fetch',\n 'alarm',\n 'webSocketError',\n 'webSocketClose',\n 'webSocketMessage',\n]);\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods by default:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option.\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 const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n\n const obj = new target(context, instrumentedEnv);\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 // Alarms are independent invocations, so we start a new trace and link to the previous alarm\n obj.alarm = wrapMethodWithSentry(\n { options, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },\n obj.alarm,\n );\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 // Get effective RPC propagation setting (handles deprecation of instrumentPrototypeMethods)\n const rpcPropagation = getEffectiveRpcPropagation(options);\n\n // Skip RPC instrumentation if not enabled\n if (!rpcPropagation) {\n return obj;\n }\n\n // If `instrumentPrototypeMethods` was passed as an array (deprecated),\n // only the listed method names should be instrumented.\n const instrumentPrototypeMethods = Array.isArray(options.instrumentPrototypeMethods)\n ? options.instrumentPrototypeMethods\n : undefined;\n const allowSet = instrumentPrototypeMethods ? new Set(instrumentPrototypeMethods) : null;\n\n // Return a Proxy that lazily wraps prototype methods on access.\n // This avoids iterating the prototype chain at construction time —\n // we only check if a property is an RPC method when it's accessed.\n const rpcMethodCache = new Map<string, UncheckedMethod>();\n\n return new Proxy(obj, {\n get(proxyTarget, prop, receiver) {\n const value = Reflect.get(proxyTarget, prop, receiver);\n\n if (typeof prop !== 'string' || BUILT_IN_DO_METHODS.has(prop)) {\n return value;\n }\n\n const cached = rpcMethodCache.get(prop);\n\n if (cached) {\n return cached;\n }\n\n if (\n typeof value !== 'function' ||\n Object.prototype.hasOwnProperty.call(proxyTarget, prop) ||\n (allowSet && !allowSet.has(prop)) ||\n // Exclude inherited Object.prototype methods (toString, valueOf, etc.)\n // These are not RPC methods and should not create spans\n prop in Object.prototype\n ) {\n return value;\n }\n\n // Bind the method to the original object to ensure private fields work correctly.\n // When called via the Proxy, `this` would be the Proxy, but private fields require\n // the original object. Bound functions ignore the thisArg passed via Reflect.apply.\n const boundValue = (value as UncheckedMethod).bind(proxyTarget);\n\n const wrapped = wrapMethodWithSentry(\n { options, context, spanName: prop, spanOp: 'rpc' },\n boundValue,\n undefined,\n true,\n );\n\n rpcMethodCache.set(prop, wrapped);\n\n return wrapped;\n },\n });\n },\n });\n}\n"],"names":["target"],"mappings":"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"}
|
package/build/esm/flush.js
CHANGED
|
@@ -1,55 +1,73 @@
|
|
|
1
1
|
import { flush } from '@sentry/core';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.
|
|
10
|
-
*/
|
|
3
|
+
const flushLockRegistries = /* @__PURE__ */ new WeakMap();
|
|
4
|
+
function getOriginalWaitUntil(context) {
|
|
5
|
+
const currentWaitUntil = context.waitUntil;
|
|
6
|
+
const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;
|
|
7
|
+
return original ?? currentWaitUntil;
|
|
8
|
+
}
|
|
11
9
|
function makeFlushLock(context) {
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const registry = getOrCreateFlushLockRegistry(context);
|
|
11
|
+
let resolveAllDone = () => void 0;
|
|
12
|
+
const allDone = new Promise((res) => {
|
|
14
13
|
resolveAllDone = res;
|
|
15
14
|
});
|
|
16
15
|
let pending = 0;
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
const lock = {
|
|
17
|
+
ready: allDone,
|
|
18
|
+
acquire: () => {
|
|
19
|
+
pending++;
|
|
20
|
+
},
|
|
21
|
+
release: () => {
|
|
22
|
+
if (--pending === 0) {
|
|
23
|
+
registry.locks.delete(lock);
|
|
24
|
+
resolveAllDone();
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
finalize: () => {
|
|
28
|
+
if (pending === 0) {
|
|
29
|
+
registry.locks.delete(lock);
|
|
30
|
+
resolveAllDone();
|
|
31
|
+
}
|
|
32
|
+
return allDone;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
registry.locks.add(lock);
|
|
36
|
+
return Object.freeze(lock);
|
|
37
|
+
}
|
|
38
|
+
function getOrCreateFlushLockRegistry(context) {
|
|
39
|
+
const waitUntil = context.waitUntil;
|
|
40
|
+
const existingRegistry = flushLockRegistries.get(waitUntil);
|
|
41
|
+
if (existingRegistry) {
|
|
42
|
+
return existingRegistry;
|
|
43
|
+
}
|
|
44
|
+
const originalWaitUntil = context.waitUntil.bind(context);
|
|
45
|
+
const registry = { locks: /* @__PURE__ */ new Set(), originalWaitUntil };
|
|
46
|
+
const instrumentedWaitUntil = (promise) => {
|
|
47
|
+
const locks = [...registry.locks];
|
|
48
|
+
for (const lock of locks) {
|
|
49
|
+
lock.acquire();
|
|
50
|
+
}
|
|
20
51
|
return originalWaitUntil(
|
|
21
52
|
promise.finally(() => {
|
|
22
|
-
|
|
23
|
-
|
|
53
|
+
for (const lock of locks) {
|
|
54
|
+
lock.release();
|
|
55
|
+
}
|
|
56
|
+
})
|
|
24
57
|
);
|
|
25
58
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (pending === 0) resolveAllDone();
|
|
30
|
-
return allDone;
|
|
31
|
-
},
|
|
32
|
-
});
|
|
59
|
+
flushLockRegistries.set(instrumentedWaitUntil, registry);
|
|
60
|
+
context.waitUntil = instrumentedWaitUntil;
|
|
61
|
+
return registry;
|
|
33
62
|
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Flushes the client and then disposes of it to allow garbage collection.
|
|
37
|
-
* This should be called at the end of each request to prevent memory leaks.
|
|
38
|
-
*
|
|
39
|
-
* @param client - The CloudflareClient instance to flush and dispose
|
|
40
|
-
* @param timeout - Timeout in milliseconds for the flush operation
|
|
41
|
-
* @returns A promise that resolves when flush and dispose are complete
|
|
42
|
-
*/
|
|
43
|
-
async function flushAndDispose(client, timeout = 2000) {
|
|
63
|
+
async function flushAndDispose(client, timeout = 2e3) {
|
|
44
64
|
if (!client) {
|
|
45
65
|
await flush(timeout);
|
|
46
|
-
|
|
47
66
|
return;
|
|
48
67
|
}
|
|
49
|
-
|
|
50
68
|
await client.flush(timeout);
|
|
51
69
|
client.dispose();
|
|
52
70
|
}
|
|
53
71
|
|
|
54
|
-
export { flushAndDispose, makeFlushLock };
|
|
72
|
+
export { flushAndDispose, getOriginalWaitUntil, makeFlushLock };
|
|
55
73
|
//# sourceMappingURL=flush.js.map
|
package/build/esm/flush.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { flush } from '@sentry/core';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n const
|
|
1
|
+
{"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { flush } from '@sentry/core';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n readonly originalWaitUntil: ExecutionContext['waitUntil'];\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Returns the original (un-instrumented) waitUntil function for a context.\n * This should be used when calling waitUntil with flushAndDispose to avoid deadlock.\n *\n * The flush lock mechanism wraps context.waitUntil to track pending tasks.\n * If we call waitUntil(flushAndDispose(client)) through the instrumented version,\n * it creates a deadlock because:\n * 1. The instrumented waitUntil acquires the flush lock\n * 2. flushAndDispose calls client.flush() which waits for the lock to be released\n * 3. The lock won't be released until the waitUntil promise completes\n * 4. The waitUntil promise won't complete until flush() returns\n *\n * By using the original waitUntil for flush operations, we bypass this issue.\n */\nexport function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const currentWaitUntil = context.waitUntil;\n const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;\n return original ?? currentWaitUntil;\n}\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const originalWaitUntil = context.waitUntil.bind(context) as typeof context.waitUntil;\n const registry: FlushLockRegistry = { locks: new Set(), originalWaitUntil };\n const instrumentedWaitUntil: typeof context.waitUntil = promise => {\n // Snapshot active locks so locks created after this call do not wait for earlier waitUntil work.\n const locks = [...registry.locks];\n\n for (const lock of locks) {\n lock.acquire();\n }\n\n return originalWaitUntil(\n promise.finally(() => {\n for (const lock of locks) {\n lock.release();\n }\n }),\n );\n };\n\n flushLockRegistries.set(instrumentedWaitUntil, registry);\n context.waitUntil = instrumentedWaitUntil;\n\n return registry;\n}\n\n/**\n * Flushes the client and then disposes of it to allow garbage collection.\n * This should be called at the end of each request to prevent memory leaks.\n *\n * @param client - The CloudflareClient instance to flush and dispose\n * @param timeout - Timeout in milliseconds for the flush operation\n * @returns A promise that resolves when flush and dispose are complete\n */\nexport async function flushAndDispose(client: Client | undefined, timeout = 2000): Promise<void> {\n if (!client) {\n await flush(timeout);\n\n return;\n }\n\n await client.flush(timeout);\n client.dispose();\n}\n"],"names":[],"mappings":";;AAmBA,MAAM,mBAAA,uBAA0B,OAAA,EAA0D;AAgBnF,SAAS,qBAAqB,OAAA,EAAsE;AAEzG,EAAA,MAAM,mBAAmB,OAAA,CAAQ,SAAA;AACjC,EAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,GAAA,CAAI,gBAAgB,CAAA,EAAG,iBAAA;AAC5D,EAAA,OAAO,QAAA,IAAY,gBAAA;AACrB;AAUO,SAAS,cAAc,OAAA,EAAsC;AAClE,EAAA,MAAM,QAAA,GAAW,6BAA6B,OAAO,CAAA;AACrD,EAAA,IAAI,iBAA6B,MAAM,MAAA;AACvC,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAc,CAAA,GAAA,KAAO;AACvC,IAAA,cAAA,GAAiB,GAAA;AAAA,EACnB,CAAC,CAAA;AACD,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,MAAM,IAAA,GAA0B;AAAA,IAC9B,KAAA,EAAO,OAAA;AAAA,IACP,SAAS,MAAM;AACb,MAAA,OAAA,EAAA;AAAA,IACF,CAAA;AAAA,IACA,SAAS,MAAM;AACb,MAAA,IAAI,EAAE,YAAY,CAAA,EAAG;AACnB,QAAA,QAAA,CAAS,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B,QAAA,cAAA,EAAe;AAAA,MACjB;AAAA,IACF,CAAA;AAAA,IACA,UAAU,MAAM;AACd,MAAA,IAAI,YAAY,CAAA,EAAG;AACjB,QAAA,QAAA,CAAS,KAAA,CAAM,OAAO,IAAI,CAAA;AAC1B,QAAA,cAAA,EAAe;AAAA,MACjB;AACA,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,QAAA,CAAS,KAAA,CAAM,IAAI,IAAI,CAAA;AACvB,EAAA,OAAO,MAAA,CAAO,OAAO,IAAI,CAAA;AAC3B;AAEA,SAAS,6BAA6B,OAAA,EAA8C;AAElF,EAAA,MAAM,YAAY,OAAA,CAAQ,SAAA;AAC1B,EAAA,MAAM,gBAAA,GAAmB,mBAAA,CAAoB,GAAA,CAAI,SAAS,CAAA;AAE1D,EAAA,IAAI,gBAAA,EAAkB;AACpB,IAAA,OAAO,gBAAA;AAAA,EACT;AAEA,EAAA,MAAM,iBAAA,GAAoB,OAAA,CAAQ,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AACxD,EAAA,MAAM,WAA8B,EAAE,KAAA,kBAAO,IAAI,GAAA,IAAO,iBAAA,EAAkB;AAC1E,EAAA,MAAM,wBAAkD,CAAA,OAAA,KAAW;AAEjE,IAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,QAAA,CAAS,KAAK,CAAA;AAEhC,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,IACf;AAEA,IAAA,OAAO,iBAAA;AAAA,MACL,OAAA,CAAQ,QAAQ,MAAM;AACpB,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,UAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,QACf;AAAA,MACF,CAAC;AAAA,KACH;AAAA,EACF,CAAA;AAEA,EAAA,mBAAA,CAAoB,GAAA,CAAI,uBAAuB,QAAQ,CAAA;AACvD,EAAA,OAAA,CAAQ,SAAA,GAAY,qBAAA;AAEpB,EAAA,OAAO,QAAA;AACT;AAUA,eAAsB,eAAA,CAAgB,MAAA,EAA4B,OAAA,GAAU,GAAA,EAAqB;AAC/F,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,MAAM,OAAO,CAAA;AAEnB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAC1B,EAAA,MAAA,CAAO,OAAA,EAAQ;AACjB;;;;"}
|
package/build/esm/instrument.js
CHANGED
|
@@ -1,85 +1,44 @@
|
|
|
1
|
-
|
|
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
|
|
1
|
+
const GLOBAL_KEY = "__SENTRY_INSTRUMENTED_MAP__";
|
|
9
2
|
function getInstrumentedMap() {
|
|
10
|
-
|
|
11
|
-
const globalObj = globalThis ;
|
|
3
|
+
const globalObj = globalThis;
|
|
12
4
|
if (!globalObj[GLOBAL_KEY]) {
|
|
13
|
-
globalObj[GLOBAL_KEY] = new WeakMap();
|
|
5
|
+
globalObj[GLOBAL_KEY] = /* @__PURE__ */ new WeakMap();
|
|
14
6
|
}
|
|
15
7
|
return globalObj[GLOBAL_KEY];
|
|
16
8
|
}
|
|
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
9
|
function isWeakMapKey(value) {
|
|
23
|
-
return
|
|
10
|
+
return typeof value === "object" && value !== null || typeof value === "function";
|
|
24
11
|
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
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)
|
|
30
|
-
*/
|
|
31
12
|
function markAsInstrumented(original, instrumented) {
|
|
32
13
|
try {
|
|
33
14
|
if (isWeakMapKey(original)) {
|
|
34
|
-
// Store mapping from original to instrumented version
|
|
35
|
-
// If instrumented is not provided, store original (for backwards compat)
|
|
36
15
|
getInstrumentedMap().set(original, instrumented ?? original);
|
|
37
16
|
}
|
|
38
|
-
// Also mark the instrumented version itself so we recognize it
|
|
39
17
|
if (isWeakMapKey(instrumented) && instrumented !== original) {
|
|
40
18
|
getInstrumentedMap().set(instrumented, instrumented);
|
|
41
19
|
}
|
|
42
20
|
} catch {
|
|
43
|
-
// ignore errors here
|
|
44
21
|
}
|
|
45
22
|
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
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.
|
|
51
|
-
*/
|
|
52
23
|
function getInstrumented(obj) {
|
|
53
24
|
try {
|
|
54
25
|
if (isWeakMapKey(obj)) {
|
|
55
|
-
return getInstrumentedMap().get(obj)
|
|
26
|
+
return getInstrumentedMap().get(obj);
|
|
56
27
|
}
|
|
57
|
-
|
|
58
|
-
return undefined;
|
|
28
|
+
return void 0;
|
|
59
29
|
} catch {
|
|
60
|
-
return
|
|
30
|
+
return void 0;
|
|
61
31
|
}
|
|
62
32
|
}
|
|
63
|
-
|
|
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
33
|
function ensureInstrumented(original, instrumentFn, noMark) {
|
|
71
34
|
const existing = getInstrumented(original);
|
|
72
|
-
|
|
73
35
|
if (existing) {
|
|
74
36
|
return existing;
|
|
75
37
|
}
|
|
76
|
-
|
|
77
38
|
const instrumented = instrumentFn(original);
|
|
78
|
-
|
|
79
39
|
if (!noMark) {
|
|
80
40
|
markAsInstrumented(original, instrumented);
|
|
81
41
|
}
|
|
82
|
-
|
|
83
42
|
return instrumented;
|
|
84
43
|
}
|
|
85
44
|
|
|
@@ -1 +1 @@
|
|
|
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":"
|
|
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":"AAKA,MAAM,UAAA,GAAa,6BAAA;AAGnB,SAAS,kBAAA,GAAwC;AAE/C,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,IAAI,CAAC,SAAA,CAAU,UAAU,CAAA,EAAG;AAC1B,IAAA,SAAA,CAAU,UAAU,CAAA,mBAAI,IAAI,OAAA,EAAQ;AAAA,EACtC;AACA,EAAA,OAAO,UAAU,UAAU,CAAA;AAC7B;AAMA,SAAS,aAAa,KAAA,EAAiC;AACrD,EAAA,OAAQ,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAS,OAAO,KAAA,KAAU,UAAA;AAC3E;AAOO,SAAS,kBAAA,CAAsB,UAAa,YAAA,EAAwB;AACzE,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,EAAG;AAG1B,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,QAAA,EAAU,YAAA,IAAgB,QAAQ,CAAA;AAAA,IAC7D;AAEA,IAAA,IAAI,YAAA,CAAa,YAAY,CAAA,IAAK,YAAA,KAAiB,QAAA,EAAU;AAC3D,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,YAAA,EAAc,YAAY,CAAA;AAAA,IACrD;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAOO,SAAS,gBAAmB,GAAA,EAAuB;AACxD,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,GAAG,CAAA,EAAG;AACrB,MAAA,OAAO,kBAAA,EAAmB,CAAE,GAAA,CAAI,GAAG,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAQO,SAAS,kBAAA,CAAsB,QAAA,EAAa,YAAA,EAAkC,MAAA,EAAqB;AACxG,EAAA,MAAM,QAAA,GAAW,gBAAgB,QAAQ,CAAA;AAEzC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,aAAa,QAAQ,CAAA;AAE1C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,kBAAA,CAAmB,UAAU,YAAY,CAAA;AAAA,EAC3C;AAEA,EAAA,OAAO,YAAA;AACT;;;;"}
|
|
@@ -1,61 +1,36 @@
|
|
|
1
1
|
import { appendRpcMeta } from '../utils/rpcMeta.js';
|
|
2
2
|
import { instrumentFetcher } from './worker/instrumentFetcher.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
const STUB_NON_RPC_METHODS = new Set(['fetch', 'connect', 'dup']);
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Instruments a DurableObjectNamespace binding to create spans for DO interactions.
|
|
9
|
-
*
|
|
10
|
-
* Wraps:
|
|
11
|
-
* - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub
|
|
12
|
-
* - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs
|
|
13
|
-
*
|
|
14
|
-
* @param namespace - The DurableObjectNamespace to instrument
|
|
15
|
-
*/
|
|
4
|
+
const STUB_NON_RPC_METHODS = /* @__PURE__ */ new Set(["fetch", "connect", "dup"]);
|
|
16
5
|
function instrumentDurableObjectNamespace(namespace) {
|
|
17
6
|
return new Proxy(namespace, {
|
|
18
7
|
get(target, prop, _receiver) {
|
|
19
|
-
const value = Reflect.get(target, prop)
|
|
20
|
-
|
|
21
|
-
if (typeof value !== 'function') {
|
|
8
|
+
const value = Reflect.get(target, prop);
|
|
9
|
+
if (typeof value !== "function") {
|
|
22
10
|
return value;
|
|
23
11
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return function ( ...args) {
|
|
12
|
+
if (prop === "get" || prop === "getByName") {
|
|
13
|
+
return function(...args) {
|
|
27
14
|
const stub = Reflect.apply(value, target, args);
|
|
28
|
-
|
|
29
15
|
return instrumentDurableObjectStub(stub);
|
|
30
16
|
};
|
|
31
17
|
}
|
|
32
|
-
|
|
33
18
|
return value.bind(target);
|
|
34
|
-
}
|
|
19
|
+
}
|
|
35
20
|
});
|
|
36
21
|
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Instruments a DurableObjectStub to create spans for outgoing fetch calls
|
|
40
|
-
* and propagate trace context across RPC calls.
|
|
41
|
-
*
|
|
42
|
-
* @param stub - The DurableObjectStub to instrument
|
|
43
|
-
*/
|
|
44
22
|
function instrumentDurableObjectStub(stub) {
|
|
45
23
|
return new Proxy(stub, {
|
|
46
24
|
get(target, prop) {
|
|
47
25
|
const value = Reflect.get(target, prop);
|
|
48
|
-
|
|
49
|
-
if (prop === 'fetch' && typeof value === 'function') {
|
|
26
|
+
if (prop === "fetch" && typeof value === "function") {
|
|
50
27
|
return instrumentFetcher((...args) => Reflect.apply(value, target, args));
|
|
51
28
|
}
|
|
52
|
-
|
|
53
|
-
if (typeof value === 'function' && typeof prop === 'string' && !STUB_NON_RPC_METHODS.has(prop)) {
|
|
29
|
+
if (typeof value === "function" && typeof prop === "string" && !STUB_NON_RPC_METHODS.has(prop)) {
|
|
54
30
|
return (...args) => Reflect.apply(value, target, appendRpcMeta(args));
|
|
55
31
|
}
|
|
56
|
-
|
|
57
32
|
return value;
|
|
58
|
-
}
|
|
33
|
+
}
|
|
59
34
|
});
|
|
60
35
|
}
|
|
61
36
|
|