import { isObjectLike, getIsolationScope, getDefaultIsolationScope, startNewTrace } from '@sentry/core'; import { setAsyncLocalStorageAsyncContextStrategy } from './async.js'; import { markAsInstrumented, getInstrumented } from './instrument.js'; import { instrumentDurableObjectHandlers } from './instrumentations/instrumentDurableObjectHandlers.js'; import { instrumentEnv } from './instrumentations/worker/instrumentEnv.js'; import { getFinalOptions } from './options.js'; import { instrumentContext } from './utils/instrumentContext.js'; import { hasRpcMeta } from './utils/rpcMeta.js'; import { getEffectiveRpcPropagation } from './utils/rpcOptions.js'; import { instrumentCloudflareAgent } from './instrumentations/agents/index.js'; import { wrapMethodWithSentry } from './wrapMethodWithSentry.js'; function constructInstrumentedDurableObject(target, ctx, env, newTarget, optionsCallback) { setAsyncLocalStorageAsyncContextStrategy(); const options = getFinalOptions(optionsCallback(env), env); const context = instrumentContext(ctx); const instrumentedEnv = instrumentEnv(env, options); const prototype = newTarget.prototype ?? target.prototype; const cachedFrameworkManagedMethods = frameworkManagedMethodsCache.get(prototype); const methodsBeforeConstruction = cachedFrameworkManagedMethods ? void 0 : resolvePrototypeMethods(prototype); const obj = Reflect.construct(target, [context, instrumentedEnv], newTarget); const frameworkManagedMethods = resolveFrameworkManagedMethods( prototype, obj, methodsBeforeConstruction, cachedFrameworkManagedMethods ); instrumentDurableObjectHandlers(obj, options, context); return { obj, options, context, frameworkManagedMethods }; } const frameworkManagedMethodsCache = /* @__PURE__ */ new WeakMap(); function resolvePrototypeMethods(prototype) { const methods = /* @__PURE__ */ new Map(); for (let current = prototype; current && current !== Object.prototype; current = Object.getPrototypeOf(current)) { for (const name of Object.getOwnPropertyNames(current)) { if (name === "constructor" || methods.has(name)) { continue; } const descriptor = Object.getOwnPropertyDescriptor(current, name); if (descriptor && typeof descriptor.value === "function") { methods.set(name, descriptor.value); } } } return methods; } function resolveFrameworkManagedMethods(prototype, obj, methodsBeforeConstruction, cached) { if (cached) { return cached; } const methodsAfterConstruction = resolvePrototypeMethods(Object.getPrototypeOf(obj)); const managed = /* @__PURE__ */ new Set(); for (const [name, method] of methodsAfterConstruction) { const before = methodsBeforeConstruction?.get(name); if (before && before !== method) { managed.add(name); } } frameworkManagedMethodsCache.set(prototype, managed); return managed; } const RESERVED_RPC_METHOD_NAMES = /* @__PURE__ */ new Set([ "constructor", "fetch", "connect", "alarm", "webSocketMessage", "webSocketClose", "webSocketError", "dup" ]); const rpcInstanceStates = /* @__PURE__ */ new WeakMap(); function finalizeWithRpcInstrumentation(obj, options, context, excludedMethods) { const rpcPropagation = getEffectiveRpcPropagation(options); if (!rpcPropagation) { return obj; } const allowedMethods = Array.isArray(options.instrumentPrototypeMethods) ? ( // eslint-disable-next-line typescript/no-deprecated new Set(options.instrumentPrototypeMethods) ) : void 0; const alwaysTrace = options.enableRpcTracePropagation === void 0; rpcInstanceStates.set(obj, { options, context, alwaysTrace }); instrumentPrototypeRpcMethods(obj, excludedMethods, allowedMethods); return obj; } function getRpcMethodDescriptor(obj, prototype, methodName, excludedMethods, allowedMethods) { if (RESERVED_RPC_METHOD_NAMES.has(methodName) || Object.prototype.hasOwnProperty.call(obj, methodName) || excludedMethods?.has(methodName) || allowedMethods && !allowedMethods.has(methodName)) { return void 0; } const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName); if (!descriptor || typeof descriptor.value !== "function" || getInstrumented(descriptor.value)) { return void 0; } return descriptor; } function instrumentPrototypeRpcMethods(obj, excludedMethods, allowedMethods) { let prototype = Object.getPrototypeOf(obj); while (prototype && prototype !== Object.prototype) { for (const methodName of Object.getOwnPropertyNames(prototype)) { const descriptor = getRpcMethodDescriptor(obj, prototype, methodName, excludedMethods, allowedMethods); if (!descriptor) { continue; } const wrapped = createRpcPrototypeWrapper(methodName, descriptor.value); try { Object.defineProperty(prototype, methodName, { ...descriptor, value: wrapped }); } catch { } markAsInstrumented(wrapped); } prototype = Object.getPrototypeOf(prototype); } } function getInstrumentedRpcMethod(state, methodName, originalMethod) { const instrumentedMethods = state.instrumentedMethods ?? (state.instrumentedMethods = /* @__PURE__ */ new Map()); let instrumented = instrumentedMethods.get(methodName); if (!instrumented) { instrumented = wrapMethodWithSentry( { options: state.options, context: state.context, spanName: state.alwaysTrace ? methodName : (rpcMeta) => rpcMeta ? methodName : void 0, spanOp: "rpc", origin: "auto.faas.cloudflare.durable_object" }, originalMethod, void 0, true ); instrumentedMethods.set(methodName, instrumented); } return instrumented; } function createRpcPrototypeWrapper(methodName, originalMethod) { const wrapper = function(...args) { const state = isObjectLike(this) ? rpcInstanceStates.get(this) : void 0; if (!state) { return Reflect.apply(originalMethod, this, args); } if (state.alwaysTrace || hasRpcMeta(args)) { return Reflect.apply(getInstrumentedRpcMethod(state, methodName, originalMethod), this, args); } if (getIsolationScope() !== getDefaultIsolationScope()) { return Reflect.apply(originalMethod, this, args); } const instrumented = getInstrumentedRpcMethod(state, methodName, originalMethod); return startNewTrace(() => Reflect.apply(instrumented, this, args)); }; Object.defineProperties(wrapper, { name: { value: originalMethod.name, configurable: true }, length: { value: originalMethod.length, configurable: true } }); return wrapper; } function instrumentDurableObjectWithSentry(optionsCallback, DurableObjectClass) { const InstrumentedClass = new Proxy(DurableObjectClass, { construct(target, [ctx, env], newTarget) { const { obj, options, context, frameworkManagedMethods } = constructInstrumentedDurableObject( target, ctx, env, newTarget, optionsCallback ); return finalizeWithRpcInstrumentation(obj, options, context, frameworkManagedMethods); } }); markAsInstrumented(InstrumentedClass); return InstrumentedClass; } function instrumentAgentWithSentry(optionsCallback, AgentClass) { const InstrumentedClass = new Proxy(AgentClass, { construct(target, [ctx, env], newTarget) { const { obj, options, context, frameworkManagedMethods } = constructInstrumentedDurableObject( target, ctx, env, newTarget, optionsCallback ); instrumentCloudflareAgent(obj); return finalizeWithRpcInstrumentation(obj, options, context, frameworkManagedMethods); } }); markAsInstrumented(InstrumentedClass); return InstrumentedClass; } export { constructInstrumentedDurableObject, finalizeWithRpcInstrumentation, instrumentAgentWithSentry, instrumentDurableObjectWithSentry }; //# sourceMappingURL=durableobject.js.map