@sentry/cloudflare 10.39.0 → 10.41.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/durableobject.js +9 -133
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/handler.js +6 -6
- package/build/cjs/handler.js.map +1 -1
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js +52 -0
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js.map +1 -0
- package/build/cjs/utils/instrumentContext.js +103 -0
- package/build/cjs/utils/instrumentContext.js.map +1 -0
- package/build/cjs/workflows.js +2 -2
- package/build/cjs/workflows.js.map +1 -1
- package/build/cjs/wrapMethodWithSentry.js +143 -0
- package/build/cjs/wrapMethodWithSentry.js.map +1 -0
- package/build/esm/durableobject.js +4 -128
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/handler.js +6 -6
- package/build/esm/handler.js.map +1 -1
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js +50 -0
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/utils/instrumentContext.js +101 -0
- package/build/esm/utils/instrumentContext.js.map +1 -0
- package/build/esm/workflows.js +2 -2
- package/build/esm/workflows.js.map +1 -1
- package/build/esm/wrapMethodWithSentry.js +141 -0
- package/build/esm/wrapMethodWithSentry.js.map +1 -0
- package/build/types/durableobject.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts +12 -0
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts.map +1 -0
- package/build/types/utils/instrumentContext.d.ts +16 -0
- package/build/types/utils/instrumentContext.d.ts.map +1 -0
- package/build/types/wrapMethodWithSentry.d.ts +21 -0
- package/build/types/wrapMethodWithSentry.d.ts.map +1 -0
- package/build/types-ts3.8/instrumentations/instrumentDurableObjectStorage.d.ts +12 -0
- package/build/types-ts3.8/utils/instrumentContext.d.ts +16 -0
- package/build/types-ts3.8/wrapMethodWithSentry.d.ts +21 -0
- package/package.json +3 -4
- package/build/cjs/utils/copyExecutionContext.js +0 -69
- package/build/cjs/utils/copyExecutionContext.js.map +0 -1
- package/build/esm/utils/copyExecutionContext.js +0 -67
- package/build/esm/utils/copyExecutionContext.js.map +0 -1
- package/build/types/utils/copyExecutionContext.d.ts +0 -11
- package/build/types/utils/copyExecutionContext.d.ts.map +0 -1
- package/build/types-ts3.8/utils/copyExecutionContext.d.ts +0 -11
|
@@ -0,0 +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 const original = Reflect.get(target, prop, receiver);\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 return (original as (...args: unknown[]) => unknown).apply(target, args);\n },\n );\n };\n },\n });\n}\n"],"names":[],"mappings":";;AAGA,MAAM,6BAAA,GAAgC,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAA;;AAIrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,8BAA8B,CAAC,OAAO,EAA8C;AACpG,EAAE,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;AAC5B,IAAI,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;AAChC,MAAM,MAAM,QAAA,GAAW,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC;;AAE1D,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,OAAA,CAAA,QAAA,GAAA,KAAA,CAAA,MAAA,EAAA,IAAA,CAAA;AACA,UAAA,CAAA;AACA,SAAA;AACA,MAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA,CAAA;AACA;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.41.0-beta.0","sideEffects":false}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { instrumentDurableObjectStorage } from '../instrumentations/instrumentDurableObjectStorage.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Instruments an execution context or DurableObjectState with Sentry tracing.
|
|
5
|
+
*
|
|
6
|
+
* Creates a copy of the context that:
|
|
7
|
+
* - Allows overriding of methods (e.g., waitUntil)
|
|
8
|
+
* - For DurableObjectState: instruments storage operations (get, put, delete, list, etc.)
|
|
9
|
+
* to create Sentry spans automatically
|
|
10
|
+
*
|
|
11
|
+
* @param ctx - The execution context or DurableObjectState to instrument
|
|
12
|
+
* @returns An instrumented copy of the context
|
|
13
|
+
*/
|
|
14
|
+
function instrumentContext(ctx) {
|
|
15
|
+
if (!ctx) return ctx;
|
|
16
|
+
|
|
17
|
+
const overrides = new Map();
|
|
18
|
+
const contextPrototype = Object.getPrototypeOf(ctx);
|
|
19
|
+
const prototypeMethodNames = Object.getOwnPropertyNames(contextPrototype) ;
|
|
20
|
+
const ownPropertyNames = Object.getOwnPropertyNames(ctx) ;
|
|
21
|
+
const instrumented = new Set(['constructor']);
|
|
22
|
+
const descriptors = [...ownPropertyNames, ...prototypeMethodNames].reduce(
|
|
23
|
+
(prevDescriptors, methodName) => {
|
|
24
|
+
if (instrumented.has(methodName)) return prevDescriptors;
|
|
25
|
+
if (typeof ctx[methodName] !== 'function') return prevDescriptors;
|
|
26
|
+
instrumented.add(methodName);
|
|
27
|
+
const overridableDescriptor = makeOverridableDescriptor(overrides, ctx, methodName);
|
|
28
|
+
return {
|
|
29
|
+
...prevDescriptors,
|
|
30
|
+
[methodName]: overridableDescriptor,
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
{} ,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Check if this is a DurableObjectState context with a storage property
|
|
37
|
+
// If so, wrap the storage with instrumentation
|
|
38
|
+
if ('storage' in ctx && ctx.storage) {
|
|
39
|
+
const originalStorage = ctx.storage;
|
|
40
|
+
let instrumentedStorage;
|
|
41
|
+
descriptors.storage = {
|
|
42
|
+
configurable: true,
|
|
43
|
+
enumerable: true,
|
|
44
|
+
get: () => {
|
|
45
|
+
if (!instrumentedStorage) {
|
|
46
|
+
instrumentedStorage = instrumentDurableObjectStorage(originalStorage);
|
|
47
|
+
}
|
|
48
|
+
return instrumentedStorage;
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
// Expose the original uninstrumented storage for internal Sentry operations
|
|
52
|
+
// This avoids creating spans for internal storage operations
|
|
53
|
+
descriptors.originalStorage = {
|
|
54
|
+
configurable: true,
|
|
55
|
+
enumerable: false,
|
|
56
|
+
get: () => originalStorage,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return Object.create(ctx, descriptors);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Creates a property descriptor that allows overriding of a method on the given context object.
|
|
65
|
+
*
|
|
66
|
+
* This descriptor supports property overriding with functions only. It delegates method calls to
|
|
67
|
+
* the provided store if an override exists or to the original method on the context otherwise.
|
|
68
|
+
*
|
|
69
|
+
* @param {OverridesStore<ContextType>} store - The storage for overridden methods specific to the context type.
|
|
70
|
+
* @param {ContextType} ctx - The context object that contains the method to be overridden.
|
|
71
|
+
* @param {keyof ContextType} method - The method on the context object to create the overridable descriptor for.
|
|
72
|
+
* @return {PropertyDescriptor} A property descriptor enabling the overriding of the specified method.
|
|
73
|
+
*/
|
|
74
|
+
function makeOverridableDescriptor(
|
|
75
|
+
store,
|
|
76
|
+
ctx,
|
|
77
|
+
method,
|
|
78
|
+
) {
|
|
79
|
+
return {
|
|
80
|
+
configurable: true,
|
|
81
|
+
enumerable: true,
|
|
82
|
+
set: newValue => {
|
|
83
|
+
if (typeof newValue == 'function') {
|
|
84
|
+
store.set(method, newValue);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
Reflect.set(ctx, method, newValue);
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
get: () => {
|
|
91
|
+
if (store.has(method)) return store.get(method);
|
|
92
|
+
const methodFunction = Reflect.get(ctx, method);
|
|
93
|
+
if (typeof methodFunction !== 'function') return methodFunction;
|
|
94
|
+
// We should do bind() to make sure that the method is bound to the context object - otherwise it will not work
|
|
95
|
+
return methodFunction.bind(ctx);
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { instrumentContext };
|
|
101
|
+
//# sourceMappingURL=instrumentContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentContext.js","sources":["../../../src/utils/instrumentContext.ts"],"sourcesContent":["import { type DurableObjectState, type DurableObjectStorage, type ExecutionContext } from '@cloudflare/workers-types';\nimport { instrumentDurableObjectStorage } from '../instrumentations/instrumentDurableObjectStorage';\n\ntype ContextType = ExecutionContext | DurableObjectState;\ntype OverridesStore<T extends ContextType> = Map<keyof T, (...args: unknown[]) => unknown>;\n\n/**\n * Instruments an execution context or DurableObjectState with Sentry tracing.\n *\n * Creates a copy of the context that:\n * - Allows overriding of methods (e.g., waitUntil)\n * - For DurableObjectState: instruments storage operations (get, put, delete, list, etc.)\n * to create Sentry spans automatically\n *\n * @param ctx - The execution context or DurableObjectState to instrument\n * @returns An instrumented copy of the context\n */\nexport function instrumentContext<T extends ContextType>(ctx: T): T {\n if (!ctx) return ctx;\n\n const overrides: OverridesStore<T> = new Map();\n const contextPrototype = Object.getPrototypeOf(ctx);\n const prototypeMethodNames = Object.getOwnPropertyNames(contextPrototype) as unknown as (keyof T)[];\n const ownPropertyNames = Object.getOwnPropertyNames(ctx) as unknown as (keyof T)[];\n const instrumented = new Set<unknown>(['constructor']);\n const descriptors: PropertyDescriptorMap = [...ownPropertyNames, ...prototypeMethodNames].reduce(\n (prevDescriptors, methodName) => {\n if (instrumented.has(methodName)) return prevDescriptors;\n if (typeof ctx[methodName] !== 'function') return prevDescriptors;\n instrumented.add(methodName);\n const overridableDescriptor = makeOverridableDescriptor(overrides, ctx, methodName);\n return {\n ...prevDescriptors,\n [methodName]: overridableDescriptor,\n };\n },\n {} as PropertyDescriptorMap,\n );\n\n // Check if this is a DurableObjectState context with a storage property\n // If so, wrap the storage with instrumentation\n if ('storage' in ctx && ctx.storage) {\n const originalStorage = ctx.storage;\n let instrumentedStorage: DurableObjectStorage | undefined;\n descriptors.storage = {\n configurable: true,\n enumerable: true,\n get: () => {\n if (!instrumentedStorage) {\n instrumentedStorage = instrumentDurableObjectStorage(originalStorage);\n }\n return instrumentedStorage;\n },\n };\n // Expose the original uninstrumented storage for internal Sentry operations\n // This avoids creating spans for internal storage operations\n descriptors.originalStorage = {\n configurable: true,\n enumerable: false,\n get: () => originalStorage,\n };\n }\n\n return Object.create(ctx, descriptors);\n}\n\n/**\n * Creates a property descriptor that allows overriding of a method on the given context object.\n *\n * This descriptor supports property overriding with functions only. It delegates method calls to\n * the provided store if an override exists or to the original method on the context otherwise.\n *\n * @param {OverridesStore<ContextType>} store - The storage for overridden methods specific to the context type.\n * @param {ContextType} ctx - The context object that contains the method to be overridden.\n * @param {keyof ContextType} method - The method on the context object to create the overridable descriptor for.\n * @return {PropertyDescriptor} A property descriptor enabling the overriding of the specified method.\n */\nfunction makeOverridableDescriptor<T extends ContextType>(\n store: OverridesStore<T>,\n ctx: T,\n method: keyof T,\n): PropertyDescriptor {\n return {\n configurable: true,\n enumerable: true,\n set: newValue => {\n if (typeof newValue == 'function') {\n store.set(method, newValue);\n return;\n }\n Reflect.set(ctx, method, newValue);\n },\n\n get: () => {\n if (store.has(method)) return store.get(method);\n const methodFunction = Reflect.get(ctx, method);\n if (typeof methodFunction !== 'function') return methodFunction;\n // We should do bind() to make sure that the method is bound to the context object - otherwise it will not work\n return methodFunction.bind(ctx);\n },\n };\n}\n"],"names":[],"mappings":"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"}
|
package/build/esm/workflows.js
CHANGED
|
@@ -2,7 +2,7 @@ import { withIsolationScope, withScope, flush, getCurrentScope, startSpan, SEMAN
|
|
|
2
2
|
import { setAsyncLocalStorageAsyncContextStrategy } from './async.js';
|
|
3
3
|
import { addCloudResourceContext } from './scope-utils.js';
|
|
4
4
|
import { init } from './sdk.js';
|
|
5
|
-
import {
|
|
5
|
+
import { instrumentContext } from './utils/instrumentContext.js';
|
|
6
6
|
|
|
7
7
|
const UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
|
|
8
8
|
|
|
@@ -129,7 +129,7 @@ function instrumentWorkflowWithSentry
|
|
|
129
129
|
return new Proxy(WorkFlowClass, {
|
|
130
130
|
construct(target, args, newTarget) {
|
|
131
131
|
const [ctx, env] = args;
|
|
132
|
-
const context =
|
|
132
|
+
const context = instrumentContext(ctx);
|
|
133
133
|
args[0] = context;
|
|
134
134
|
|
|
135
135
|
const options = optionsCallback(env);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflows.js","sources":["../../src/workflows.ts"],"sourcesContent":["import type { PropagationContext } from '@sentry/core';\nimport {\n captureException,\n flush,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type {\n WorkflowEntrypoint,\n WorkflowEvent,\n WorkflowSleepDuration,\n WorkflowStep,\n WorkflowStepConfig,\n WorkflowStepEvent,\n WorkflowTimeoutDuration,\n} from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\nimport { copyExecutionContext } from './utils/copyExecutionContext';\n\nconst UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;\n\n/**\n * Hashes a string to a UUID using SHA-1.\n */\nexport async function deterministicTraceIdFromInstanceId(instanceId: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(instanceId));\n return (\n Array.from(new Uint8Array(buf))\n // We only need the first 16 bytes for the 32 characters\n .slice(0, 16)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n );\n}\n\nasync function propagationContextFromInstanceId(instanceId: string): Promise<PropagationContext> {\n const traceId = UUID_REGEX.test(instanceId)\n ? instanceId.replace(/-/g, '')\n : await deterministicTraceIdFromInstanceId(instanceId);\n\n // Derive sampleRand from last 4 characters of the random UUID\n //\n // We cannot store any state between workflow steps, so we derive the\n // sampleRand from the traceId itself. This ensures that the sampling is\n // consistent across all steps in the same workflow instance.\n const sampleRand = parseInt(traceId.slice(-4), 16) / 0xffff;\n\n return {\n traceId,\n sampleRand,\n };\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _ctx: ExecutionContext,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: () => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ): Promise<T> {\n // Capture the current scope, so parent span (e.g., a startSpan surrounding step.do) is preserved\n const scopeForStep = getCurrentScope();\n\n const userCallback = (maybeCallback || configOrCallback) as () => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\n\n const instrumentedCallback: () => Promise<T> = async () => {\n return startSpan(\n {\n op: 'function.step.do',\n name,\n scope: scopeForStep,\n attributes: {\n 'cloudflare.workflow.timeout': config?.timeout,\n 'cloudflare.workflow.retries.backoff': config?.retries?.backoff,\n 'cloudflare.workflow.retries.delay': config?.retries?.delay,\n 'cloudflare.workflow.retries.limit': config?.retries?.limit,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.workflow',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task',\n },\n },\n async span => {\n try {\n const result = await userCallback();\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n captureException(error, { mechanism: { handled: true, type: 'auto.faas.cloudflare.workflow' } });\n throw error;\n } finally {\n this._ctx.waitUntil(flush(2000));\n }\n },\n );\n };\n\n return config ? this._step.do(name, config, instrumentedCallback) : this._step.do(name, instrumentedCallback);\n }\n\n public async sleep(name: string, duration: WorkflowSleepDuration): Promise<void> {\n return this._step.sleep(name, duration);\n }\n\n public async sleepUntil(name: string, timestamp: Date | number): Promise<void> {\n return this._step.sleepUntil(name, timestamp);\n }\n\n public async waitForEvent<T extends Rpc.Serializable<T>>(\n name: string,\n options: { type: string; timeout?: WorkflowTimeoutDuration | number },\n ): Promise<WorkflowStepEvent<T>> {\n return this._step.waitForEvent<T>(name, options);\n }\n}\n\n/**\n * Instruments a Cloudflare Workflow class with Sentry.\n *\n * @example\n * ```typescript\n * const InstrumentedWorkflow = instrumentWorkflowWithSentry(\n * (env) => ({ dsn: env.SENTRY_DSN }),\n * MyWorkflowClass\n * );\n *\n * export default InstrumentedWorkflow;\n * ```\n *\n * @param optionsCallback - Function that returns Sentry options to initialize Sentry\n * @param WorkflowClass - The workflow class to instrument\n * @returns Instrumented workflow class with the same interface\n */\nexport function instrumentWorkflowWithSentry<\n E, // Environment type\n P, // Payload type\n T extends WorkflowEntrypoint<E, P>, // WorkflowEntrypoint type\n C extends new (ctx: ExecutionContext, env: E) => T, // Constructor type of the WorkflowEntrypoint class\n>(optionsCallback: (env: E) => CloudflareOptions, WorkFlowClass: C): C {\n return new Proxy(WorkFlowClass, {\n construct(target: C, args: [ctx: ExecutionContext, env: E], newTarget) {\n const [ctx, env] = args;\n const context = copyExecutionContext(ctx);\n args[0] = context;\n\n const options = optionsCallback(env);\n const instance = Reflect.construct(target, args, newTarget) as T;\n return new Proxy(instance, {\n get(obj, prop, receiver) {\n if (prop === 'run') {\n return async function (event: WorkflowEvent<P>, step: WorkflowStep): Promise<unknown> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withIsolationScope(async isolationScope => {\n const client = init({ ...options, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = await propagationContextFromInstanceId(event.instanceId);\n scope.setPropagationContext(propagationContext);\n\n try {\n return await obj.run.call(\n obj,\n event,\n new WrappedWorkflowStep(event.instanceId, context, options, step),\n );\n } finally {\n context.waitUntil(flush(2000));\n }\n });\n });\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflows.js","sources":["../../src/workflows.ts"],"sourcesContent":["import type { PropagationContext } from '@sentry/core';\nimport {\n captureException,\n flush,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type {\n WorkflowEntrypoint,\n WorkflowEvent,\n WorkflowSleepDuration,\n WorkflowStep,\n WorkflowStepConfig,\n WorkflowStepEvent,\n WorkflowTimeoutDuration,\n} from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\nimport { instrumentContext } from './utils/instrumentContext';\n\nconst UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;\n\n/**\n * Hashes a string to a UUID using SHA-1.\n */\nexport async function deterministicTraceIdFromInstanceId(instanceId: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(instanceId));\n return (\n Array.from(new Uint8Array(buf))\n // We only need the first 16 bytes for the 32 characters\n .slice(0, 16)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n );\n}\n\nasync function propagationContextFromInstanceId(instanceId: string): Promise<PropagationContext> {\n const traceId = UUID_REGEX.test(instanceId)\n ? instanceId.replace(/-/g, '')\n : await deterministicTraceIdFromInstanceId(instanceId);\n\n // Derive sampleRand from last 4 characters of the random UUID\n //\n // We cannot store any state between workflow steps, so we derive the\n // sampleRand from the traceId itself. This ensures that the sampling is\n // consistent across all steps in the same workflow instance.\n const sampleRand = parseInt(traceId.slice(-4), 16) / 0xffff;\n\n return {\n traceId,\n sampleRand,\n };\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _ctx: ExecutionContext,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: () => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ): Promise<T> {\n // Capture the current scope, so parent span (e.g., a startSpan surrounding step.do) is preserved\n const scopeForStep = getCurrentScope();\n\n const userCallback = (maybeCallback || configOrCallback) as () => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\n\n const instrumentedCallback: () => Promise<T> = async () => {\n return startSpan(\n {\n op: 'function.step.do',\n name,\n scope: scopeForStep,\n attributes: {\n 'cloudflare.workflow.timeout': config?.timeout,\n 'cloudflare.workflow.retries.backoff': config?.retries?.backoff,\n 'cloudflare.workflow.retries.delay': config?.retries?.delay,\n 'cloudflare.workflow.retries.limit': config?.retries?.limit,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.workflow',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task',\n },\n },\n async span => {\n try {\n const result = await userCallback();\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n captureException(error, { mechanism: { handled: true, type: 'auto.faas.cloudflare.workflow' } });\n throw error;\n } finally {\n this._ctx.waitUntil(flush(2000));\n }\n },\n );\n };\n\n return config ? this._step.do(name, config, instrumentedCallback) : this._step.do(name, instrumentedCallback);\n }\n\n public async sleep(name: string, duration: WorkflowSleepDuration): Promise<void> {\n return this._step.sleep(name, duration);\n }\n\n public async sleepUntil(name: string, timestamp: Date | number): Promise<void> {\n return this._step.sleepUntil(name, timestamp);\n }\n\n public async waitForEvent<T extends Rpc.Serializable<T>>(\n name: string,\n options: { type: string; timeout?: WorkflowTimeoutDuration | number },\n ): Promise<WorkflowStepEvent<T>> {\n return this._step.waitForEvent<T>(name, options);\n }\n}\n\n/**\n * Instruments a Cloudflare Workflow class with Sentry.\n *\n * @example\n * ```typescript\n * const InstrumentedWorkflow = instrumentWorkflowWithSentry(\n * (env) => ({ dsn: env.SENTRY_DSN }),\n * MyWorkflowClass\n * );\n *\n * export default InstrumentedWorkflow;\n * ```\n *\n * @param optionsCallback - Function that returns Sentry options to initialize Sentry\n * @param WorkflowClass - The workflow class to instrument\n * @returns Instrumented workflow class with the same interface\n */\nexport function instrumentWorkflowWithSentry<\n E, // Environment type\n P, // Payload type\n T extends WorkflowEntrypoint<E, P>, // WorkflowEntrypoint type\n C extends new (ctx: ExecutionContext, env: E) => T, // Constructor type of the WorkflowEntrypoint class\n>(optionsCallback: (env: E) => CloudflareOptions, WorkFlowClass: C): C {\n return new Proxy(WorkFlowClass, {\n construct(target: C, args: [ctx: ExecutionContext, env: E], newTarget) {\n const [ctx, env] = args;\n const context = instrumentContext(ctx);\n args[0] = context;\n\n const options = optionsCallback(env);\n const instance = Reflect.construct(target, args, newTarget) as T;\n return new Proxy(instance, {\n get(obj, prop, receiver) {\n if (prop === 'run') {\n return async function (event: WorkflowEvent<P>, step: WorkflowStep): Promise<unknown> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withIsolationScope(async isolationScope => {\n const client = init({ ...options, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = await propagationContextFromInstanceId(event.instanceId);\n scope.setPropagationContext(propagationContext);\n\n try {\n return await obj.run.call(\n obj,\n event,\n new WrappedWorkflowStep(event.instanceId, context, options, step),\n );\n } finally {\n context.waitUntil(flush(2000));\n }\n });\n });\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { getClient, withScope, withIsolationScope, isThenable, flush, captureException, SEMANTIC_ATTRIBUTE_SENTRY_OP, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
|
|
2
|
+
import { isInstrumented, markAsInstrumented } from './instrument.js';
|
|
3
|
+
import { init } from './sdk.js';
|
|
4
|
+
|
|
5
|
+
/** Extended DurableObjectState with originalStorage exposed by instrumentContext */
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Wraps a method with Sentry tracing.
|
|
9
|
+
*
|
|
10
|
+
* @param wrapperOptions - The options for the wrapper.
|
|
11
|
+
* @param handler - The method to wrap.
|
|
12
|
+
* @param callback - The callback to call.
|
|
13
|
+
* @param noMark - Whether to mark the method as instrumented.
|
|
14
|
+
* @returns The wrapped method.
|
|
15
|
+
*/
|
|
16
|
+
function wrapMethodWithSentry(
|
|
17
|
+
wrapperOptions,
|
|
18
|
+
handler,
|
|
19
|
+
callback,
|
|
20
|
+
noMark,
|
|
21
|
+
) {
|
|
22
|
+
if (isInstrumented(handler)) {
|
|
23
|
+
return handler;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!noMark) {
|
|
27
|
+
markAsInstrumented(handler);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return new Proxy(handler, {
|
|
31
|
+
apply(target, thisArg, args) {
|
|
32
|
+
const currentClient = getClient();
|
|
33
|
+
// if a client is already set, use withScope, otherwise use withIsolationScope
|
|
34
|
+
const sentryWithScope = currentClient ? withScope : withIsolationScope;
|
|
35
|
+
|
|
36
|
+
const wrappedFunction = (scope) => {
|
|
37
|
+
// In certain situations, the passed context can become undefined.
|
|
38
|
+
// For example, for Astro while prerendering pages at build time.
|
|
39
|
+
// see: https://github.com/getsentry/sentry-javascript/issues/13217
|
|
40
|
+
const context = wrapperOptions.context ;
|
|
41
|
+
|
|
42
|
+
const waitUntil = context?.waitUntil?.bind?.(context);
|
|
43
|
+
|
|
44
|
+
const currentClient = scope.getClient();
|
|
45
|
+
if (!currentClient) {
|
|
46
|
+
const client = init({ ...wrapperOptions.options, ctx: context });
|
|
47
|
+
scope.setClient(client);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!wrapperOptions.spanName) {
|
|
51
|
+
try {
|
|
52
|
+
if (callback) {
|
|
53
|
+
callback(...args);
|
|
54
|
+
}
|
|
55
|
+
const result = Reflect.apply(target, thisArg, args);
|
|
56
|
+
|
|
57
|
+
if (isThenable(result)) {
|
|
58
|
+
return result.then(
|
|
59
|
+
(res) => {
|
|
60
|
+
waitUntil?.(flush(2000));
|
|
61
|
+
return res;
|
|
62
|
+
},
|
|
63
|
+
(e) => {
|
|
64
|
+
captureException(e, {
|
|
65
|
+
mechanism: {
|
|
66
|
+
type: 'auto.faas.cloudflare.durable_object',
|
|
67
|
+
handled: false,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
waitUntil?.(flush(2000));
|
|
71
|
+
throw e;
|
|
72
|
+
},
|
|
73
|
+
);
|
|
74
|
+
} else {
|
|
75
|
+
waitUntil?.(flush(2000));
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
captureException(e, {
|
|
80
|
+
mechanism: {
|
|
81
|
+
type: 'auto.faas.cloudflare.durable_object',
|
|
82
|
+
handled: false,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
waitUntil?.(flush(2000));
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const attributes = wrapperOptions.spanOp
|
|
91
|
+
? {
|
|
92
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,
|
|
93
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',
|
|
94
|
+
}
|
|
95
|
+
: {};
|
|
96
|
+
|
|
97
|
+
return startSpan({ name: wrapperOptions.spanName, attributes }, () => {
|
|
98
|
+
try {
|
|
99
|
+
const result = Reflect.apply(target, thisArg, args);
|
|
100
|
+
|
|
101
|
+
if (isThenable(result)) {
|
|
102
|
+
return result.then(
|
|
103
|
+
(res) => {
|
|
104
|
+
waitUntil?.(flush(2000));
|
|
105
|
+
return res;
|
|
106
|
+
},
|
|
107
|
+
(e) => {
|
|
108
|
+
captureException(e, {
|
|
109
|
+
mechanism: {
|
|
110
|
+
type: 'auto.faas.cloudflare.durable_object',
|
|
111
|
+
handled: false,
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
waitUntil?.(flush(2000));
|
|
115
|
+
throw e;
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
} else {
|
|
119
|
+
waitUntil?.(flush(2000));
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
} catch (e) {
|
|
123
|
+
captureException(e, {
|
|
124
|
+
mechanism: {
|
|
125
|
+
type: 'auto.faas.cloudflare.durable_object',
|
|
126
|
+
handled: false,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
waitUntil?.(flush(2000));
|
|
130
|
+
throw e;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return sentryWithScope(wrappedFunction);
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export { wrapMethodWithSentry };
|
|
141
|
+
//# sourceMappingURL=wrapMethodWithSentry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapMethodWithSentry.js","sources":["../../src/wrapMethodWithSentry.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport {\n captureException,\n flush,\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 { isInstrumented, markAsInstrumented } from './instrument';\nimport { init } from './sdk';\n\n/** Extended DurableObjectState with originalStorage exposed by instrumentContext */\ninterface InstrumentedDurableObjectState extends DurableObjectState {\n originalStorage?: DurableObjectStorage;\n}\n\ntype MethodWrapperOptions = {\n spanName?: string;\n spanOp?: string;\n options: CloudflareOptions;\n context: ExecutionContext | DurableObjectState;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type UncheckedMethod = (...args: any[]) => any;\ntype OriginalMethod = UncheckedMethod;\n\n/**\n * Wraps a method with Sentry tracing.\n *\n * @param wrapperOptions - The options for the wrapper.\n * @param handler - The method to wrap.\n * @param callback - The callback to call.\n * @param noMark - Whether to mark the method as instrumented.\n * @returns The wrapped method.\n */\nexport function wrapMethodWithSentry<T extends OriginalMethod>(\n wrapperOptions: MethodWrapperOptions,\n handler: T,\n callback?: (...args: Parameters<T>) => void,\n noMark?: true,\n): T {\n if (isInstrumented(handler)) {\n return handler;\n }\n\n if (!noMark) {\n markAsInstrumented(handler);\n }\n\n return new Proxy(handler, {\n apply(target, thisArg, args: Parameters<T>) {\n const currentClient = getClient();\n // if a client is already set, use withScope, otherwise use withIsolationScope\n const sentryWithScope = currentClient ? withScope : withIsolationScope;\n\n const wrappedFunction = (scope: Scope): unknown => {\n // In certain situations, the passed context can become undefined.\n // For example, for Astro while prerendering pages at build time.\n // see: https://github.com/getsentry/sentry-javascript/issues/13217\n const context = wrapperOptions.context as InstrumentedDurableObjectState | undefined;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const currentClient = scope.getClient();\n if (!currentClient) {\n const client = init({ ...wrapperOptions.options, ctx: context as unknown as ExecutionContext | undefined });\n scope.setClient(client);\n }\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?.(flush(2000));\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?.(flush(2000));\n throw e;\n },\n );\n } else {\n waitUntil?.(flush(2000));\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?.(flush(2000));\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?.(flush(2000));\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?.(flush(2000));\n throw e;\n },\n );\n } else {\n waitUntil?.(flush(2000));\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?.(flush(2000));\n throw e;\n }\n });\n };\n\n return sentryWithScope(wrappedFunction);\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"durableobject.d.ts","sourceRoot":"","sources":["../../src/durableobject.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"durableobject.d.ts","sourceRoot":"","sources":["../../src/durableobject.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAQlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,iCAAiC,CAC/C,CAAC,EACD,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,EAC1B,CAAC,SAAS,KAAK,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EACtD,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,CAAC,GAAG,CAAC,CAyG1E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DurableObjectStorage } from '@cloudflare/workers-types';
|
|
2
|
+
/**
|
|
3
|
+
* Instruments DurableObjectStorage methods with Sentry spans.
|
|
4
|
+
*
|
|
5
|
+
* Wraps the following async methods:
|
|
6
|
+
* - get, put, delete, list (KV API)
|
|
7
|
+
*
|
|
8
|
+
* @param storage - The DurableObjectStorage instance to instrument
|
|
9
|
+
* @returns An instrumented DurableObjectStorage instance
|
|
10
|
+
*/
|
|
11
|
+
export declare function instrumentDurableObjectStorage(storage: DurableObjectStorage): DurableObjectStorage;
|
|
12
|
+
//# sourceMappingURL=instrumentDurableObjectStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentDurableObjectStorage.d.ts","sourceRoot":"","sources":["../../../src/instrumentations/instrumentDurableObjectStorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAOtE;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,oBAAoB,GAAG,oBAAoB,CAiClG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DurableObjectState, type ExecutionContext } from '@cloudflare/workers-types';
|
|
2
|
+
type ContextType = ExecutionContext | DurableObjectState;
|
|
3
|
+
/**
|
|
4
|
+
* Instruments an execution context or DurableObjectState with Sentry tracing.
|
|
5
|
+
*
|
|
6
|
+
* Creates a copy of the context that:
|
|
7
|
+
* - Allows overriding of methods (e.g., waitUntil)
|
|
8
|
+
* - For DurableObjectState: instruments storage operations (get, put, delete, list, etc.)
|
|
9
|
+
* to create Sentry spans automatically
|
|
10
|
+
*
|
|
11
|
+
* @param ctx - The execution context or DurableObjectState to instrument
|
|
12
|
+
* @returns An instrumented copy of the context
|
|
13
|
+
*/
|
|
14
|
+
export declare function instrumentContext<T extends ContextType>(ctx: T): T;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=instrumentContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentContext.d.ts","sourceRoot":"","sources":["../../../src/utils/instrumentContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAA6B,KAAK,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAGtH,KAAK,WAAW,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAGzD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CA+ClE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CloudflareOptions } from './client';
|
|
2
|
+
type MethodWrapperOptions = {
|
|
3
|
+
spanName?: string;
|
|
4
|
+
spanOp?: string;
|
|
5
|
+
options: CloudflareOptions;
|
|
6
|
+
context: ExecutionContext | DurableObjectState;
|
|
7
|
+
};
|
|
8
|
+
export type UncheckedMethod = (...args: any[]) => any;
|
|
9
|
+
type OriginalMethod = UncheckedMethod;
|
|
10
|
+
/**
|
|
11
|
+
* Wraps a method with Sentry tracing.
|
|
12
|
+
*
|
|
13
|
+
* @param wrapperOptions - The options for the wrapper.
|
|
14
|
+
* @param handler - The method to wrap.
|
|
15
|
+
* @param callback - The callback to call.
|
|
16
|
+
* @param noMark - Whether to mark the method as instrumented.
|
|
17
|
+
* @returns The wrapped method.
|
|
18
|
+
*/
|
|
19
|
+
export declare function wrapMethodWithSentry<T extends OriginalMethod>(wrapperOptions: MethodWrapperOptions, handler: T, callback?: (...args: Parameters<T>) => void, noMark?: true): T;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=wrapMethodWithSentry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapMethodWithSentry.d.ts","sourceRoot":"","sources":["../../src/wrapMethodWithSentry.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AASlD,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,gBAAgB,GAAG,kBAAkB,CAAC;CAChD,CAAC;AAGF,MAAM,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC;AACtD,KAAK,cAAc,GAAG,eAAe,CAAC;AAEtC;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,cAAc,EAC3D,cAAc,EAAE,oBAAoB,EACpC,OAAO,EAAE,CAAC,EACV,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,EAC3C,MAAM,CAAC,EAAE,IAAI,GACZ,CAAC,CAqHH"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DurableObjectStorage } from '@cloudflare/workers-types';
|
|
2
|
+
/**
|
|
3
|
+
* Instruments DurableObjectStorage methods with Sentry spans.
|
|
4
|
+
*
|
|
5
|
+
* Wraps the following async methods:
|
|
6
|
+
* - get, put, delete, list (KV API)
|
|
7
|
+
*
|
|
8
|
+
* @param storage - The DurableObjectStorage instance to instrument
|
|
9
|
+
* @returns An instrumented DurableObjectStorage instance
|
|
10
|
+
*/
|
|
11
|
+
export declare function instrumentDurableObjectStorage(storage: DurableObjectStorage): DurableObjectStorage;
|
|
12
|
+
//# sourceMappingURL=instrumentDurableObjectStorage.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DurableObjectState, ExecutionContext } from '@cloudflare/workers-types';
|
|
2
|
+
type ContextType = ExecutionContext | DurableObjectState;
|
|
3
|
+
/**
|
|
4
|
+
* Instruments an execution context or DurableObjectState with Sentry tracing.
|
|
5
|
+
*
|
|
6
|
+
* Creates a copy of the context that:
|
|
7
|
+
* - Allows overriding of methods (e.g., waitUntil)
|
|
8
|
+
* - For DurableObjectState: instruments storage operations (get, put, delete, list, etc.)
|
|
9
|
+
* to create Sentry spans automatically
|
|
10
|
+
*
|
|
11
|
+
* @param ctx - The execution context or DurableObjectState to instrument
|
|
12
|
+
* @returns An instrumented copy of the context
|
|
13
|
+
*/
|
|
14
|
+
export declare function instrumentContext<T extends ContextType>(ctx: T): T;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=instrumentContext.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CloudflareOptions } from './client';
|
|
2
|
+
type MethodWrapperOptions = {
|
|
3
|
+
spanName?: string;
|
|
4
|
+
spanOp?: string;
|
|
5
|
+
options: CloudflareOptions;
|
|
6
|
+
context: ExecutionContext | DurableObjectState;
|
|
7
|
+
};
|
|
8
|
+
export type UncheckedMethod = (...args: any[]) => any;
|
|
9
|
+
type OriginalMethod = UncheckedMethod;
|
|
10
|
+
/**
|
|
11
|
+
* Wraps a method with Sentry tracing.
|
|
12
|
+
*
|
|
13
|
+
* @param wrapperOptions - The options for the wrapper.
|
|
14
|
+
* @param handler - The method to wrap.
|
|
15
|
+
* @param callback - The callback to call.
|
|
16
|
+
* @param noMark - Whether to mark the method as instrumented.
|
|
17
|
+
* @returns The wrapped method.
|
|
18
|
+
*/
|
|
19
|
+
export declare function wrapMethodWithSentry<T extends OriginalMethod>(wrapperOptions: MethodWrapperOptions, handler: T, callback?: (...args: Parameters<T>) => void, noMark?: true): T;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=wrapMethodWithSentry.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/cloudflare",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.41.0-beta.0",
|
|
4
4
|
"description": "Official Sentry SDK for Cloudflare Workers and Pages",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/cloudflare",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@opentelemetry/api": "^1.9.0",
|
|
53
|
-
"@sentry/core": "10.
|
|
53
|
+
"@sentry/core": "10.41.0-beta.0"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"@cloudflare/workers-types": "^4.x"
|
|
@@ -72,10 +72,9 @@
|
|
|
72
72
|
"build:types": "run-s build:types:core build:types:downlevel",
|
|
73
73
|
"build:types:core": "tsc -p tsconfig.types.json",
|
|
74
74
|
"build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8",
|
|
75
|
-
"build:watch": "run-p build:transpile:watch
|
|
75
|
+
"build:watch": "run-p build:transpile:watch",
|
|
76
76
|
"build:dev:watch": "yarn build:watch",
|
|
77
77
|
"build:transpile:watch": "rollup -c rollup.npm.config.mjs --watch",
|
|
78
|
-
"build:types:watch": "tsc -p tsconfig.types.json --watch",
|
|
79
78
|
"build:tarball": "npm pack",
|
|
80
79
|
"circularDepCheck": "madge --circular src/index.ts",
|
|
81
80
|
"clean": "rimraf build coverage sentry-cloudflare-*.tgz",
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Creates a new copy of the given execution context, optionally overriding methods.
|
|
5
|
-
*
|
|
6
|
-
* @param {ContextType|void} ctx - The execution context to be copied. Can be of type `ContextType` or `void`.
|
|
7
|
-
* @return {ContextType|void} A new execution context with the same properties and overridden methods if applicable.
|
|
8
|
-
*/
|
|
9
|
-
function copyExecutionContext(ctx) {
|
|
10
|
-
if (!ctx) return ctx;
|
|
11
|
-
|
|
12
|
-
const overrides = new Map();
|
|
13
|
-
const contextPrototype = Object.getPrototypeOf(ctx);
|
|
14
|
-
const prototypeMethodNames = Object.getOwnPropertyNames(contextPrototype) ;
|
|
15
|
-
const ownPropertyNames = Object.getOwnPropertyNames(ctx) ;
|
|
16
|
-
const instrumented = new Set(['constructor']);
|
|
17
|
-
const descriptors = [...ownPropertyNames, ...prototypeMethodNames].reduce((prevDescriptors, methodName) => {
|
|
18
|
-
if (instrumented.has(methodName)) return prevDescriptors;
|
|
19
|
-
if (typeof ctx[methodName] !== 'function') return prevDescriptors;
|
|
20
|
-
instrumented.add(methodName);
|
|
21
|
-
const overridableDescriptor = makeOverridableDescriptor(overrides, ctx, methodName);
|
|
22
|
-
return {
|
|
23
|
-
...prevDescriptors,
|
|
24
|
-
[methodName]: overridableDescriptor,
|
|
25
|
-
};
|
|
26
|
-
}, {});
|
|
27
|
-
|
|
28
|
-
return Object.create(ctx, descriptors);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Creates a property descriptor that allows overriding of a method on the given context object.
|
|
33
|
-
*
|
|
34
|
-
* This descriptor supports property overriding with functions only. It delegates method calls to
|
|
35
|
-
* the provided store if an override exists or to the original method on the context otherwise.
|
|
36
|
-
*
|
|
37
|
-
* @param {OverridesStore<ContextType>} store - The storage for overridden methods specific to the context type.
|
|
38
|
-
* @param {ContextType} ctx - The context object that contains the method to be overridden.
|
|
39
|
-
* @param {keyof ContextType} method - The method on the context object to create the overridable descriptor for.
|
|
40
|
-
* @return {PropertyDescriptor} A property descriptor enabling the overriding of the specified method.
|
|
41
|
-
*/
|
|
42
|
-
function makeOverridableDescriptor(
|
|
43
|
-
store,
|
|
44
|
-
ctx,
|
|
45
|
-
method,
|
|
46
|
-
) {
|
|
47
|
-
return {
|
|
48
|
-
configurable: true,
|
|
49
|
-
enumerable: true,
|
|
50
|
-
set: newValue => {
|
|
51
|
-
if (typeof newValue == 'function') {
|
|
52
|
-
store.set(method, newValue);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
Reflect.set(ctx, method, newValue);
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
get: () => {
|
|
59
|
-
if (store.has(method)) return store.get(method);
|
|
60
|
-
const methodFunction = Reflect.get(ctx, method);
|
|
61
|
-
if (typeof methodFunction !== 'function') return methodFunction;
|
|
62
|
-
// We should do bind() to make sure that the method is bound to the context object - otherwise it will not work
|
|
63
|
-
return methodFunction.bind(ctx);
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
exports.copyExecutionContext = copyExecutionContext;
|
|
69
|
-
//# sourceMappingURL=copyExecutionContext.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"copyExecutionContext.js","sources":["../../../src/utils/copyExecutionContext.ts"],"sourcesContent":["import { type DurableObjectState, type ExecutionContext } from '@cloudflare/workers-types';\n\ntype ContextType = ExecutionContext | DurableObjectState;\ntype OverridesStore<T extends ContextType> = Map<keyof T, (...args: unknown[]) => unknown>;\n\n/**\n * Creates a new copy of the given execution context, optionally overriding methods.\n *\n * @param {ContextType|void} ctx - The execution context to be copied. Can be of type `ContextType` or `void`.\n * @return {ContextType|void} A new execution context with the same properties and overridden methods if applicable.\n */\nexport function copyExecutionContext<T extends ContextType>(ctx: T): T {\n if (!ctx) return ctx;\n\n const overrides: OverridesStore<T> = new Map();\n const contextPrototype = Object.getPrototypeOf(ctx);\n const prototypeMethodNames = Object.getOwnPropertyNames(contextPrototype) as unknown as (keyof T)[];\n const ownPropertyNames = Object.getOwnPropertyNames(ctx) as unknown as (keyof T)[];\n const instrumented = new Set<unknown>(['constructor']);\n const descriptors = [...ownPropertyNames, ...prototypeMethodNames].reduce((prevDescriptors, methodName) => {\n if (instrumented.has(methodName)) return prevDescriptors;\n if (typeof ctx[methodName] !== 'function') return prevDescriptors;\n instrumented.add(methodName);\n const overridableDescriptor = makeOverridableDescriptor(overrides, ctx, methodName);\n return {\n ...prevDescriptors,\n [methodName]: overridableDescriptor,\n };\n }, {});\n\n return Object.create(ctx, descriptors);\n}\n\n/**\n * Creates a property descriptor that allows overriding of a method on the given context object.\n *\n * This descriptor supports property overriding with functions only. It delegates method calls to\n * the provided store if an override exists or to the original method on the context otherwise.\n *\n * @param {OverridesStore<ContextType>} store - The storage for overridden methods specific to the context type.\n * @param {ContextType} ctx - The context object that contains the method to be overridden.\n * @param {keyof ContextType} method - The method on the context object to create the overridable descriptor for.\n * @return {PropertyDescriptor} A property descriptor enabling the overriding of the specified method.\n */\nfunction makeOverridableDescriptor<T extends ContextType>(\n store: OverridesStore<T>,\n ctx: T,\n method: keyof T,\n): PropertyDescriptor {\n return {\n configurable: true,\n enumerable: true,\n set: newValue => {\n if (typeof newValue == 'function') {\n store.set(method, newValue);\n return;\n }\n Reflect.set(ctx, method, newValue);\n },\n\n get: () => {\n if (store.has(method)) return store.get(method);\n const methodFunction = Reflect.get(ctx, method);\n if (typeof methodFunction !== 'function') return methodFunction;\n // We should do bind() to make sure that the method is bound to the context object - otherwise it will not work\n return methodFunction.bind(ctx);\n },\n };\n}\n"],"names":[],"mappings":";;AAKA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAwB,GAAG,EAAQ;AACvE,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG;;AAEtB,EAAE,MAAM,SAAS,GAAsB,IAAI,GAAG,EAAE;AAChD,EAAE,MAAM,mBAAmB,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC;AACrD,EAAE,MAAM,uBAAuB,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,CAAA;AAC1E,EAAE,MAAM,mBAAmB,MAAM,CAAC,mBAAmB,CAAC,GAAG,CAAA;AACzD,EAAE,MAAM,eAAe,IAAI,GAAG,CAAU,CAAC,aAAa,CAAC,CAAC;AACxD,EAAE,MAAM,WAAA,GAAc,CAAC,GAAG,gBAAgB,EAAE,GAAG,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,UAAU,KAAK;AAC7G,IAAI,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,eAAe;AAC5D,IAAI,IAAI,OAAO,GAAG,CAAC,UAAU,CAAA,KAAM,UAAU,EAAE,OAAO,eAAe;AACrE,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;AAChC,IAAI,MAAM,qBAAA,GAAwB,yBAAyB,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC;AACvF,IAAI,OAAO;AACX,MAAM,GAAG,eAAe;AACxB,MAAM,CAAC,UAAU,GAAG,qBAAqB;AACzC,KAAK;AACL,EAAE,CAAC,EAAE,EAAE,CAAC;;AAER,EAAE,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC;AACxC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,yBAAyB;AAClC,EAAE,KAAK;AACP,EAAE,GAAG;AACL,EAAE,MAAM;AACR,EAAsB;AACtB,EAAE,OAAO;AACT,IAAI,YAAY,EAAE,IAAI;AACtB,IAAI,UAAU,EAAE,IAAI;AACpB,IAAI,GAAG,EAAE,QAAA,IAAY;AACrB,MAAM,IAAI,OAAO,QAAA,IAAY,UAAU,EAAE;AACzC,QAAQ,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC;AACnC,QAAQ;AACR,MAAM;AACN,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC;AACxC,IAAI,CAAC;;AAEL,IAAI,GAAG,EAAE,MAAM;AACf,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC;AACrD,MAAM,MAAM,cAAA,GAAiB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC;AACrD,MAAM,IAAI,OAAO,cAAA,KAAmB,UAAU,EAAE,OAAO,cAAc;AACrE;AACA,MAAM,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC;AACrC,IAAI,CAAC;AACL,GAAG;AACH;;;;"}
|