{"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":["startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","storeSpanContext","isThenable"],"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,OAAOA,cAAS;AACxB,UAAU;AACV;AACA,YAAY,IAAI,EAAE,CAAC,uBAAuB,EAAE,UAAU,CAAC,CAAA;AACA,YAAA,EAAA,EAAA,IAAA;AACA,YAAA,UAAA,EAAA;AACA,cAAA,CAAAC,qCAAA,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,MAAAC,2BAAA,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,CAAAC,eAAA,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;;;;"}