@sentry/cloudflare 10.48.0 → 10.49.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/client.js.map +1 -1
- package/build/cjs/durableobject.js +13 -5
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/index.js +1 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js +56 -0
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js.map +1 -0
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js +38 -3
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEmail.js +3 -2
- package/build/cjs/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEnv.js +83 -0
- package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -0
- package/build/cjs/instrumentations/worker/instrumentFetch.js +3 -2
- package/build/cjs/instrumentations/worker/instrumentFetch.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentFetcher.js +38 -0
- package/build/cjs/instrumentations/worker/instrumentFetcher.js.map +1 -0
- package/build/cjs/instrumentations/worker/instrumentQueue.js +3 -2
- package/build/cjs/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentScheduled.js +3 -2
- package/build/cjs/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentTail.js +3 -2
- package/build/cjs/instrumentations/worker/instrumentTail.js.map +1 -1
- package/build/cjs/integrations/tracing/vercelai.js +2 -1
- package/build/cjs/integrations/tracing/vercelai.js.map +1 -1
- package/build/cjs/sdk.js +6 -1
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/utils/instrumentContext.js +2 -1
- package/build/cjs/utils/instrumentContext.js.map +1 -1
- package/build/cjs/utils/isBinding.js +32 -0
- package/build/cjs/utils/isBinding.js.map +1 -0
- package/build/cjs/utils/rpcOptions.js +84 -0
- package/build/cjs/utils/rpcOptions.js.map +1 -0
- package/build/cjs/utils/traceLinks.js +78 -0
- package/build/cjs/utils/traceLinks.js.map +1 -0
- package/build/cjs/workflows.js +3 -2
- package/build/cjs/workflows.js.map +1 -1
- package/build/cjs/wrapMethodWithSentry.js +90 -45
- package/build/cjs/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/durableobject.js +13 -5
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/index.js +1 -1
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js +54 -0
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js.map +1 -0
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js +39 -4
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEmail.js +3 -2
- package/build/esm/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEnv.js +81 -0
- package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -0
- package/build/esm/instrumentations/worker/instrumentFetch.js +3 -2
- package/build/esm/instrumentations/worker/instrumentFetch.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentFetcher.js +36 -0
- package/build/esm/instrumentations/worker/instrumentFetcher.js.map +1 -0
- package/build/esm/instrumentations/worker/instrumentQueue.js +3 -2
- package/build/esm/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentScheduled.js +3 -2
- package/build/esm/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentTail.js +3 -2
- package/build/esm/instrumentations/worker/instrumentTail.js.map +1 -1
- package/build/esm/integrations/tracing/vercelai.js +2 -1
- package/build/esm/integrations/tracing/vercelai.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/sdk.js +7 -2
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/utils/instrumentContext.js +2 -1
- package/build/esm/utils/instrumentContext.js.map +1 -1
- package/build/esm/utils/isBinding.js +29 -0
- package/build/esm/utils/isBinding.js.map +1 -0
- package/build/esm/utils/rpcOptions.js +81 -0
- package/build/esm/utils/rpcOptions.js.map +1 -0
- package/build/esm/utils/traceLinks.js +73 -0
- package/build/esm/utils/traceLinks.js.map +1 -0
- package/build/esm/workflows.js +3 -2
- package/build/esm/workflows.js.map +1 -1
- package/build/esm/wrapMethodWithSentry.js +91 -46
- package/build/esm/wrapMethodWithSentry.js.map +1 -1
- package/build/types/client.d.ts +39 -10
- package/build/types/client.d.ts.map +1 -1
- package/build/types/durableobject.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentDurableObjectNamespace.d.ts +12 -0
- package/build/types/instrumentations/instrumentDurableObjectNamespace.d.ts.map +1 -0
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts +8 -1
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEmail.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEnv.d.ts +16 -0
- package/build/types/instrumentations/worker/instrumentEnv.d.ts.map +1 -0
- package/build/types/instrumentations/worker/instrumentFetch.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentFetcher.d.ts +10 -0
- package/build/types/instrumentations/worker/instrumentFetcher.d.ts.map +1 -0
- package/build/types/instrumentations/worker/instrumentQueue.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentScheduled.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentTail.d.ts.map +1 -1
- package/build/types/integrations/tracing/vercelai.d.ts +9 -1
- package/build/types/integrations/tracing/vercelai.d.ts.map +1 -1
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types/utils/instrumentContext.d.ts.map +1 -1
- package/build/types/utils/isBinding.d.ts +49 -0
- package/build/types/utils/isBinding.d.ts.map +1 -0
- package/build/types/utils/rpcOptions.d.ts +24 -0
- package/build/types/utils/rpcOptions.d.ts.map +1 -0
- package/build/types/utils/traceLinks.d.ts +27 -0
- package/build/types/utils/traceLinks.d.ts.map +1 -0
- package/build/types/workflows.d.ts.map +1 -1
- package/build/types/wrapMethodWithSentry.d.ts +19 -2
- package/build/types/wrapMethodWithSentry.d.ts.map +1 -1
- package/build/types-ts3.8/client.d.ts +39 -10
- package/build/types-ts3.8/index.d.ts +1 -1
- package/build/types-ts3.8/instrumentations/instrumentDurableObjectNamespace.d.ts +12 -0
- package/build/types-ts3.8/instrumentations/instrumentDurableObjectStorage.d.ts +8 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentEnv.d.ts +16 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentFetcher.d.ts +10 -0
- package/build/types-ts3.8/integrations/tracing/vercelai.d.ts +9 -1
- package/build/types-ts3.8/utils/isBinding.d.ts +49 -0
- package/build/types-ts3.8/utils/rpcOptions.d.ts +24 -0
- package/build/types-ts3.8/utils/traceLinks.d.ts +27 -0
- package/build/types-ts3.8/wrapMethodWithSentry.d.ts +19 -2
- package/package.json +2 -2
|
@@ -4,11 +4,13 @@ const core = require('@sentry/core');
|
|
|
4
4
|
const flush = require('./flush.js');
|
|
5
5
|
const instrument = require('./instrument.js');
|
|
6
6
|
const sdk = require('./sdk.js');
|
|
7
|
+
const traceLinks = require('./utils/traceLinks.js');
|
|
7
8
|
|
|
8
9
|
/** Extended DurableObjectState with originalStorage exposed by instrumentContext */
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
|
-
* Wraps a method with Sentry tracing.
|
|
12
|
+
* Wraps a method with Sentry error tracking and optional tracing.
|
|
13
|
+
* Supports starting new traces and linking to previous invocations via Durable Object storage.
|
|
12
14
|
*
|
|
13
15
|
* @param wrapperOptions - The options for the wrapper.
|
|
14
16
|
* @param handler - The method to wrap.
|
|
@@ -27,44 +29,58 @@ function wrapMethodWithSentry(
|
|
|
27
29
|
original =>
|
|
28
30
|
new Proxy(original, {
|
|
29
31
|
apply(target, thisArg, args) {
|
|
32
|
+
const { startNewTrace } = wrapperOptions;
|
|
33
|
+
|
|
34
|
+
// For startNewTrace, always use withIsolationScope to ensure a fresh scope
|
|
35
|
+
// Otherwise, use existing client's scope or isolation scope
|
|
30
36
|
const currentClient = core.getClient();
|
|
31
|
-
|
|
32
|
-
const sentryWithScope = currentClient ? core.withScope : core.withIsolationScope;
|
|
37
|
+
const sentryWithScope = startNewTrace ? core.withIsolationScope : currentClient ? core.withScope : core.withIsolationScope;
|
|
33
38
|
|
|
34
39
|
const wrappedFunction = (scope) => {
|
|
35
40
|
// In certain situations, the passed context can become undefined.
|
|
36
41
|
// For example, for Astro while prerendering pages at build time.
|
|
37
42
|
// see: https://github.com/getsentry/sentry-javascript/issues/13217
|
|
38
|
-
const context = wrapperOptions.context
|
|
43
|
+
const context = wrapperOptions.context;
|
|
39
44
|
|
|
40
45
|
const waitUntil = context?.waitUntil?.bind?.(context);
|
|
46
|
+
const storage = context && 'originalStorage' in context ? context.originalStorage : undefined;
|
|
41
47
|
|
|
42
|
-
let
|
|
48
|
+
let scopeClient = scope.getClient();
|
|
43
49
|
// Check if client exists AND is still usable (transport not disposed)
|
|
44
50
|
// This handles the case where a previous handler disposed the client
|
|
45
51
|
// but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)
|
|
46
|
-
|
|
52
|
+
// For startNewTrace, always create a fresh client
|
|
53
|
+
if (startNewTrace || !scopeClient?.getTransport()) {
|
|
47
54
|
const client = sdk.init({
|
|
48
55
|
...wrapperOptions.options,
|
|
49
56
|
ctx: context ,
|
|
50
57
|
});
|
|
51
58
|
scope.setClient(client);
|
|
52
|
-
|
|
59
|
+
scopeClient = client;
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
const clientToDispose =
|
|
62
|
+
const clientToDispose = scopeClient;
|
|
63
|
+
const methodName = wrapperOptions.spanName || 'unknown';
|
|
64
|
+
|
|
65
|
+
const teardown = async () => {
|
|
66
|
+
if (startNewTrace && storage) {
|
|
67
|
+
await traceLinks.storeSpanContext(storage, methodName);
|
|
68
|
+
}
|
|
69
|
+
await flush.flushAndDispose(clientToDispose);
|
|
70
|
+
};
|
|
56
71
|
|
|
57
72
|
if (!wrapperOptions.spanName) {
|
|
58
73
|
try {
|
|
59
74
|
if (callback) {
|
|
60
75
|
callback(...args);
|
|
61
76
|
}
|
|
77
|
+
|
|
62
78
|
const result = Reflect.apply(target, thisArg, args);
|
|
63
79
|
|
|
64
80
|
if (core.isThenable(result)) {
|
|
65
81
|
return result.then(
|
|
66
82
|
(res) => {
|
|
67
|
-
waitUntil?.(
|
|
83
|
+
waitUntil?.(teardown());
|
|
68
84
|
return res;
|
|
69
85
|
},
|
|
70
86
|
(e) => {
|
|
@@ -74,12 +90,12 @@ function wrapMethodWithSentry(
|
|
|
74
90
|
handled: false,
|
|
75
91
|
},
|
|
76
92
|
});
|
|
77
|
-
waitUntil?.(
|
|
93
|
+
waitUntil?.(teardown());
|
|
78
94
|
throw e;
|
|
79
95
|
},
|
|
80
96
|
);
|
|
81
97
|
} else {
|
|
82
|
-
waitUntil?.(
|
|
98
|
+
waitUntil?.(teardown());
|
|
83
99
|
return result;
|
|
84
100
|
}
|
|
85
101
|
} catch (e) {
|
|
@@ -89,7 +105,7 @@ function wrapMethodWithSentry(
|
|
|
89
105
|
handled: false,
|
|
90
106
|
},
|
|
91
107
|
});
|
|
92
|
-
waitUntil?.(
|
|
108
|
+
waitUntil?.(teardown());
|
|
93
109
|
throw e;
|
|
94
110
|
}
|
|
95
111
|
}
|
|
@@ -101,42 +117,71 @@ function wrapMethodWithSentry(
|
|
|
101
117
|
}
|
|
102
118
|
: {};
|
|
103
119
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
const executeSpan = () => {
|
|
121
|
+
return core.startSpan({ name: methodName, attributes }, span => {
|
|
122
|
+
// When linking to previous trace, fetch the stored context and add links asynchronously
|
|
123
|
+
// This avoids blocking the response while fetching from storage
|
|
124
|
+
if (startNewTrace && storage) {
|
|
125
|
+
waitUntil?.(
|
|
126
|
+
traceLinks.getStoredSpanContext(storage, methodName).then(storedContext => {
|
|
127
|
+
if (storedContext) {
|
|
128
|
+
span.addLinks(traceLinks.buildSpanLinks(storedContext));
|
|
129
|
+
// TODO: Remove this once EAP can store span links. We currently only set this attribute so that we
|
|
130
|
+
// can obtain the previous trace information from the EAP store. Long-term, EAP will handle
|
|
131
|
+
// span links and then we should remove this again. Also throwing in a TODO(v11), to remind us
|
|
132
|
+
// to check this at v11 time :)
|
|
133
|
+
const sampledFlag = storedContext.sampled ? '1' : '0';
|
|
134
|
+
span.setAttribute(
|
|
135
|
+
'sentry.previous_trace',
|
|
136
|
+
`${storedContext.traceId}-${storedContext.spanId}-${sampledFlag}`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
107
142
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
try {
|
|
144
|
+
const result = Reflect.apply(target, thisArg, args);
|
|
145
|
+
|
|
146
|
+
if (core.isThenable(result)) {
|
|
147
|
+
return result.then(
|
|
148
|
+
(res) => {
|
|
149
|
+
waitUntil?.(teardown());
|
|
150
|
+
return res;
|
|
151
|
+
},
|
|
152
|
+
(e) => {
|
|
153
|
+
core.captureException(e, {
|
|
154
|
+
mechanism: {
|
|
155
|
+
type: 'auto.faas.cloudflare.durable_object',
|
|
156
|
+
handled: false,
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
waitUntil?.(teardown());
|
|
160
|
+
throw e;
|
|
161
|
+
},
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
waitUntil?.(teardown());
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
} catch (e) {
|
|
168
|
+
core.captureException(e, {
|
|
169
|
+
mechanism: {
|
|
170
|
+
type: 'auto.faas.cloudflare.durable_object',
|
|
171
|
+
handled: false,
|
|
123
172
|
},
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return result;
|
|
173
|
+
});
|
|
174
|
+
waitUntil?.(teardown());
|
|
175
|
+
throw e;
|
|
128
176
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
throw e;
|
|
138
|
-
}
|
|
139
|
-
});
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
if (startNewTrace) {
|
|
181
|
+
return core.startNewTrace(() => executeSpan());
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return executeSpan();
|
|
140
185
|
};
|
|
141
186
|
|
|
142
187
|
return sentryWithScope(wrappedFunction);
|
|
@@ -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 { 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":"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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 startNewTrace as startNewTraceCore,\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';\nimport { buildSpanLinks, getStoredSpanContext, storeSpanContext } from './utils/traceLinks';\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 | InstrumentedDurableObjectState;\n /**\n * If true, starts a fresh trace instead of inheriting from a parent trace.\n * Useful for scheduled/independent invocations like alarms.\n *\n * If true, it also stores the current span context and links to the previous invocation's span.\n * Uses Durable Object storage to persist the link. The link is set asynchronously via `span.addLinks()`\n * in a `waitUntil` to avoid blocking.\n *\n * @default false\n */\n startNewTrace?: boolean;\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 error tracking and optional tracing.\n * Supports starting new traces and linking to previous invocations via Durable Object storage.\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 { startNewTrace } = wrapperOptions;\n\n // For startNewTrace, always use withIsolationScope to ensure a fresh scope\n // Otherwise, use existing client's scope or isolation scope\n const currentClient = getClient();\n const sentryWithScope = startNewTrace ? withIsolationScope : currentClient ? withScope : withIsolationScope;\n\n const wrappedFunction = (scope: Scope): unknown | Promise<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: typeof wrapperOptions.context | undefined = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n const storage = context && 'originalStorage' in context ? context.originalStorage : undefined;\n\n let scopeClient = 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 // For startNewTrace, always create a fresh client\n if (startNewTrace || !scopeClient?.getTransport()) {\n const client = init({\n ...wrapperOptions.options,\n ctx: context as unknown as ExecutionContext | undefined,\n });\n scope.setClient(client);\n scopeClient = client;\n }\n\n const clientToDispose = scopeClient;\n const methodName = wrapperOptions.spanName || 'unknown';\n\n const teardown = async (): Promise<void> => {\n if (startNewTrace && storage) {\n await storeSpanContext(storage, methodName);\n }\n await flushAndDispose(clientToDispose);\n };\n\n if (!wrapperOptions.spanName) {\n try {\n if (callback) {\n callback(...args);\n }\n\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(\n (res: unknown) => {\n waitUntil?.(teardown());\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?.(teardown());\n throw e;\n },\n );\n } else {\n waitUntil?.(teardown());\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?.(teardown());\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 const executeSpan = (): unknown => {\n return startSpan({ name: methodName, attributes }, span => {\n // When linking to previous trace, fetch the stored context and add links asynchronously\n // This avoids blocking the response while fetching from storage\n if (startNewTrace && storage) {\n waitUntil?.(\n getStoredSpanContext(storage, methodName).then(storedContext => {\n if (storedContext) {\n span.addLinks(buildSpanLinks(storedContext));\n // TODO: Remove this once EAP can store span links. We currently only set this attribute so that we\n // can obtain the previous trace information from the EAP store. Long-term, EAP will handle\n // span links and then we should remove this again. Also throwing in a TODO(v11), to remind us\n // to check this at v11 time :)\n const sampledFlag = storedContext.sampled ? '1' : '0';\n span.setAttribute(\n 'sentry.previous_trace',\n `${storedContext.traceId}-${storedContext.spanId}-${sampledFlag}`,\n );\n }\n }),\n );\n }\n\n try {\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(\n (res: unknown) => {\n waitUntil?.(teardown());\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?.(teardown());\n throw e;\n },\n );\n } else {\n waitUntil?.(teardown());\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?.(teardown());\n throw e;\n }\n });\n };\n\n if (startNewTrace) {\n return startNewTraceCore(() => executeSpan());\n }\n\n return executeSpan();\n };\n\n return sentryWithScope(wrappedFunction);\n },\n }),\n noMark,\n );\n}\n"],"names":["ensureInstrumented","getClient","withIsolationScope","withScope","init","storeSpanContext","flushAndDispose","isThenable","captureException","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan","getStoredSpanContext","buildSpanLinks","startNewTraceCore"],"mappings":"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"}
|
package/build/esm/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';\nimport { applySdkMetadata, debug, ServerRuntimeClient } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\n\n/**\n * The Sentry Cloudflare SDK Client.\n *\n * @see CloudflareClientOptions for documentation on configuration options.\n * @see ServerRuntimeClient for usage documentation.\n */\nexport class CloudflareClient extends ServerRuntimeClient {\n private readonly _flushLock: ReturnType<typeof makeFlushLock> | void;\n private _pendingSpans: Set<string> = new Set();\n private _spanCompletionPromise: Promise<void> | null = null;\n private _resolveSpanCompletion: (() => void) | null = null;\n\n private _unsubscribeSpanStart: (() => void) | null = null;\n private _unsubscribeSpanEnd: (() => void) | null = null;\n\n /**\n * Creates a new Cloudflare SDK instance.\n * @param options Configuration options for this SDK.\n */\n public constructor(options: CloudflareClientOptions) {\n applySdkMetadata(options, 'cloudflare');\n options._metadata = options._metadata || {};\n const { flushLock, ...serverOptions } = options;\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...serverOptions,\n platform: 'javascript',\n // TODO: Grab version information\n runtime: { name: 'cloudflare' },\n // TODO: Add server name\n };\n\n super(clientOptions);\n this._flushLock = flushLock;\n\n // Track span lifecycle to know when to flush\n this._unsubscribeSpanStart = this.on('spanStart', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span started:', spanId);\n this._pendingSpans.add(spanId);\n\n if (!this._spanCompletionPromise) {\n this._spanCompletionPromise = new Promise(resolve => {\n this._resolveSpanCompletion = resolve;\n });\n }\n });\n\n this._unsubscribeSpanEnd = this.on('spanEnd', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span ended:', spanId);\n this._pendingSpans.delete(spanId);\n\n // If no more pending spans, resolve the completion promise\n if (this._pendingSpans.size === 0 && this._resolveSpanCompletion) {\n DEBUG_BUILD && debug.log('[CloudflareClient] All spans completed, resolving promise');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\n }\n });\n }\n\n /**\n * Flushes pending operations and ensures all data is processed.\n * If a timeout is provided, the operation will be completed within the specified time limit.\n *\n * It will wait for all pending spans to complete before flushing.\n *\n * @param {number} [timeout] - Optional timeout in milliseconds to force the completion of the flush operation.\n * @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.\n */\n public async flush(timeout?: number): Promise<boolean> {\n if (this._flushLock) {\n await this._flushLock.finalize();\n }\n\n if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Waiting for', this._pendingSpans.size, 'pending spans to complete...');\n\n const timeoutMs = timeout ?? 5000;\n const spanCompletionRace = Promise.race([\n this._spanCompletionPromise,\n new Promise(resolve =>\n setTimeout(() => {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Span completion timeout after', timeoutMs, 'ms, flushing anyway');\n resolve(undefined);\n }, timeoutMs),\n ),\n ]);\n\n await spanCompletionRace;\n }\n\n return super.flush(timeout);\n }\n\n /**\n * Disposes of the client and releases all resources.\n *\n * This method clears all Cloudflare-specific state in addition to the base client cleanup.\n * It unsubscribes from span lifecycle events and clears pending span tracking.\n *\n * Call this method after flushing to allow the client to be garbage collected.\n * After calling dispose(), the client should not be used anymore.\n */\n public override dispose(): void {\n DEBUG_BUILD && debug.log('[CloudflareClient] Disposing client...');\n\n super.dispose();\n\n if (this._unsubscribeSpanStart) {\n this._unsubscribeSpanStart();\n this._unsubscribeSpanStart = null;\n }\n if (this._unsubscribeSpanEnd) {\n this._unsubscribeSpanEnd();\n this._unsubscribeSpanEnd = null;\n }\n\n this._resetSpanCompletionPromise();\n (this as unknown as { _flushLock: ReturnType<typeof makeFlushLock> | void })._flushLock = undefined;\n }\n\n /**\n * Resets the span completion promise and resolve function.\n */\n private _resetSpanCompletionPromise(): void {\n this._pendingSpans.clear();\n this._spanCompletionPromise = null;\n this._resolveSpanCompletion = null;\n }\n}\n\ninterface BaseCloudflareOptions {\n /**\n * @ignore Used internally to disable the deDupeIntegration for workflows.\n * @hidden Used internally to disable the deDupeIntegration for workflows.\n * @default true\n */\n enableDedupe?: boolean;\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n *\n * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`.\n *\n * @default false\n */\n skipOpenTelemetrySetup?: boolean;\n\n /**\n * Enable instrumentation of prototype methods for DurableObjects.\n *\n * When `true`, the SDK will wrap all methods on the DurableObject prototype chain\n * to automatically create spans and capture errors for RPC method calls.\n *\n * When an array of strings is provided, only the specified method names will be instrumented.\n *\n * This feature adds runtime overhead as it wraps methods at the prototype level.\n * Only enable this if you need automatic instrumentation of prototype methods.\n *\n * @default false\n * @example\n * ```ts\n * // Instrument all prototype methods\n * instrumentPrototypeMethods: true\n *\n * // Instrument only specific methods\n * instrumentPrototypeMethods: ['myMethod', 'anotherMethod']\n * ```\n */\n instrumentPrototypeMethods?: boolean | string[];\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK\n *\n * @see @sentry/core Options for more information.\n */\nexport interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {\n ctx?: ExecutionContext;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK Client class\n *\n * @see CloudflareClient for more information.\n */\nexport interface CloudflareClientOptions extends ClientOptions<CloudflareTransportOptions>, BaseCloudflareOptions {\n flushLock?: ReturnType<typeof makeFlushLock>;\n}\n"],"names":[],"mappings":";;;AAMA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,gBAAA,SAAyB,mBAAA,CAAoB;;AAE1D,kBAAU,aAAa,GAAgB,IAAI,GAAG,GAAC;AAC/C,GAAE,OAAA,GAAA,CAAA,IAAA,CAAQ,sBAAsB,GAAyB,KAAA;AACzD,GAAE,OAAA,GAAA,CAAA,IAAA,CAAQ,sBAAsB,GAAwB,KAAA;;AAExD,GAAE,OAAA,GAAA,CAAA,IAAA,CAAQ,qBAAqB,GAAwB,KAAA;AACvD,GAAE,OAAA,GAAA,CAAA,IAAA,CAAQ,mBAAmB,GAAwB,KAAA;;AAErD;AACA;AACA;AACA;AACA,GAAS,WAAW,CAAC,OAAO,EAA2B;AACvD,IAAI,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC;AAC3C,IAAI,OAAO,CAAC,SAAA,GAAY,OAAO,CAAC,SAAA,IAAa,EAAE;AAC/C,IAAI,MAAM,EAAE,SAAS,EAAE,GAAG,aAAA,EAAc,GAAI,OAAO;;AAEnD,IAAI,MAAM,aAAa,GAA+B;AACtD,MAAM,GAAG,aAAa;AACtB,MAAM,QAAQ,EAAE,YAAY;AAC5B;AACA,MAAM,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc;AACrC;AACA,KAAK;;AAEL,IAAI,KAAK,CAAC,aAAa,CAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,MAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,OAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,OAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,OAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CAAA,gBAAA,CAAA,SAAA,CAAA,OAAA,CAAA,IAAA,CAAA,IAAA,CAAA,CACvB,IAAI,IAAI,CAAC,UAAA,GAAa,SAAS;;AAE/B;AACA,IAAI,IAAI,CAAC,qBAAA,GAAwB,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,IAAA,IAAQ;AAC9D,MAAM,MAAM,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM;AAC9C,MAAM,WAAA,IAAe,KAAK,CAAC,GAAG,CAAC,kCAAkC,EAAE,MAAM,CAAC;AAC1E,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;;AAEpC,MAAM,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE;AACxC,QAAQ,IAAI,CAAC,sBAAA,GAAyB,IAAI,OAAO,CAAC,WAAW;AAC7D,UAAU,IAAI,CAAC,sBAAA,GAAyB,OAAO;AAC/C,QAAQ,CAAC,CAAC;AACV,MAAM;AACN,IAAI,CAAC,CAAC;;AAEN,IAAI,IAAI,CAAC,mBAAA,GAAsB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,IAAA,IAAQ;AAC1D,MAAM,MAAM,SAAS,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM;AAC9C,MAAM,WAAA,IAAe,KAAK,CAAC,GAAG,CAAC,gCAAgC,EAAE,MAAM,CAAC;AACxE,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;;AAEvC;AACA,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC,IAAA,KAAS,CAAA,IAAK,IAAI,CAAC,sBAAsB,EAAE;AACxE,QAAQ,eAAe,KAAK,CAAC,GAAG,CAAC,2DAA2D,CAAC;AAC7F,QAAQ,IAAI,CAAC,sBAAsB,EAAE;AACrC,QAAQ,IAAI,CAAC,2BAA2B,EAAE;AAC1C,MAAM;AACN,IAAI,CAAC,CAAC;AACN,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAS,MAAM,KAAK,CAAC,OAAO,EAA6B;AACzD,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE;AACzB,MAAM,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE;AACtC,IAAI;;AAEJ,IAAI,IAAI,IAAI,CAAC,aAAa,CAAC,IAAA,GAAO,CAAA,IAAK,IAAI,CAAC,sBAAsB,EAAE;AACpE,MAAM,WAAA;AACN,QAAQ,KAAK,CAAC,GAAG,CAAC,gCAAgC,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,8BAA8B,CAAC;;AAE5G,MAAM,MAAM,SAAA,GAAY,OAAA,IAAW,IAAI;AACvC,MAAM,MAAM,kBAAA,GAAqB,OAAO,CAAC,IAAI,CAAC;AAC9C,QAAQ,IAAI,CAAC,sBAAsB;AACnC,QAAQ,IAAI,OAAO,CAAC,OAAA;AACpB,UAAU,UAAU,CAAC,MAAM;AAC3B,YAAY,WAAA;AACZ,cAAc,KAAK,CAAC,GAAG,CAAC,kDAAkD,EAAE,SAAS,EAAE,qBAAqB,CAAC;AAC7G,YAAY,OAAO,CAAC,SAAS,CAAC;AAC9B,UAAU,CAAC,EAAE,SAAS,CAAC;AACvB,SAAS;AACT,OAAO,CAAC;;AAER,MAAM,MAAM,kBAAkB;AAC9B,IAAI;;AAEJ,IAAI,OAAO,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;AAC/B,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAkB,OAAO,GAAS;AAClC,IAAI,eAAe,KAAK,CAAC,GAAG,CAAC,wCAAwC,CAAC;;AAEtE,IAAI,KAAK,CAAC,OAAO,EAAE;;AAEnB,IAAI,IAAI,IAAI,CAAC,qBAAqB,EAAE;AACpC,MAAM,IAAI,CAAC,qBAAqB,EAAE;AAClC,MAAM,IAAI,CAAC,qBAAA,GAAwB,IAAI;AACvC,IAAI;AACJ,IAAI,IAAI,IAAI,CAAC,mBAAmB,EAAE;AAClC,MAAM,IAAI,CAAC,mBAAmB,EAAE;AAChC,MAAM,IAAI,CAAC,mBAAA,GAAsB,IAAI;AACrC,IAAI;;AAEJ,IAAI,IAAI,CAAC,2BAA2B,EAAE;AACtC,IAAI,CAAC,IAAA,GAA4E,UAAA,GAAa,SAAS;AACvG,EAAE;;AAEF;AACA;AACA;AACA,GAAU,2BAA2B,GAAS;AAC9C,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE;AAC9B,IAAI,IAAI,CAAC,sBAAA,GAAyB,IAAI;AACtC,IAAI,IAAI,CAAC,sBAAA,GAAyB,IAAI;AACtC,EAAE;AACF;;;;"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';\nimport { applySdkMetadata, debug, ServerRuntimeClient } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\n\n/**\n * The Sentry Cloudflare SDK Client.\n *\n * @see CloudflareClientOptions for documentation on configuration options.\n * @see ServerRuntimeClient for usage documentation.\n */\nexport class CloudflareClient extends ServerRuntimeClient {\n private readonly _flushLock: ReturnType<typeof makeFlushLock> | void;\n private _pendingSpans: Set<string> = new Set();\n private _spanCompletionPromise: Promise<void> | null = null;\n private _resolveSpanCompletion: (() => void) | null = null;\n\n private _unsubscribeSpanStart: (() => void) | null = null;\n private _unsubscribeSpanEnd: (() => void) | null = null;\n\n /**\n * Creates a new Cloudflare SDK instance.\n * @param options Configuration options for this SDK.\n */\n public constructor(options: CloudflareClientOptions) {\n applySdkMetadata(options, 'cloudflare');\n options._metadata = options._metadata || {};\n const { flushLock, ...serverOptions } = options;\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...serverOptions,\n platform: 'javascript',\n // TODO: Grab version information\n runtime: { name: 'cloudflare' },\n // TODO: Add server name\n };\n\n super(clientOptions);\n this._flushLock = flushLock;\n\n // Track span lifecycle to know when to flush\n this._unsubscribeSpanStart = this.on('spanStart', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span started:', spanId);\n this._pendingSpans.add(spanId);\n\n if (!this._spanCompletionPromise) {\n this._spanCompletionPromise = new Promise(resolve => {\n this._resolveSpanCompletion = resolve;\n });\n }\n });\n\n this._unsubscribeSpanEnd = this.on('spanEnd', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span ended:', spanId);\n this._pendingSpans.delete(spanId);\n\n // If no more pending spans, resolve the completion promise\n if (this._pendingSpans.size === 0 && this._resolveSpanCompletion) {\n DEBUG_BUILD && debug.log('[CloudflareClient] All spans completed, resolving promise');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\n }\n });\n }\n\n /**\n * Flushes pending operations and ensures all data is processed.\n * If a timeout is provided, the operation will be completed within the specified time limit.\n *\n * It will wait for all pending spans to complete before flushing.\n *\n * @param {number} [timeout] - Optional timeout in milliseconds to force the completion of the flush operation.\n * @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.\n */\n public async flush(timeout?: number): Promise<boolean> {\n if (this._flushLock) {\n await this._flushLock.finalize();\n }\n\n if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Waiting for', this._pendingSpans.size, 'pending spans to complete...');\n\n const timeoutMs = timeout ?? 5000;\n const spanCompletionRace = Promise.race([\n this._spanCompletionPromise,\n new Promise(resolve =>\n setTimeout(() => {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Span completion timeout after', timeoutMs, 'ms, flushing anyway');\n resolve(undefined);\n }, timeoutMs),\n ),\n ]);\n\n await spanCompletionRace;\n }\n\n return super.flush(timeout);\n }\n\n /**\n * Disposes of the client and releases all resources.\n *\n * This method clears all Cloudflare-specific state in addition to the base client cleanup.\n * It unsubscribes from span lifecycle events and clears pending span tracking.\n *\n * Call this method after flushing to allow the client to be garbage collected.\n * After calling dispose(), the client should not be used anymore.\n */\n public override dispose(): void {\n DEBUG_BUILD && debug.log('[CloudflareClient] Disposing client...');\n\n super.dispose();\n\n if (this._unsubscribeSpanStart) {\n this._unsubscribeSpanStart();\n this._unsubscribeSpanStart = null;\n }\n if (this._unsubscribeSpanEnd) {\n this._unsubscribeSpanEnd();\n this._unsubscribeSpanEnd = null;\n }\n\n this._resetSpanCompletionPromise();\n (this as unknown as { _flushLock: ReturnType<typeof makeFlushLock> | void })._flushLock = undefined;\n }\n\n /**\n * Resets the span completion promise and resolve function.\n */\n private _resetSpanCompletionPromise(): void {\n this._pendingSpans.clear();\n this._spanCompletionPromise = null;\n this._resolveSpanCompletion = null;\n }\n}\n\ninterface BaseCloudflareOptions {\n /**\n * @ignore Used internally to disable the deDupeIntegration for workflows.\n * @hidden Used internally to disable the deDupeIntegration for workflows.\n * @default true\n */\n enableDedupe?: boolean;\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n *\n * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`.\n *\n * @default false\n */\n skipOpenTelemetrySetup?: boolean;\n\n /**\n * Enable trace propagation for RPC calls between Workers, Durable Objects, and Service Bindings.\n *\n * When enabled, trace context (sentry-trace + baggage) is propagated across:\n * - `stub.fetch()` calls to Durable Objects (via HTTP headers)\n * - Service binding `fetch()` calls (via HTTP headers)\n * - RPC method calls to Durable Objects (via trailing argument)\n *\n * When enabled on the **receiver side** (DurableObject), the SDK will also:\n * - Extract and continue traces from incoming RPC calls\n * - Create spans for each RPC method invocation\n * - Capture errors thrown by RPC methods\n *\n * **Important:** This option should be enabled on **both sides** for full trace propagation.\n *\n * @default false\n * @example\n * ```ts\n * // Worker side (caller)\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * handler,\n * );\n *\n * // Durable Object side (receiver)\n * export const MyDO = Sentry.instrumentDurableObjectWithSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * MyDOBase,\n * );\n * ```\n */\n enableRpcTracePropagation?: boolean;\n\n /**\n * @deprecated Use `enableRpcTracePropagation` instead. This option will be removed in a future major version.\n *\n * Enable instrumentation of prototype methods for DurableObjects.\n *\n * When `true`, the SDK will wrap all methods on the DurableObject prototype chain\n * to automatically create spans and capture errors for RPC method calls.\n *\n * When an array of strings is provided, only the specified method names will be instrumented.\n *\n * @default false\n */\n instrumentPrototypeMethods?: boolean | string[];\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK\n *\n * @see @sentry/core Options for more information.\n */\nexport interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {\n ctx?: ExecutionContext;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK Client class\n *\n * @see CloudflareClient for more information.\n */\nexport interface CloudflareClientOptions extends ClientOptions<CloudflareTransportOptions>, BaseCloudflareOptions {\n flushLock?: ReturnType<typeof makeFlushLock>;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { captureException } from '@sentry/core';
|
|
2
2
|
import { setAsyncLocalStorageAsyncContextStrategy } from './async.js';
|
|
3
3
|
import { ensureInstrumented, getInstrumented, markAsInstrumented } from './instrument.js';
|
|
4
|
+
import { instrumentEnv } from './instrumentations/worker/instrumentEnv.js';
|
|
4
5
|
import { getFinalOptions } from './options.js';
|
|
5
6
|
import { wrapRequestHandler } from './request.js';
|
|
6
7
|
import { instrumentContext } from './utils/instrumentContext.js';
|
|
8
|
+
import { getPrototypeMethodFilter } from './utils/rpcOptions.js';
|
|
7
9
|
import { wrapMethodWithSentry } from './wrapMethodWithSentry.js';
|
|
8
10
|
|
|
9
11
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
@@ -48,10 +50,10 @@ function instrumentDurableObjectWithSentry
|
|
|
48
50
|
construct(target, [ctx, env]) {
|
|
49
51
|
setAsyncLocalStorageAsyncContextStrategy();
|
|
50
52
|
const context = instrumentContext(ctx);
|
|
51
|
-
|
|
52
53
|
const options = getFinalOptions(optionsCallback(env), env);
|
|
54
|
+
const instrumentedEnv = instrumentEnv(env, options);
|
|
53
55
|
|
|
54
|
-
const obj = new target(context,
|
|
56
|
+
const obj = new target(context, instrumentedEnv);
|
|
55
57
|
|
|
56
58
|
// These are the methods that are available on a Durable Object
|
|
57
59
|
// ref: https://developers.cloudflare.com/durable-objects/api/base/
|
|
@@ -78,7 +80,11 @@ function instrumentDurableObjectWithSentry
|
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
if (obj.alarm && typeof obj.alarm === 'function') {
|
|
81
|
-
|
|
83
|
+
// Alarms are independent invocations, so we start a new trace and link to the previous alarm
|
|
84
|
+
obj.alarm = wrapMethodWithSentry(
|
|
85
|
+
{ options, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },
|
|
86
|
+
obj.alarm,
|
|
87
|
+
);
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {
|
|
@@ -143,8 +149,10 @@ function instrumentDurableObjectWithSentry
|
|
|
143
149
|
configurable: false,
|
|
144
150
|
});
|
|
145
151
|
|
|
146
|
-
|
|
147
|
-
|
|
152
|
+
const methodFilter = getPrototypeMethodFilter(options);
|
|
153
|
+
|
|
154
|
+
if (methodFilter) {
|
|
155
|
+
instrumentPrototype(target, methodFilter);
|
|
148
156
|
}
|
|
149
157
|
|
|
150
158
|
return obj;
|
|
@@ -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, 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
|
+
{"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 { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport { getPrototypeMethodFilter } from './utils/rpcOptions';\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 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 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 const methodFilter = getPrototypeMethodFilter(options);\n\n if (methodFilter) {\n instrumentPrototype(target, methodFilter);\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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"}
|
package/build/esm/index.js
CHANGED
|
@@ -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, 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';
|
|
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, spanStreamingIntegration, 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';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { instrumentFetcher } from './worker/instrumentFetcher.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Instruments a DurableObjectNamespace binding to create spans for DO interactions.
|
|
5
|
+
*
|
|
6
|
+
* Wraps:
|
|
7
|
+
* - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub
|
|
8
|
+
* - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs
|
|
9
|
+
*
|
|
10
|
+
* @param namespace - The DurableObjectNamespace to instrument
|
|
11
|
+
*/
|
|
12
|
+
function instrumentDurableObjectNamespace(namespace) {
|
|
13
|
+
return new Proxy(namespace, {
|
|
14
|
+
get(target, prop, _receiver) {
|
|
15
|
+
const value = Reflect.get(target, prop) ;
|
|
16
|
+
|
|
17
|
+
if (typeof value !== 'function') {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (prop === 'get' || prop === 'getByName') {
|
|
22
|
+
return function ( ...args) {
|
|
23
|
+
const stub = Reflect.apply(value, target, args);
|
|
24
|
+
|
|
25
|
+
return instrumentDurableObjectStub(stub);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return value.bind(target);
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Instruments a DurableObjectStub to propagate trace context across fetch calls.
|
|
36
|
+
*
|
|
37
|
+
* @param stub - The DurableObjectStub to instrument
|
|
38
|
+
*/
|
|
39
|
+
function instrumentDurableObjectStub(stub) {
|
|
40
|
+
return new Proxy(stub, {
|
|
41
|
+
get(target, prop, receiver) {
|
|
42
|
+
const value = Reflect.get(target, prop, receiver);
|
|
43
|
+
|
|
44
|
+
if (prop === 'fetch' && typeof value === 'function') {
|
|
45
|
+
return instrumentFetcher((input, init) => Reflect.apply(value, target, [input, init]));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return value;
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { instrumentDurableObjectNamespace };
|
|
54
|
+
//# sourceMappingURL=instrumentDurableObjectNamespace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentDurableObjectNamespace.js","sources":["../../../src/instrumentations/instrumentDurableObjectNamespace.ts"],"sourcesContent":["import type { DurableObjectNamespace, DurableObjectStub } from '@cloudflare/workers-types';\nimport { instrumentFetcher } from './worker/instrumentFetcher';\n\n/**\n * Instruments a DurableObjectNamespace binding to create spans for DO interactions.\n *\n * Wraps:\n * - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub\n * - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs\n *\n * @param namespace - The DurableObjectNamespace to instrument\n */\nexport function instrumentDurableObjectNamespace(namespace: DurableObjectNamespace): DurableObjectNamespace {\n return new Proxy(namespace, {\n get(target, prop, _receiver) {\n const value = Reflect.get(target, prop) as unknown;\n\n if (typeof value !== 'function') {\n return value;\n }\n\n if (prop === 'get' || prop === 'getByName') {\n return function (this: unknown, ...args: unknown[]) {\n const stub = Reflect.apply(value, target, args);\n\n return instrumentDurableObjectStub(stub);\n };\n }\n\n return value.bind(target);\n },\n });\n}\n\n/**\n * Instruments a DurableObjectStub to propagate trace context across fetch calls.\n *\n * @param stub - The DurableObjectStub to instrument\n */\nfunction instrumentDurableObjectStub(stub: DurableObjectStub): DurableObjectStub {\n return new Proxy(stub, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((input, init) => Reflect.apply(value, target, [input, init]));\n }\n\n return value;\n },\n });\n}\n"],"names":[],"mappings":";;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,gCAAgC,CAAC,SAAS,EAAkD;AAC5G,EAAE,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE;AAC9B,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;AACjC,MAAM,MAAM,KAAA,GAAQ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAA;;AAE5C,MAAM,IAAI,OAAO,KAAA,KAAU,UAAU,EAAE;AACvC,QAAQ,OAAO,KAAK;AACpB,MAAM;;AAEN,MAAM,IAAI,IAAA,KAAS,SAAS,IAAA,KAAS,WAAW,EAAE;AAClD,QAAQ,OAAO,WAAyB,GAAG,IAAI,EAAa;AAC5D,UAAU,MAAM,IAAA,GAAO,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;;AAEzD,UAAU,OAAO,2BAA2B,CAAC,IAAI,CAAC;AAClD,QAAQ,CAAC;AACT,MAAM;;AAEN,MAAM,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AAC/B,IAAI,CAAC;AACL,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS,2BAA2B,CAAC,IAAI,EAAwC;AACjF,EAAE,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE;AACzB,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;AAChC,MAAM,MAAM,KAAA,GAAQ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC;;AAEvD,MAAM,IAAI,IAAA,KAAS,OAAA,IAAW,OAAO,KAAA,KAAU,UAAU,EAAE;AAC3D,QAAQ,OAAO,iBAAiB,CAAC,CAAC,KAAK,EAAE,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAC9F,MAAM;;AAEN,MAAM,OAAO,KAAK;AAClB,IAAI,CAAC;AACL,GAAG,CAAC;AACJ;;;;"}
|
|
@@ -1,17 +1,26 @@
|
|
|
1
|
-
import { startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
|
|
1
|
+
import { startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, isThenable } from '@sentry/core';
|
|
2
|
+
import { storeSpanContext } from '../utils/traceLinks.js';
|
|
2
3
|
|
|
3
|
-
const STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list'] ;
|
|
4
|
+
const STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list', 'setAlarm', 'getAlarm', 'deleteAlarm'] ;
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Instruments DurableObjectStorage methods with Sentry spans.
|
|
7
8
|
*
|
|
8
9
|
* Wraps the following async methods:
|
|
9
10
|
* - get, put, delete, list (KV API)
|
|
11
|
+
* - setAlarm, getAlarm, deleteAlarm (Alarm API)
|
|
12
|
+
*
|
|
13
|
+
* When setAlarm is called, it also stores the current span context so that when
|
|
14
|
+
* the alarm fires later, it can link back to the trace that called setAlarm.
|
|
10
15
|
*
|
|
11
16
|
* @param storage - The DurableObjectStorage instance to instrument
|
|
17
|
+
* @param waitUntil - Optional waitUntil function to defer span context storage
|
|
12
18
|
* @returns An instrumented DurableObjectStorage instance
|
|
13
19
|
*/
|
|
14
|
-
function instrumentDurableObjectStorage(
|
|
20
|
+
function instrumentDurableObjectStorage(
|
|
21
|
+
storage,
|
|
22
|
+
waitUntil,
|
|
23
|
+
) {
|
|
15
24
|
return new Proxy(storage, {
|
|
16
25
|
get(target, prop, _receiver) {
|
|
17
26
|
// Use `target` as the receiver instead of the proxy (`_receiver`).
|
|
@@ -43,7 +52,33 @@ function instrumentDurableObjectStorage(storage) {
|
|
|
43
52
|
},
|
|
44
53
|
},
|
|
45
54
|
() => {
|
|
46
|
-
|
|
55
|
+
const teardown = async () => {
|
|
56
|
+
// When setAlarm is called, store the current span context so that when the alarm
|
|
57
|
+
// fires later, it can link back to the trace that called setAlarm.
|
|
58
|
+
// We use the original (uninstrumented) storage (target) to avoid creating a span
|
|
59
|
+
// for this internal operation. The storage is deferred via waitUntil to not block.
|
|
60
|
+
if (methodName === 'setAlarm') {
|
|
61
|
+
await storeSpanContext(target, 'alarm');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const result = (original ).apply(target, args);
|
|
66
|
+
|
|
67
|
+
if (!isThenable(result)) {
|
|
68
|
+
waitUntil?.(teardown());
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result.then(
|
|
74
|
+
res => {
|
|
75
|
+
waitUntil?.(teardown());
|
|
76
|
+
return res;
|
|
77
|
+
},
|
|
78
|
+
e => {
|
|
79
|
+
throw e;
|
|
80
|
+
},
|
|
81
|
+
);
|
|
47
82
|
},
|
|
48
83
|
);
|
|
49
84
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentDurableObjectStorage.js","sources":["../../../src/instrumentations/instrumentDurableObjectStorage.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\n\nconst STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list'] as const;\n\ntype StorageMethod = (typeof STORAGE_METHODS_TO_INSTRUMENT)[number];\n\n/**\n * Instruments DurableObjectStorage methods with Sentry spans.\n *\n * Wraps the following async methods:\n * - get, put, delete, list (KV API)\n *\n * @param storage - The DurableObjectStorage instance to instrument\n * @returns An instrumented DurableObjectStorage instance\n */\nexport function instrumentDurableObjectStorage(storage: DurableObjectStorage): DurableObjectStorage {\n return new Proxy(storage, {\n get(target, prop, _receiver) {\n // Use `target` as the receiver instead of the proxy (`_receiver`).\n // Native workerd getters (e.g., `storage.sql`) validate `this` via\n // internal slots. Passing the proxy as receiver breaks that check,\n // causing \"Illegal invocation: function called with incorrect `this`\n // reference\" errors.\n const original = Reflect.get(target, prop, target);\n\n if (typeof original !== 'function') {\n return original;\n }\n\n const methodName = prop as string;\n if (!STORAGE_METHODS_TO_INSTRUMENT.includes(methodName as StorageMethod)) {\n return (original as (...args: unknown[]) => unknown).bind(target);\n }\n\n return function (this: unknown, ...args: unknown[]) {\n return startSpan(\n {\n // Use underscore naming to match Cloudflare's native instrumentation (e.g., \"durable_object_storage_get\")\n name: `durable_object_storage_${methodName}`,\n op: 'db',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.durable_object',\n 'db.system.name': 'cloudflare.durable_object.storage',\n 'db.operation.name': methodName,\n },\n },\n () => {\n
|
|
1
|
+
{"version":3,"file":"instrumentDurableObjectStorage.js","sources":["../../../src/instrumentations/instrumentDurableObjectStorage.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport { isThenable, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\nimport { storeSpanContext } from '../utils/traceLinks';\n\nconst STORAGE_METHODS_TO_INSTRUMENT = ['get', 'put', 'delete', 'list', 'setAlarm', 'getAlarm', 'deleteAlarm'] as const;\n\ntype StorageMethod = (typeof STORAGE_METHODS_TO_INSTRUMENT)[number];\n\ntype WaitUntil = (promise: Promise<unknown>) => void;\n\n/**\n * Instruments DurableObjectStorage methods with Sentry spans.\n *\n * Wraps the following async methods:\n * - get, put, delete, list (KV API)\n * - setAlarm, getAlarm, deleteAlarm (Alarm API)\n *\n * When setAlarm is called, it also stores the current span context so that when\n * the alarm fires later, it can link back to the trace that called setAlarm.\n *\n * @param storage - The DurableObjectStorage instance to instrument\n * @param waitUntil - Optional waitUntil function to defer span context storage\n * @returns An instrumented DurableObjectStorage instance\n */\nexport function instrumentDurableObjectStorage(\n storage: DurableObjectStorage,\n waitUntil?: WaitUntil,\n): DurableObjectStorage {\n return new Proxy(storage, {\n get(target, prop, _receiver) {\n // Use `target` as the receiver instead of the proxy (`_receiver`).\n // Native workerd getters (e.g., `storage.sql`) validate `this` via\n // internal slots. Passing the proxy as receiver breaks that check,\n // causing \"Illegal invocation: function called with incorrect `this`\n // reference\" errors.\n const original = Reflect.get(target, prop, target);\n\n if (typeof original !== 'function') {\n return original;\n }\n\n const methodName = prop as string;\n if (!STORAGE_METHODS_TO_INSTRUMENT.includes(methodName as StorageMethod)) {\n return (original as (...args: unknown[]) => unknown).bind(target);\n }\n\n return function (this: unknown, ...args: unknown[]) {\n return startSpan(\n {\n // Use underscore naming to match Cloudflare's native instrumentation (e.g., \"durable_object_storage_get\")\n name: `durable_object_storage_${methodName}`,\n op: 'db',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.durable_object',\n 'db.system.name': 'cloudflare.durable_object.storage',\n 'db.operation.name': methodName,\n },\n },\n () => {\n const teardown = async (): Promise<void> => {\n // When setAlarm is called, store the current span context so that when the alarm\n // fires later, it can link back to the trace that called setAlarm.\n // We use the original (uninstrumented) storage (target) to avoid creating a span\n // for this internal operation. The storage is deferred via waitUntil to not block.\n if (methodName === 'setAlarm') {\n await storeSpanContext(target, 'alarm');\n }\n };\n\n const result = (original as (...args: unknown[]) => unknown).apply(target, args);\n\n if (!isThenable(result)) {\n waitUntil?.(teardown());\n\n return result;\n }\n\n return result.then(\n res => {\n waitUntil?.(teardown());\n return res;\n },\n e => {\n throw e;\n },\n );\n },\n );\n };\n },\n });\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,gCAAgC,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,CAAA;;AAM5G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,8BAA8B;AAC9C,EAAE,OAAO;AACT,EAAE,SAAS;AACX,EAAwB;AACxB,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;AAC5B,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;AACjC;AACA;AACA;AACA;AACA;AACA,MAAM,MAAM,QAAA,GAAW,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;;AAExD,MAAM,IAAI,OAAO,QAAA,KAAa,UAAU,EAAE;AAC1C,QAAQ,OAAO,QAAQ;AACvB,MAAM;;AAEN,MAAM,MAAM,UAAA,GAAa,IAAA;AACzB,MAAM,IAAI,CAAC,6BAA6B,CAAC,QAAQ,CAAC,UAAA,EAA4B,EAAE;AAChF,QAAQ,OAAO,CAAC,QAAA,GAA6C,IAAI,CAAC,MAAM,CAAC;AACzE,MAAM;;AAEN,MAAM,OAAO,WAAyB,GAAG,IAAI,EAAa;AAC1D,QAAQ,OAAO,SAAS;AACxB,UAAU;AACV;AACA,YAAY,IAAI,EAAE,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAA;AACA,YAAA,EAAA,EAAA,IAAA;AACA,YAAA,UAAA,EAAA;AACA,cAAA,CAAA,gCAAA,GAAA,mCAAA;AACA,cAAA,gBAAA,EAAA,mCAAA;AACA,cAAA,mBAAA,EAAA,UAAA;AACA,aAAA;AACA,WAAA;AACA,UAAA,MAAA;AACA,YAAA,MAAA,QAAA,GAAA,YAAA;AACA;AACA;AACA;AACA;AACA,cAAA,IAAA,UAAA,KAAA,UAAA,EAAA;AACA,gBAAA,MAAA,gBAAA,CAAA,MAAA,EAAA,OAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;;AAEA,YAAA,MAAA,MAAA,GAAA,CAAA,QAAA,GAAA,KAAA,CAAA,MAAA,EAAA,IAAA,CAAA;;AAEA,YAAA,IAAA,CAAA,UAAA,CAAA,MAAA,CAAA,EAAA;AACA,cAAA,SAAA,GAAA,QAAA,EAAA,CAAA;;AAEA,cAAA,OAAA,MAAA;AACA,YAAA;;AAEA,YAAA,OAAA,MAAA,CAAA,IAAA;AACA,cAAA,GAAA,IAAA;AACA,gBAAA,SAAA,GAAA,QAAA,EAAA,CAAA;AACA,gBAAA,OAAA,GAAA;AACA,cAAA,CAAA;AACA,cAAA,CAAA,IAAA;AACA,gBAAA,MAAA,CAAA;AACA,cAAA,CAAA;AACA,aAAA;AACA,UAAA,CAAA;AACA,SAAA;AACA,MAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;;;"}
|