@sentry/cloudflare 10.47.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 +42 -16
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/index.js +3 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrument.js +72 -8
- package/build/cjs/instrument.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/instrumentWorkerEntrypoint.js +101 -0
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -0
- package/build/cjs/instrumentations/worker/instrumentEmail.js +16 -13
- 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 +36 -10
- 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 +36 -10
- package/build/cjs/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentScheduled.js +36 -13
- package/build/cjs/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentTail.js +34 -10
- 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/request.js +5 -6
- package/build/cjs/request.js.map +1 -1
- package/build/cjs/scope-utils.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/isCloudflareClass.js +29 -0
- package/build/cjs/utils/isCloudflareClass.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/withSentry.js +31 -20
- package/build/cjs/withSentry.js.map +1 -1
- package/build/cjs/workflows.js +3 -2
- package/build/cjs/workflows.js.map +1 -1
- package/build/cjs/wrapMethodWithSentry.js +157 -112
- package/build/cjs/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/durableobject.js +43 -17
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/index.js +1 -1
- package/build/esm/instrument.js +71 -8
- package/build/esm/instrument.js.map +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/instrumentWorkerEntrypoint.js +99 -0
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -0
- package/build/esm/instrumentations/worker/instrumentEmail.js +17 -14
- 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 +37 -12
- 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 +37 -12
- package/build/esm/instrumentations/worker/instrumentQueue.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentScheduled.js +37 -15
- package/build/esm/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentTail.js +35 -12
- 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/request.js +5 -6
- package/build/esm/request.js.map +1 -1
- package/build/esm/scope-utils.js.map +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/isCloudflareClass.js +27 -0
- package/build/esm/utils/isCloudflareClass.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/withSentry.js +32 -21
- package/build/esm/withSentry.js.map +1 -1
- package/build/esm/workflows.js +3 -2
- package/build/esm/workflows.js.map +1 -1
- package/build/esm/wrapMethodWithSentry.js +159 -114
- 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/instrument.d.ts +15 -4
- package/build/types/instrument.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/instrumentWorkerEntrypoint.d.ts +42 -0
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts.map +1 -0
- package/build/types/instrumentations/worker/instrumentEmail.d.ts +2 -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 +6 -1
- 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 +6 -1
- package/build/types/instrumentations/worker/instrumentQueue.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentScheduled.d.ts +6 -1
- package/build/types/instrumentations/worker/instrumentScheduled.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentTail.d.ts +6 -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/request.d.ts +3 -3
- package/build/types/request.d.ts.map +1 -1
- package/build/types/scope-utils.d.ts +2 -2
- package/build/types/scope-utils.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/isCloudflareClass.d.ts +30 -0
- package/build/types/utils/isCloudflareClass.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/withSentry.d.ts +3 -2
- package/build/types/withSentry.d.ts.map +1 -1
- 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/instrument.d.ts +15 -4
- 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/instrumentWorkerEntrypoint.d.ts +42 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentEmail.d.ts +2 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentEnv.d.ts +16 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentFetch.d.ts +6 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentFetcher.d.ts +10 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentQueue.d.ts +6 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentScheduled.d.ts +6 -1
- package/build/types-ts3.8/instrumentations/worker/instrumentTail.d.ts +6 -1
- package/build/types-ts3.8/integrations/tracing/vercelai.d.ts +9 -1
- package/build/types-ts3.8/request.d.ts +3 -3
- package/build/types-ts3.8/scope-utils.d.ts +2 -2
- package/build/types-ts3.8/utils/isBinding.d.ts +49 -0
- package/build/types-ts3.8/utils/isCloudflareClass.d.ts +30 -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/withSentry.d.ts +3 -2
- package/build/types-ts3.8/wrapMethodWithSentry.d.ts +19 -2
- package/package.json +2 -2
|
@@ -4,9 +4,10 @@ const core = require('@sentry/core');
|
|
|
4
4
|
|
|
5
5
|
const INTEGRATION_NAME = 'VercelAI';
|
|
6
6
|
|
|
7
|
-
const _vercelAIIntegration = (() => {
|
|
7
|
+
const _vercelAIIntegration = ((options = {}) => {
|
|
8
8
|
return {
|
|
9
9
|
name: INTEGRATION_NAME,
|
|
10
|
+
options,
|
|
10
11
|
setup(client) {
|
|
11
12
|
core.addVercelAiProcessors(client);
|
|
12
13
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercelai.js","sources":["../../../../src/integrations/tracing/vercelai.ts"],"sourcesContent":["/**\n * This is a copy of the Vercel AI integration from the node SDK.\n *\n * The only difference is that it does not use `@opentelemetry/instrumentation`\n * because Cloudflare Workers do not support it.\n *\n * Therefore, we cannot automatically patch setting `experimental_telemetry: { isEnabled: true }`\n * and users have to manually set this to get spans.\n */\n\nimport type { IntegrationFn } from '@sentry/core';\nimport { addVercelAiProcessors, defineIntegration } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'VercelAI';\n\nconst _vercelAIIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n addVercelAiProcessors(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.\n * This integration is not enabled by default, you need to manually add it.\n *\n * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).\n *\n * You need to enable collecting spans for a specific call by setting\n * `experimental_telemetry.isEnabled` to `true` in the first argument of the function call.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true },\n * });\n * ```\n *\n * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each\n * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs`\n * to `true`.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },\n * });\n */\nexport const vercelAIIntegration = defineIntegration(_vercelAIIntegration);\n"],"names":["addVercelAiProcessors","defineIntegration"],"mappings":";;;;AAaA,MAAM,gBAAA,GAAmB,UAAU;;
|
|
1
|
+
{"version":3,"file":"vercelai.js","sources":["../../../../src/integrations/tracing/vercelai.ts"],"sourcesContent":["/**\n * This is a copy of the Vercel AI integration from the node SDK.\n *\n * The only difference is that it does not use `@opentelemetry/instrumentation`\n * because Cloudflare Workers do not support it.\n *\n * Therefore, we cannot automatically patch setting `experimental_telemetry: { isEnabled: true }`\n * and users have to manually set this to get spans.\n */\n\nimport type { IntegrationFn } from '@sentry/core';\nimport { addVercelAiProcessors, defineIntegration } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'VercelAI';\n\ninterface VercelAiOptions {\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n}\n\nconst _vercelAIIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n options,\n setup(client) {\n addVercelAiProcessors(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.\n * This integration is not enabled by default, you need to manually add it.\n *\n * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).\n *\n * You need to enable collecting spans for a specific call by setting\n * `experimental_telemetry.isEnabled` to `true` in the first argument of the function call.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true },\n * });\n * ```\n *\n * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each\n * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs`\n * to `true`.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },\n * });\n */\nexport const vercelAIIntegration = defineIntegration(_vercelAIIntegration);\n"],"names":["addVercelAiProcessors","defineIntegration"],"mappings":";;;;AAaA,MAAM,gBAAA,GAAmB,UAAU;;AAUnC,MAAM,oBAAA,IAAwB,CAAC,OAAO,GAAoB,EAAE,KAAK;AACjE,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B,IAAI,OAAO;AACX,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAMA,0BAAqB,CAAC,MAAM,CAAC;AACnC,IAAI,CAAC;AACL,GAAG;AACH,CAAC,CAAA;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACa,mBAAA,GAAsBC,sBAAiB,CAAC,oBAAoB;;;;"}
|
package/build/cjs/request.js
CHANGED
|
@@ -15,11 +15,7 @@ function wrapRequestHandler(
|
|
|
15
15
|
) {
|
|
16
16
|
return core.withIsolationScope(async isolationScope => {
|
|
17
17
|
const { options, request, captureErrors = true } = wrapperOptions;
|
|
18
|
-
|
|
19
|
-
// In certain situations, the passed context can become undefined.
|
|
20
|
-
// For example, for Astro while prerendering pages at build time.
|
|
21
|
-
// see: https://github.com/getsentry/sentry-javascript/issues/13217
|
|
22
|
-
const context = wrapperOptions.context ;
|
|
18
|
+
const context = wrapperOptions.context;
|
|
23
19
|
|
|
24
20
|
const waitUntil = context?.waitUntil?.bind?.(context);
|
|
25
21
|
|
|
@@ -53,7 +49,10 @@ function wrapRequestHandler(
|
|
|
53
49
|
scopeUtils.addRequest(isolationScope, request);
|
|
54
50
|
if (request.cf) {
|
|
55
51
|
scopeUtils.addCultureContext(isolationScope, request.cf);
|
|
56
|
-
|
|
52
|
+
|
|
53
|
+
if (typeof request.cf.httpProtocol === 'string') {
|
|
54
|
+
attributes['network.protocol.name'] = request.cf.httpProtocol;
|
|
55
|
+
}
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
// Do not capture spans for OPTIONS and HEAD requests
|
package/build/cjs/request.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown>>;\n context: ExecutionContext;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n\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 ExecutionContext | undefined;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n // Streaming response detected - monitor consumption to keep span alive\n try {\n const [clientStream, monitorStream] = res.body.tee();\n\n // Monitor stream consumption and end span when complete\n const streamMonitor = (async () => {\n const reader = monitorStream.getReader();\n\n try {\n let done = false;\n while (!done) {\n const result = await reader.read();\n done = result.done;\n }\n } catch {\n // Stream error or cancellation - will end span in finally\n } finally {\n reader.releaseLock();\n span.end();\n waitUntil?.(flushAndDispose(client));\n }\n })();\n\n // Keep worker alive until stream monitoring completes (otherwise span won't end)\n waitUntil?.(streamMonitor);\n\n // Return response with client stream\n return new Response(clientStream, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch (_e) {\n // tee() failed (e.g stream already locked) - fall back to non-streaming handling\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":["withIsolationScope","init","parseStringToURLObject","getHttpSpanDetailsFromUrlObject","httpHeadersToSpanAttributes","winterCGHeadersToDict","getClient","SEMANTIC_ATTRIBUTE_SENTRY_OP","addCloudResourceContext","addRequest","addCultureContext","captureException","flushAndDispose","continueTrace","startSpanManual","setHttpStatus","classifyResponseStreaming"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request.js","sources":["../../src/request.ts"],"sourcesContent":["import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport {\n captureException,\n continueTrace,\n getClient,\n getHttpSpanDetailsFromUrlObject,\n httpHeadersToSpanAttributes,\n parseStringToURLObject,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n setHttpStatus,\n startSpanManual,\n winterCGHeadersToDict,\n withIsolationScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';\nimport { init } from './sdk';\nimport { classifyResponseStreaming } from './utils/streaming';\n\ninterface RequestHandlerWrapperOptions {\n options: CloudflareOptions;\n request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;\n context: ExecutionContext | undefined;\n /**\n * If true, errors will be captured, rethrown and sent to Sentry.\n * Otherwise, errors are rethrown but not captured.\n *\n * You most likely don't want to set this to `false`, if you use `wrapRequestHandler` directly.\n * This is primarily meant as an escape hatch for higher-level SDKs relying on additional error\n * capturing mechanisms where this wrapper captures errors too early or too generally.\n *\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Wraps a cloudflare request handler in Sentry instrumentation\n */\nexport function wrapRequestHandler(\n wrapperOptions: RequestHandlerWrapperOptions,\n handler: (...args: unknown[]) => Response | Promise<Response>,\n): Promise<Response> {\n return withIsolationScope(async isolationScope => {\n const { options, request, captureErrors = true } = wrapperOptions;\n const context = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n const urlObject = parseStringToURLObject(request.url);\n const [name, attributes] = getHttpSpanDetailsFromUrlObject(urlObject, 'server', 'auto.http.cloudflare', request);\n\n const contentLength = request.headers.get('content-length');\n if (contentLength) {\n attributes['http.request.body.size'] = parseInt(contentLength, 10);\n }\n\n const userAgentHeader = request.headers.get('user-agent');\n if (userAgentHeader) {\n attributes['user_agent.original'] = userAgentHeader;\n }\n\n Object.assign(\n attributes,\n httpHeadersToSpanAttributes(\n winterCGHeadersToDict(request.headers),\n getClient()?.getOptions().sendDefaultPii ?? false,\n ),\n );\n\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = 'http.server';\n\n addCloudResourceContext(isolationScope);\n addRequest(isolationScope, request);\n if (request.cf) {\n addCultureContext(isolationScope, request.cf);\n\n if (typeof request.cf.httpProtocol === 'string') {\n attributes['network.protocol.name'] = request.cf.httpProtocol;\n }\n }\n\n // Do not capture spans for OPTIONS and HEAD requests\n if (request.method === 'OPTIONS' || request.method === 'HEAD') {\n try {\n return await handler();\n } catch (e) {\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n throw e;\n } finally {\n waitUntil?.(flushAndDispose(client));\n }\n }\n\n return continueTrace(\n { sentryTrace: request.headers.get('sentry-trace') || '', baggage: request.headers.get('baggage') },\n () => {\n // Note: This span will not have a duration unless I/O happens in the handler. This is\n // because of how the cloudflare workers runtime works.\n // See: https://developers.cloudflare.com/workers/runtime-apis/performance/\n\n // Use startSpanManual to control when span ends (needed for streaming responses)\n return startSpanManual({ name, attributes }, async span => {\n let res: Response;\n\n try {\n res = await handler();\n setHttpStatus(span, res.status);\n\n // After the handler runs, the span name might have been updated by nested instrumentation\n // (e.g., Remix parameterizing routes). The span should already have the correct name\n // from that instrumentation, so we don't need to do anything here.\n } catch (e) {\n span.end();\n if (captureErrors) {\n captureException(e, { mechanism: { handled: false, type: 'auto.http.cloudflare' } });\n }\n waitUntil?.(flushAndDispose(client));\n throw e;\n }\n\n // Classify response to detect actual streaming\n const classification = classifyResponseStreaming(res);\n\n if (classification.isStreaming && res.body) {\n // Streaming response detected - monitor consumption to keep span alive\n try {\n const [clientStream, monitorStream] = res.body.tee();\n\n // Monitor stream consumption and end span when complete\n const streamMonitor = (async () => {\n const reader = monitorStream.getReader();\n\n try {\n let done = false;\n while (!done) {\n const result = await reader.read();\n done = result.done;\n }\n } catch {\n // Stream error or cancellation - will end span in finally\n } finally {\n reader.releaseLock();\n span.end();\n waitUntil?.(flushAndDispose(client));\n }\n })();\n\n // Keep worker alive until stream monitoring completes (otherwise span won't end)\n waitUntil?.(streamMonitor);\n\n // Return response with client stream\n return new Response(clientStream, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n } catch (_e) {\n // tee() failed (e.g stream already locked) - fall back to non-streaming handling\n span.end();\n waitUntil?.(flushAndDispose(client));\n return res;\n }\n }\n\n // Non-streaming response - end span immediately and return original\n span.end();\n\n // Don't dispose for protocol upgrades (101 Switching Protocols) - the connection stays alive.\n // This includes WebSocket upgrades where webSocketMessage/webSocketClose handlers\n // will still be called and may need the client to capture errors.\n if (res.status === 101) {\n waitUntil?.(client?.flush(2000));\n } else {\n waitUntil?.(flushAndDispose(client));\n }\n return res;\n });\n },\n );\n });\n}\n"],"names":["withIsolationScope","init","parseStringToURLObject","getHttpSpanDetailsFromUrlObject","httpHeadersToSpanAttributes","winterCGHeadersToDict","getClient","SEMANTIC_ATTRIBUTE_SENTRY_OP","addCloudResourceContext","addRequest","addCultureContext","captureException","flushAndDispose","continueTrace","startSpanManual","setHttpStatus","classifyResponseStreaming"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-utils.js","sources":["../../src/scope-utils.ts"],"sourcesContent":["import type { IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport type { Scope } from '@sentry/core';\nimport { winterCGRequestToRequestData } from '@sentry/core';\n\n/**\n * Set cloud resource context on scope.\n */\nexport function addCloudResourceContext(scope: Scope): void {\n scope.setContext('cloud_resource', {\n 'cloud.provider': 'cloudflare',\n });\n}\n\n/**\n * Set culture context on scope\n */\nexport function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties): void {\n scope.setContext('culture', {\n timezone: cf.timezone,\n });\n}\n\n/**\n * Set request data on scope\n */\nexport function addRequest(scope: Scope, request: Request): void {\n scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });\n}\n"],"names":["winterCGRequestToRequestData"],"mappings":";;;;AAIA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,KAAK,EAAe;AAC5D,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACrC,IAAI,gBAAgB,EAAE,YAAY;AAClC,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"scope-utils.js","sources":["../../src/scope-utils.ts"],"sourcesContent":["import type { CfProperties, IncomingRequestCfProperties } from '@cloudflare/workers-types';\nimport type { Scope } from '@sentry/core';\nimport { winterCGRequestToRequestData } from '@sentry/core';\n\n/**\n * Set cloud resource context on scope.\n */\nexport function addCloudResourceContext(scope: Scope): void {\n scope.setContext('cloud_resource', {\n 'cloud.provider': 'cloudflare',\n });\n}\n\n/**\n * Set culture context on scope\n */\nexport function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties | CfProperties): void {\n scope.setContext('culture', {\n timezone: cf.timezone,\n });\n}\n\n/**\n * Set request data on scope\n */\nexport function addRequest(scope: Scope, request: Request): void {\n scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });\n}\n"],"names":["winterCGRequestToRequestData"],"mappings":";;;;AAIA;AACA;AACA;AACO,SAAS,uBAAuB,CAAC,KAAK,EAAe;AAC5D,EAAE,KAAK,CAAC,UAAU,CAAC,gBAAgB,EAAE;AACrC,IAAI,gBAAgB,EAAE,YAAY;AAClC,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAS,EAAE,EAAoD;AACtG,EAAE,KAAK,CAAC,UAAU,CAAC,SAAS,EAAE;AAC9B,IAAI,QAAQ,EAAE,EAAE,CAAC,QAAQ;AACzB,GAAG,CAAC;AACJ;;AAEA;AACA;AACA;AACO,SAAS,UAAU,CAAC,KAAK,EAAS,OAAO,EAAiB;AACjE,EAAE,KAAK,CAAC,wBAAwB,CAAC,EAAE,iBAAiB,EAAEA,iCAA4B,CAAC,OAAO,CAAA,EAAG,CAAC;AAC9F;;;;;;"}
|
package/build/cjs/sdk.js
CHANGED
|
@@ -41,10 +41,15 @@ function init(options) {
|
|
|
41
41
|
const flushLock = options.ctx ? flush.makeFlushLock(options.ctx) : undefined;
|
|
42
42
|
delete options.ctx;
|
|
43
43
|
|
|
44
|
+
const resolvedIntegrations = core.getIntegrationsToSetup(options);
|
|
45
|
+
if (options.traceLifecycle === 'stream' && !resolvedIntegrations.some(i => i.name === 'SpanStreaming')) {
|
|
46
|
+
resolvedIntegrations.push(core.spanStreamingIntegration());
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
const clientOptions = {
|
|
45
50
|
...options,
|
|
46
51
|
stackParser: core.stackParserFromStackParserOptions(options.stackParser || stacktrace.defaultStackParser),
|
|
47
|
-
integrations:
|
|
52
|
+
integrations: resolvedIntegrations,
|
|
48
53
|
transport: options.transport || transport.makeCloudflareTransport,
|
|
49
54
|
flushLock,
|
|
50
55
|
};
|
package/build/cjs/sdk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport {\n consoleIntegration,\n conversationIdIntegration,\n dedupeIntegration,\n functionToStringIntegration,\n getIntegrationsToSetup,\n inboundFiltersIntegration,\n initAndBind,\n linkedErrorsIntegration,\n requestDataIntegration,\n stackParserFromStackParserOptions,\n} from '@sentry/core';\nimport type { CloudflareClientOptions, CloudflareOptions } from './client';\nimport { CloudflareClient } from './client';\nimport { makeFlushLock } from './flush';\nimport { fetchIntegration } from './integrations/fetch';\nimport { honoIntegration } from './integrations/hono';\nimport { setupOpenTelemetryTracer } from './opentelemetry/tracer';\nimport { makeCloudflareTransport } from './transport';\nimport { defaultStackParser } from './vendor/stacktrace';\n\n/** Get the default integrations for the Cloudflare SDK. */\nexport function getDefaultIntegrations(options: CloudflareOptions): Integration[] {\n const sendDefaultPii = options.sendDefaultPii ?? false;\n return [\n // The Dedupe integration should not be used in workflows because we want to\n // capture all step failures, even if they are the same error.\n ...(options.enableDedupe === false ? [] : [dedupeIntegration()]),\n // TODO(v11): Replace with `eventFiltersIntegration` once we remove the deprecated `inboundFiltersIntegration`\n // eslint-disable-next-line deprecation/deprecation\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n linkedErrorsIntegration(),\n fetchIntegration(),\n honoIntegration(),\n // TODO(v11): the `include` object should be defined directly in the integration based on `sendDefaultPii`\n requestDataIntegration(sendDefaultPii ? undefined : { include: { cookies: false } }),\n consoleIntegration(),\n ];\n}\n\n/**\n * Initializes the cloudflare SDK.\n */\nexport function init(options: CloudflareOptions): CloudflareClient | undefined {\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n const flushLock = options.ctx ? makeFlushLock(options.ctx) : undefined;\n delete options.ctx;\n\n const clientOptions: CloudflareClientOptions = {\n ...options,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations:
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../src/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport {\n consoleIntegration,\n conversationIdIntegration,\n dedupeIntegration,\n functionToStringIntegration,\n getIntegrationsToSetup,\n inboundFiltersIntegration,\n initAndBind,\n linkedErrorsIntegration,\n requestDataIntegration,\n spanStreamingIntegration,\n stackParserFromStackParserOptions,\n} from '@sentry/core';\nimport type { CloudflareClientOptions, CloudflareOptions } from './client';\nimport { CloudflareClient } from './client';\nimport { makeFlushLock } from './flush';\nimport { fetchIntegration } from './integrations/fetch';\nimport { honoIntegration } from './integrations/hono';\nimport { setupOpenTelemetryTracer } from './opentelemetry/tracer';\nimport { makeCloudflareTransport } from './transport';\nimport { defaultStackParser } from './vendor/stacktrace';\n\n/** Get the default integrations for the Cloudflare SDK. */\nexport function getDefaultIntegrations(options: CloudflareOptions): Integration[] {\n const sendDefaultPii = options.sendDefaultPii ?? false;\n return [\n // The Dedupe integration should not be used in workflows because we want to\n // capture all step failures, even if they are the same error.\n ...(options.enableDedupe === false ? [] : [dedupeIntegration()]),\n // TODO(v11): Replace with `eventFiltersIntegration` once we remove the deprecated `inboundFiltersIntegration`\n // eslint-disable-next-line deprecation/deprecation\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n linkedErrorsIntegration(),\n fetchIntegration(),\n honoIntegration(),\n // TODO(v11): the `include` object should be defined directly in the integration based on `sendDefaultPii`\n requestDataIntegration(sendDefaultPii ? undefined : { include: { cookies: false } }),\n consoleIntegration(),\n ];\n}\n\n/**\n * Initializes the cloudflare SDK.\n */\nexport function init(options: CloudflareOptions): CloudflareClient | undefined {\n if (options.defaultIntegrations === undefined) {\n options.defaultIntegrations = getDefaultIntegrations(options);\n }\n\n const flushLock = options.ctx ? makeFlushLock(options.ctx) : undefined;\n delete options.ctx;\n\n const resolvedIntegrations = getIntegrationsToSetup(options);\n if (options.traceLifecycle === 'stream' && !resolvedIntegrations.some(i => i.name === 'SpanStreaming')) {\n resolvedIntegrations.push(spanStreamingIntegration());\n }\n\n const clientOptions: CloudflareClientOptions = {\n ...options,\n stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),\n integrations: resolvedIntegrations,\n transport: options.transport || makeCloudflareTransport,\n flushLock,\n };\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 (!options.skipOpenTelemetrySetup) {\n setupOpenTelemetryTracer();\n }\n\n return initAndBind(CloudflareClient, clientOptions) as CloudflareClient;\n}\n"],"names":["dedupeIntegration","inboundFiltersIntegration","functionToStringIntegration","conversationIdIntegration","linkedErrorsIntegration","fetchIntegration","honoIntegration","requestDataIntegration","consoleIntegration","makeFlushLock","getIntegrationsToSetup","spanStreamingIntegration","stackParserFromStackParserOptions","defaultStackParser","makeCloudflareTransport","setupOpenTelemetryTracer","initAndBind","CloudflareClient"],"mappings":";;;;;;;;;;;AAuBA;AACO,SAAS,sBAAsB,CAAC,OAAO,EAAoC;AAClF,EAAE,MAAM,cAAA,GAAiB,OAAO,CAAC,cAAA,IAAkB,KAAK;AACxD,EAAE,OAAO;AACT;AACA;AACA,IAAI,IAAI,OAAO,CAAC,YAAA,KAAiB,KAAA,GAAQ,EAAC,GAAI,CAACA,sBAAiB,EAAE,CAAC,CAAC;AACpE;AACA;AACA,IAAIC,8BAAyB,EAAE;AAC/B,IAAIC,gCAA2B,EAAE;AACjC,IAAIC,8BAAyB,EAAE;AAC/B,IAAIC,4BAAuB,EAAE;AAC7B,IAAIC,sBAAgB,EAAE;AACtB,IAAIC,oBAAe,EAAE;AACrB;AACA,IAAIC,2BAAsB,CAAC,cAAA,GAAiB,YAAY,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,KAAA,EAAM,EAAG,CAAC;AACxF,IAAIC,uBAAkB,EAAE;AACxB,GAAG;AACH;;AAEA;AACA;AACA;AACO,SAAS,IAAI,CAAC,OAAO,EAAmD;AAC/E,EAAE,IAAI,OAAO,CAAC,mBAAA,KAAwB,SAAS,EAAE;AACjD,IAAI,OAAO,CAAC,mBAAA,GAAsB,sBAAsB,CAAC,OAAO,CAAC;AACjE,EAAE;;AAEF,EAAE,MAAM,SAAA,GAAY,OAAO,CAAC,GAAA,GAAMC,mBAAa,CAAC,OAAO,CAAC,GAAG,CAAA,GAAI,SAAS;AACxE,EAAE,OAAO,OAAO,CAAC,GAAG;;AAEpB,EAAE,MAAM,oBAAA,GAAuBC,2BAAsB,CAAC,OAAO,CAAC;AAC9D,EAAE,IAAI,OAAO,CAAC,mBAAmB,QAAA,IAAY,CAAC,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAA,KAAS,eAAe,CAAC,EAAE;AAC1G,IAAI,oBAAoB,CAAC,IAAI,CAACC,6BAAwB,EAAE,CAAC;AACzD,EAAE;;AAEF,EAAE,MAAM,aAAa,GAA4B;AACjD,IAAI,GAAG,OAAO;AACd,IAAI,WAAW,EAAEC,sCAAiC,CAAC,OAAO,CAAC,WAAA,IAAeC,6BAAkB,CAAC;AAC7F,IAAI,YAAY,EAAE,oBAAoB;AACtC,IAAI,SAAS,EAAE,OAAO,CAAC,SAAA,IAAaC,iCAAuB;AAC3D,IAAI,SAAS;AACb,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE;AACvC,IAAIC,+BAAwB,EAAE;AAC9B,EAAE;;AAEF,EAAE,OAAOC,gBAAW,CAACC,uBAAgB,EAAE,aAAa,CAAA;AACpD;;;;;"}
|
|
@@ -39,13 +39,14 @@ function instrumentContext(ctx) {
|
|
|
39
39
|
// If so, wrap the storage with instrumentation
|
|
40
40
|
if ('storage' in ctx && ctx.storage) {
|
|
41
41
|
const originalStorage = ctx.storage;
|
|
42
|
+
const waitUntil = 'waitUntil' in ctx && typeof ctx.waitUntil === 'function' ? ctx.waitUntil.bind(ctx) : undefined;
|
|
42
43
|
let instrumentedStorage;
|
|
43
44
|
descriptors.storage = {
|
|
44
45
|
configurable: true,
|
|
45
46
|
enumerable: true,
|
|
46
47
|
get: () => {
|
|
47
48
|
if (!instrumentedStorage) {
|
|
48
|
-
instrumentedStorage = instrumentDurableObjectStorage.instrumentDurableObjectStorage(originalStorage);
|
|
49
|
+
instrumentedStorage = instrumentDurableObjectStorage.instrumentDurableObjectStorage(originalStorage, waitUntil);
|
|
49
50
|
}
|
|
50
51
|
return instrumentedStorage;
|
|
51
52
|
},
|
|
@@ -1 +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":["instrumentDurableObjectStorage"],"mappings":";;;;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,iBAAiB,CAAwB,GAAG,EAAQ;AACpE,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,WAAW,GAA0B,CAAC,GAAG,gBAAgB,EAAE,GAAG,oBAAoB,CAAC,CAAC,MAAM;AAClG,IAAI,CAAC,eAAe,EAAE,UAAU,KAAK;AACrC,MAAM,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,eAAe;AAC9D,MAAM,IAAI,OAAO,GAAG,CAAC,UAAU,CAAA,KAAM,UAAU,EAAE,OAAO,eAAe;AACvE,MAAM,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC;AAClC,MAAM,MAAM,qBAAA,GAAwB,yBAAyB,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC;AACzF,MAAM,OAAO;AACb,QAAQ,GAAG,eAAe;AAC1B,QAAQ,CAAC,UAAU,GAAG,qBAAqB;AAC3C,OAAO;AACP,IAAI,CAAC;AACL,IAAI,EAAC;AACL,GAAG;;AAEH;AACA;AACA,EAAE,IAAI,SAAA,IAAa,OAAO,GAAG,CAAC,OAAO,EAAE;AACvC,IAAI,MAAM,eAAA,GAAkB,GAAG,CAAC,OAAO;AACvC,IAAI,IAAI,mBAAmB;AAC3B,IAAI,WAAW,CAAC,OAAA,GAAU;AAC1B,MAAM,YAAY,EAAE,IAAI;AACxB,MAAM,UAAU,EAAE,IAAI;AACtB,MAAM,GAAG,EAAE,MAAM;AACjB,QAAQ,IAAI,CAAC,mBAAmB,EAAE;AAClC,UAAU,
|
|
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 const waitUntil = 'waitUntil' in ctx && typeof ctx.waitUntil === 'function' ? ctx.waitUntil.bind(ctx) : undefined;\n let instrumentedStorage: DurableObjectStorage | undefined;\n descriptors.storage = {\n configurable: true,\n enumerable: true,\n get: () => {\n if (!instrumentedStorage) {\n instrumentedStorage = instrumentDurableObjectStorage(originalStorage, waitUntil);\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":["instrumentDurableObjectStorage"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a value is a JSRPC proxy (service binding).
|
|
5
|
+
*
|
|
6
|
+
* JSRPC proxies return a truthy value for ANY property access, including
|
|
7
|
+
* properties that don't exist. This makes other duck-type checks unreliable
|
|
8
|
+
* unless we exclude JSRPC first.
|
|
9
|
+
*
|
|
10
|
+
* Must be checked before other binding type checks.
|
|
11
|
+
*/
|
|
12
|
+
function isJSRPC(item) {
|
|
13
|
+
try {
|
|
14
|
+
return !!(item )[`__some_property_that_will_never_exist__${Math.random()}`];
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const isNotJSRPC = (item) => !isJSRPC(item);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Duck-type check for DurableObjectNamespace bindings.
|
|
24
|
+
* DurableObjectNamespace has `idFromName`, `idFromString`, `get`, `newUniqueId`.
|
|
25
|
+
*/
|
|
26
|
+
function isDurableObjectNamespace(item) {
|
|
27
|
+
return item != null && isNotJSRPC(item) && typeof item.idFromName === 'function';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
exports.isDurableObjectNamespace = isDurableObjectNamespace;
|
|
31
|
+
exports.isJSRPC = isJSRPC;
|
|
32
|
+
//# sourceMappingURL=isBinding.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isBinding.js","sources":["../../../src/utils/isBinding.ts"],"sourcesContent":["/**\n * Adapted from https://github.com/evanderkoogh/otel-cf-workers/blob/effeb549f0a4ed1c55ea0c4f0d8e8e37e5494fb3/src/instrumentation/env.ts\n *\n * BSD 3-Clause License\n *\n * Copyright (c) 2023, Erwin van der Koogh\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * 1. Redistributions of source code must retain the above copyright notice, this\n * list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright notice,\n * this list of conditions and the following disclaimer in the documentation\n * and/or other materials provided with the distribution.\n *\n * 3. Neither the name of the copyright holder nor the names of its\n * contributors may be used to endorse or promote products derived from\n * this software without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\nimport type { DurableObjectNamespace } from '@cloudflare/workers-types';\n\n/**\n * Checks if a value is a JSRPC proxy (service binding).\n *\n * JSRPC proxies return a truthy value for ANY property access, including\n * properties that don't exist. This makes other duck-type checks unreliable\n * unless we exclude JSRPC first.\n *\n * Must be checked before other binding type checks.\n */\nexport function isJSRPC(item: unknown): item is Service {\n try {\n return !!(item as Record<string, unknown>)[`__some_property_that_will_never_exist__${Math.random()}`];\n } catch {\n return false;\n }\n}\n\nconst isNotJSRPC = (item: unknown): item is Record<string, unknown> => !isJSRPC(item);\n\n/**\n * Duck-type check for DurableObjectNamespace bindings.\n * DurableObjectNamespace has `idFromName`, `idFromString`, `get`, `newUniqueId`.\n */\nexport function isDurableObjectNamespace(item: unknown): item is DurableObjectNamespace {\n return item != null && isNotJSRPC(item) && typeof item.idFromName === 'function';\n}\n"],"names":[],"mappings":";;AAmCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,OAAO,CAAC,IAAI,EAA4B;AACxD,EAAE,IAAI;AACN,IAAI,OAAO,CAAC,CAAC,CAAC,IAAA,GAAiC,CAAC,uCAAuC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA,CAAA;AACA,EAAA,CAAA,CAAA,MAAA;AACA,IAAA,OAAA,KAAA;AACA,EAAA;AACA;;AAEA,MAAA,UAAA,GAAA,CAAA,IAAA,KAAA,CAAA,OAAA,CAAA,IAAA,CAAA;;AAEA;AACA;AACA;AACA;AACA,SAAA,wBAAA,CAAA,IAAA,EAAA;AACA,EAAA,OAAA,IAAA,IAAA,IAAA,IAAA,UAAA,CAAA,IAAA,CAAA,IAAA,OAAA,IAAA,CAAA,UAAA,KAAA,UAAA;AACA;;;;;"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
function isCloudflareClass(value, className) {
|
|
4
|
+
if (!value || typeof value !== 'function') {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (value.name === className) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let proto = value.prototype;
|
|
13
|
+
|
|
14
|
+
while (proto) {
|
|
15
|
+
const ctor = (proto ).constructor;
|
|
16
|
+
const constructorName = ctor?.name;
|
|
17
|
+
|
|
18
|
+
if (constructorName === className) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
proto = Object.getPrototypeOf(proto);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.isCloudflareClass = isCloudflareClass;
|
|
29
|
+
//# sourceMappingURL=isCloudflareClass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isCloudflareClass.js","sources":["../../../src/utils/isCloudflareClass.ts"],"sourcesContent":["import type { DurableObject, WorkflowEntrypoint } from 'cloudflare:workers';\nimport type { WorkerEntrypointConstructor } from '../instrumentations/instrumentWorkerEntrypoint';\ntype CloudflareClassName = 'WorkerEntrypoint' | 'DurableObject' | 'WorkflowEntrypoint';\n\n/**\n * Checks if a class constructor extends a specific Cloudflare base class.\n *\n * Uses prototype chain walking with constructor names rather than instanceof,\n * so it works in Node at build time without requiring the cloudflare:workers\n * module (which only exists in the Workers runtime).\n *\n * This is used to differentiate between different Cloudflare worker types:\n * - WorkerEntrypoint: Class-based workers (used with instrumentWorkerEntrypoint)\n * - DurableObject: Durable Object classes\n * - Workflow: Workflow classes\n *\n * For ExportedHandler (plain objects), this will return false for all types.\n *\n * @param value - The value to check (typically a class constructor)\n * @param className - The Cloudflare base class name to check against\n * @returns true if the value is a class that extends the specified Cloudflare class\n *\n * @example\n * ```ts\n * isCloudflareClass(MyWorker, 'WorkerEntrypoint') // true if MyWorker extends WorkerEntrypoint\n * isCloudflareClass(MyDO, 'DurableObject') // true if MyDO extends DurableObject\n * ```\n */\nexport function isCloudflareClass(value: unknown, className: 'WorkerEntrypoint'): value is WorkerEntrypointConstructor;\nexport function isCloudflareClass(\n value: unknown,\n className: 'DurableObject',\n): value is new (...args: unknown[]) => DurableObject;\nexport function isCloudflareClass(\n value: unknown,\n className: 'WorkflowEntrypoint',\n): value is new (...args: unknown[]) => WorkflowEntrypoint;\nexport function isCloudflareClass(value: unknown, className: CloudflareClassName): boolean {\n if (!value || typeof value !== 'function') {\n return false;\n }\n\n if (value.name === className) {\n return false;\n }\n\n let proto: object | null = value.prototype;\n\n while (proto) {\n const ctor = (proto as { constructor?: { name?: string } }).constructor;\n const constructorName = ctor?.name;\n\n if (constructorName === className) {\n return true;\n }\n\n proto = Object.getPrototypeOf(proto);\n }\n\n return false;\n}\n"],"names":[],"mappings":";;AAqCO,SAAS,iBAAiB,CAAC,KAAK,EAAW,SAAS,EAAgC;AAC3F,EAAE,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,UAAU,EAAE;AAC7C,IAAI,OAAO,KAAK;AAChB,EAAE;;AAEF,EAAE,IAAI,KAAK,CAAC,IAAA,KAAS,SAAS,EAAE;AAChC,IAAI,OAAO,KAAK;AAChB,EAAE;;AAEF,EAAE,IAAI,KAAK,GAAkB,KAAK,CAAC,SAAS;;AAE5C,EAAE,OAAO,KAAK,EAAE;AAChB,IAAI,MAAM,IAAA,GAAO,CAAC,KAAA,GAA8C,WAAW;AAC3E,IAAI,MAAM,eAAA,GAAkB,IAAI,EAAE,IAAI;;AAEtC,IAAI,IAAI,eAAA,KAAoB,SAAS,EAAE;AACvC,MAAM,OAAO,IAAI;AACjB,IAAI;;AAEJ,IAAI,QAAQ,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC;AACxC,EAAE;;AAEF,EAAE,OAAO,KAAK;AACd;;;;"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const debugBuild = require('../debug-build.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Gets the effective RPC propagation setting, handling deprecation of `instrumentPrototypeMethods`.
|
|
8
|
+
*
|
|
9
|
+
* Priority:
|
|
10
|
+
* 1. If `enableRpcTracePropagation` is set, use it (ignore `instrumentPrototypeMethods`)
|
|
11
|
+
* 2. If only `instrumentPrototypeMethods` is set, use it with deprecation warning (converted to boolean)
|
|
12
|
+
* 3. If neither is set, return `false`
|
|
13
|
+
*
|
|
14
|
+
* @returns The effective setting for RPC trace propagation
|
|
15
|
+
*/
|
|
16
|
+
function getEffectiveRpcPropagation(options) {
|
|
17
|
+
const { enableRpcTracePropagation, instrumentPrototypeMethods } = options;
|
|
18
|
+
|
|
19
|
+
// If the new option is explicitly set, use it
|
|
20
|
+
if (enableRpcTracePropagation !== undefined) {
|
|
21
|
+
if (instrumentPrototypeMethods !== undefined) {
|
|
22
|
+
debugBuild.DEBUG_BUILD &&
|
|
23
|
+
core.debug.warn(
|
|
24
|
+
'[Sentry] Both `enableRpcTracePropagation` and `instrumentPrototypeMethods` are set. ' +
|
|
25
|
+
'Using `enableRpcTracePropagation` and ignoring `instrumentPrototypeMethods`.',
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
return enableRpcTracePropagation;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Fall back to deprecated option with warning
|
|
32
|
+
if (instrumentPrototypeMethods !== undefined) {
|
|
33
|
+
debugBuild.DEBUG_BUILD &&
|
|
34
|
+
core.debug.warn(
|
|
35
|
+
'[Sentry] `instrumentPrototypeMethods` is deprecated and will be removed in a future major version. ' +
|
|
36
|
+
'Please use `enableRpcTracePropagation` instead.',
|
|
37
|
+
);
|
|
38
|
+
// instrumentPrototypeMethods can be boolean or string[], convert to boolean
|
|
39
|
+
return (
|
|
40
|
+
instrumentPrototypeMethods === true ||
|
|
41
|
+
(Array.isArray(instrumentPrototypeMethods) && instrumentPrototypeMethods.length > 0)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Gets the method filter for prototype method instrumentation.
|
|
50
|
+
*
|
|
51
|
+
* Returns:
|
|
52
|
+
* - `null` if no instrumentation should occur
|
|
53
|
+
* - `true` if all methods should be instrumented
|
|
54
|
+
* - `string[]` if only specific methods should be instrumented (deprecated behavior)
|
|
55
|
+
*
|
|
56
|
+
* @returns The method filter or null if no instrumentation
|
|
57
|
+
*/
|
|
58
|
+
function getPrototypeMethodFilter(options) {
|
|
59
|
+
const { enableRpcTracePropagation, instrumentPrototypeMethods } = options;
|
|
60
|
+
|
|
61
|
+
// If the new option is explicitly set, use it (boolean only, no filtering)
|
|
62
|
+
if (enableRpcTracePropagation !== undefined) {
|
|
63
|
+
return !!enableRpcTracePropagation;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Fall back to deprecated option - preserve array filtering behavior
|
|
67
|
+
if (instrumentPrototypeMethods !== undefined) {
|
|
68
|
+
if (instrumentPrototypeMethods === true) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (Array.isArray(instrumentPrototypeMethods) && instrumentPrototypeMethods.length > 0) {
|
|
73
|
+
return instrumentPrototypeMethods;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
exports.getEffectiveRpcPropagation = getEffectiveRpcPropagation;
|
|
83
|
+
exports.getPrototypeMethodFilter = getPrototypeMethodFilter;
|
|
84
|
+
//# sourceMappingURL=rpcOptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpcOptions.js","sources":["../../../src/utils/rpcOptions.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport type { CloudflareOptions } from '../client';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Gets the effective RPC propagation setting, handling deprecation of `instrumentPrototypeMethods`.\n *\n * Priority:\n * 1. If `enableRpcTracePropagation` is set, use it (ignore `instrumentPrototypeMethods`)\n * 2. If only `instrumentPrototypeMethods` is set, use it with deprecation warning (converted to boolean)\n * 3. If neither is set, return `false`\n *\n * @returns The effective setting for RPC trace propagation\n */\nexport function getEffectiveRpcPropagation(options: CloudflareOptions): boolean {\n const { enableRpcTracePropagation, instrumentPrototypeMethods } = options;\n\n // If the new option is explicitly set, use it\n if (enableRpcTracePropagation !== undefined) {\n if (instrumentPrototypeMethods !== undefined) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] Both `enableRpcTracePropagation` and `instrumentPrototypeMethods` are set. ' +\n 'Using `enableRpcTracePropagation` and ignoring `instrumentPrototypeMethods`.',\n );\n }\n return enableRpcTracePropagation;\n }\n\n // Fall back to deprecated option with warning\n if (instrumentPrototypeMethods !== undefined) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] `instrumentPrototypeMethods` is deprecated and will be removed in a future major version. ' +\n 'Please use `enableRpcTracePropagation` instead.',\n );\n // instrumentPrototypeMethods can be boolean or string[], convert to boolean\n return (\n instrumentPrototypeMethods === true ||\n (Array.isArray(instrumentPrototypeMethods) && instrumentPrototypeMethods.length > 0)\n );\n }\n\n return false;\n}\n\n/**\n * Gets the method filter for prototype method instrumentation.\n *\n * Returns:\n * - `null` if no instrumentation should occur\n * - `true` if all methods should be instrumented\n * - `string[]` if only specific methods should be instrumented (deprecated behavior)\n *\n * @returns The method filter or null if no instrumentation\n */\nexport function getPrototypeMethodFilter(options: CloudflareOptions): boolean | string[] {\n const { enableRpcTracePropagation, instrumentPrototypeMethods } = options;\n\n // If the new option is explicitly set, use it (boolean only, no filtering)\n if (enableRpcTracePropagation !== undefined) {\n return !!enableRpcTracePropagation;\n }\n\n // Fall back to deprecated option - preserve array filtering behavior\n if (instrumentPrototypeMethods !== undefined) {\n if (instrumentPrototypeMethods === true) {\n return true;\n }\n\n if (Array.isArray(instrumentPrototypeMethods) && instrumentPrototypeMethods.length > 0) {\n return instrumentPrototypeMethods;\n }\n\n return false;\n }\n\n return false;\n}\n"],"names":["DEBUG_BUILD","debug"],"mappings":";;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,0BAA0B,CAAC,OAAO,EAA8B;AAChF,EAAE,MAAM,EAAE,yBAAyB,EAAE,0BAAA,EAA2B,GAAI,OAAO;;AAE3E;AACA,EAAE,IAAI,yBAAA,KAA8B,SAAS,EAAE;AAC/C,IAAI,IAAI,0BAAA,KAA+B,SAAS,EAAE;AAClD,MAAMA,sBAAA;AACN,QAAQC,UAAK,CAAC,IAAI;AAClB,UAAU,sFAAA;AACV,YAAY,8EAA8E;AAC1F,SAAS;AACT,IAAI;AACJ,IAAI,OAAO,yBAAyB;AACpC,EAAE;;AAEF;AACA,EAAE,IAAI,0BAAA,KAA+B,SAAS,EAAE;AAChD,IAAID,sBAAA;AACJ,MAAMC,UAAK,CAAC,IAAI;AAChB,QAAQ,qGAAA;AACR,UAAU,iDAAiD;AAC3D,OAAO;AACP;AACA,IAAI;AACJ,MAAM,0BAAA,KAA+B,IAAA;AACrC,OAAO,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAA,IAAK,0BAA0B,CAAC,MAAA,GAAS,CAAC;AACzF;AACA,EAAE;;AAEF,EAAE,OAAO,KAAK;AACd;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,wBAAwB,CAAC,OAAO,EAAyC;AACzF,EAAE,MAAM,EAAE,yBAAyB,EAAE,0BAAA,EAA2B,GAAI,OAAO;;AAE3E;AACA,EAAE,IAAI,yBAAA,KAA8B,SAAS,EAAE;AAC/C,IAAI,OAAO,CAAC,CAAC,yBAAyB;AACtC,EAAE;;AAEF;AACA,EAAE,IAAI,0BAAA,KAA+B,SAAS,EAAE;AAChD,IAAI,IAAI,0BAAA,KAA+B,IAAI,EAAE;AAC7C,MAAM,OAAO,IAAI;AACjB,IAAI;;AAEJ,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,0BAA0B,CAAA,IAAK,0BAA0B,CAAC,MAAA,GAAS,CAAC,EAAE;AAC5F,MAAM,OAAO,0BAA0B;AACvC,IAAI;;AAEJ,IAAI,OAAO,KAAK;AAChB,EAAE;;AAEF,EAAE,OAAO,KAAK;AACd;;;;;"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const api = require('@opentelemetry/api');
|
|
4
|
+
const core = require('@sentry/core');
|
|
5
|
+
const debugBuild = require('../debug-build.js');
|
|
6
|
+
|
|
7
|
+
/** Storage key prefix for the span context that links consecutive method invocations */
|
|
8
|
+
const SENTRY_TRACE_LINK_KEY_PREFIX = '__SENTRY_TRACE_LINK__';
|
|
9
|
+
|
|
10
|
+
/** Stored span context for creating span links */
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets the storage key for a specific method's trace link.
|
|
14
|
+
*/
|
|
15
|
+
function getTraceLinkKey(methodName) {
|
|
16
|
+
return `${SENTRY_TRACE_LINK_KEY_PREFIX}${methodName}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Stores the current span context in Durable Object storage for trace linking.
|
|
21
|
+
* Uses the original uninstrumented storage to avoid creating spans for internal operations.
|
|
22
|
+
* Errors are silently ignored to prevent internal storage failures from propagating to user code.
|
|
23
|
+
*/
|
|
24
|
+
async function storeSpanContext(originalStorage, methodName) {
|
|
25
|
+
try {
|
|
26
|
+
const activeSpan = core.getActiveSpan();
|
|
27
|
+
if (activeSpan) {
|
|
28
|
+
const spanContext = activeSpan.spanContext();
|
|
29
|
+
const storedContext = {
|
|
30
|
+
traceId: spanContext.traceId,
|
|
31
|
+
spanId: spanContext.spanId,
|
|
32
|
+
sampled: core.spanIsSampled(activeSpan),
|
|
33
|
+
};
|
|
34
|
+
await originalStorage.put(getTraceLinkKey(methodName), storedContext);
|
|
35
|
+
}
|
|
36
|
+
} catch (error) {
|
|
37
|
+
// Silently ignore storage errors to prevent internal failures from affecting user code
|
|
38
|
+
debugBuild.DEBUG_BUILD && core.debug.log(`[CloudflareClient] Error storing span context for method ${methodName}`, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Retrieves a stored span context from Durable Object storage.
|
|
44
|
+
*/
|
|
45
|
+
async function getStoredSpanContext(
|
|
46
|
+
originalStorage,
|
|
47
|
+
methodName,
|
|
48
|
+
) {
|
|
49
|
+
try {
|
|
50
|
+
return await originalStorage.get(getTraceLinkKey(methodName));
|
|
51
|
+
} catch {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Builds span links from a stored span context.
|
|
58
|
+
*/
|
|
59
|
+
function buildSpanLinks(storedContext) {
|
|
60
|
+
return [
|
|
61
|
+
{
|
|
62
|
+
context: {
|
|
63
|
+
traceId: storedContext.traceId,
|
|
64
|
+
spanId: storedContext.spanId,
|
|
65
|
+
traceFlags: storedContext.sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE,
|
|
66
|
+
},
|
|
67
|
+
attributes: {
|
|
68
|
+
[core.SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE]: 'previous_trace',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
exports.buildSpanLinks = buildSpanLinks;
|
|
75
|
+
exports.getStoredSpanContext = getStoredSpanContext;
|
|
76
|
+
exports.getTraceLinkKey = getTraceLinkKey;
|
|
77
|
+
exports.storeSpanContext = storeSpanContext;
|
|
78
|
+
//# sourceMappingURL=traceLinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traceLinks.js","sources":["../../../src/utils/traceLinks.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport { TraceFlags } from '@opentelemetry/api';\nimport type { SpanLink } from '@sentry/core';\nimport { debug, getActiveSpan, SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE, spanIsSampled } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/** Storage key prefix for the span context that links consecutive method invocations */\nconst SENTRY_TRACE_LINK_KEY_PREFIX = '__SENTRY_TRACE_LINK__';\n\n/** Stored span context for creating span links */\nexport interface StoredSpanContext {\n traceId: string;\n spanId: string;\n sampled: boolean;\n}\n\n/**\n * Gets the storage key for a specific method's trace link.\n */\nexport function getTraceLinkKey(methodName: string): string {\n return `${SENTRY_TRACE_LINK_KEY_PREFIX}${methodName}`;\n}\n\n/**\n * Stores the current span context in Durable Object storage for trace linking.\n * Uses the original uninstrumented storage to avoid creating spans for internal operations.\n * Errors are silently ignored to prevent internal storage failures from propagating to user code.\n */\nexport async function storeSpanContext(originalStorage: DurableObjectStorage, methodName: string): Promise<void> {\n try {\n const activeSpan = getActiveSpan();\n if (activeSpan) {\n const spanContext = activeSpan.spanContext();\n const storedContext: StoredSpanContext = {\n traceId: spanContext.traceId,\n spanId: spanContext.spanId,\n sampled: spanIsSampled(activeSpan),\n };\n await originalStorage.put(getTraceLinkKey(methodName), storedContext);\n }\n } catch (error) {\n // Silently ignore storage errors to prevent internal failures from affecting user code\n DEBUG_BUILD && debug.log(`[CloudflareClient] Error storing span context for method ${methodName}`, error);\n }\n}\n\n/**\n * Retrieves a stored span context from Durable Object storage.\n */\nexport async function getStoredSpanContext(\n originalStorage: DurableObjectStorage,\n methodName: string,\n): Promise<StoredSpanContext | undefined> {\n try {\n return await originalStorage.get<StoredSpanContext>(getTraceLinkKey(methodName));\n } catch {\n return undefined;\n }\n}\n\n/**\n * Builds span links from a stored span context.\n */\nexport function buildSpanLinks(storedContext: StoredSpanContext): SpanLink[] {\n return [\n {\n context: {\n traceId: storedContext.traceId,\n spanId: storedContext.spanId,\n traceFlags: storedContext.sampled ? TraceFlags.SAMPLED : TraceFlags.NONE,\n },\n attributes: {\n [SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE]: 'previous_trace',\n },\n },\n ];\n}\n"],"names":["getActiveSpan","spanIsSampled","DEBUG_BUILD","debug","TraceFlags","SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE"],"mappings":";;;;;;AAMA;AACA,MAAM,4BAAA,GAA+B,uBAAuB;;AAE5D;;AAOA;AACA;AACA;AACO,SAAS,eAAe,CAAC,UAAU,EAAkB;AAC5D,EAAE,OAAO,CAAC,EAAA,4BAAA,CAAA,EAAA,UAAA,CAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,eAAA,gBAAA,CAAA,eAAA,EAAA,UAAA,EAAA;AACA,EAAA,IAAA;AACA,IAAA,MAAA,UAAA,GAAAA,kBAAA,EAAA;AACA,IAAA,IAAA,UAAA,EAAA;AACA,MAAA,MAAA,WAAA,GAAA,UAAA,CAAA,WAAA,EAAA;AACA,MAAA,MAAA,aAAA,GAAA;AACA,QAAA,OAAA,EAAA,WAAA,CAAA,OAAA;AACA,QAAA,MAAA,EAAA,WAAA,CAAA,MAAA;AACA,QAAA,OAAA,EAAAC,kBAAA,CAAA,UAAA,CAAA;AACA,OAAA;AACA,MAAA,MAAA,eAAA,CAAA,GAAA,CAAA,eAAA,CAAA,UAAA,CAAA,EAAA,aAAA,CAAA;AACA,IAAA;AACA,EAAA,CAAA,CAAA,OAAA,KAAA,EAAA;AACA;AACA,IAAAC,sBAAA,IAAAC,UAAA,CAAA,GAAA,CAAA,CAAA,yDAAA,EAAA,UAAA,CAAA,CAAA,EAAA,KAAA,CAAA;AACA,EAAA;AACA;;AAEA;AACA;AACA;AACA,eAAA,oBAAA;AACA,EAAA,eAAA;AACA,EAAA,UAAA;AACA,EAAA;AACA,EAAA,IAAA;AACA,IAAA,OAAA,MAAA,eAAA,CAAA,GAAA,CAAA,eAAA,CAAA,UAAA,CAAA,CAAA;AACA,EAAA,CAAA,CAAA,MAAA;AACA,IAAA,OAAA,SAAA;AACA,EAAA;AACA;;AAEA;AACA;AACA;AACA,SAAA,cAAA,CAAA,aAAA,EAAA;AACA,EAAA,OAAA;AACA,IAAA;AACA,MAAA,OAAA,EAAA;AACA,QAAA,OAAA,EAAA,aAAA,CAAA,OAAA;AACA,QAAA,MAAA,EAAA,aAAA,CAAA,MAAA;AACA,QAAA,UAAA,EAAA,aAAA,CAAA,OAAA,GAAAC,cAAA,CAAA,OAAA,GAAAA,cAAA,CAAA,IAAA;AACA,OAAA;AACA,MAAA,UAAA,EAAA;AACA,QAAA,CAAAC,sCAAA,GAAA,gBAAA;AACA,OAAA;AACA,KAAA;AACA,GAAA;AACA;;;;;;;"}
|
package/build/cjs/withSentry.js
CHANGED
|
@@ -8,6 +8,8 @@ const instrumentQueue = require('./instrumentations/worker/instrumentQueue.js');
|
|
|
8
8
|
const instrumentScheduled = require('./instrumentations/worker/instrumentScheduled.js');
|
|
9
9
|
const instrumentTail = require('./instrumentations/worker/instrumentTail.js');
|
|
10
10
|
const hono = require('./integrations/hono.js');
|
|
11
|
+
const isCloudflareClass = require('./utils/isCloudflareClass.js');
|
|
12
|
+
const instrumentWorkerEntrypoint = require('./instrumentations/instrumentWorkerEntrypoint.js');
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* Wrapper for Cloudflare handlers.
|
|
@@ -20,18 +22,30 @@ const hono = require('./integrations/hono.js');
|
|
|
20
22
|
* @param handler {ExportedHandler} The handler to wrap.
|
|
21
23
|
* @returns The wrapped handler.
|
|
22
24
|
*/
|
|
25
|
+
// TODO(v11): The generic types need to be rewritten to following to improve type safety:
|
|
26
|
+
// T extends ExportedHandler<any, any, any> | WorkerEntrypointConstructor<any, any>
|
|
23
27
|
function withSentry
|
|
24
28
|
|
|
25
29
|
(optionsCallback, handler) {
|
|
30
|
+
if (isCloudflareClass.isCloudflareClass(handler, 'WorkerEntrypoint')) {
|
|
31
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
32
|
+
return instrumentWorkerEntrypoint.instrumentWorkerEntrypoint(optionsCallback , handler);
|
|
33
|
+
}
|
|
34
|
+
|
|
26
35
|
async.setAsyncLocalStorageAsyncContextStrategy();
|
|
27
36
|
|
|
28
37
|
try {
|
|
29
|
-
|
|
38
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
39
|
+
instrumentFetch.instrumentExportedHandlerFetch(handler, optionsCallback );
|
|
30
40
|
instrumentHonoErrorHandler(handler);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
42
|
+
instrumentScheduled.instrumentExportedHandlerScheduled(handler, optionsCallback );
|
|
43
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
44
|
+
instrumentEmail.instrumentExportedHandlerEmail(handler, optionsCallback );
|
|
45
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
46
|
+
instrumentQueue.instrumentExportedHandlerQueue(handler, optionsCallback );
|
|
47
|
+
// oxlint-disable-next-line typescript/no-explicit-any
|
|
48
|
+
instrumentTail.instrumentExportedHandlerTail(handler, optionsCallback );
|
|
35
49
|
// This is here because Miniflare sometimes cannot get instrumented
|
|
36
50
|
} catch {
|
|
37
51
|
// Do not console anything here, we don't want to spam the console with errors
|
|
@@ -42,23 +56,20 @@ function withSentry
|
|
|
42
56
|
|
|
43
57
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
58
|
function instrumentHonoErrorHandler(handler) {
|
|
45
|
-
if (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
apply(target, thisArg, args) {
|
|
53
|
-
const [err, context] = args;
|
|
54
|
-
|
|
55
|
-
hono.getHonoIntegration()?.handleHonoException(err, context);
|
|
59
|
+
if ('onError' in handler && 'errorHandler' in handler && typeof handler.errorHandler === 'function') {
|
|
60
|
+
handler.errorHandler = instrument.ensureInstrumented(
|
|
61
|
+
handler.errorHandler,
|
|
62
|
+
original =>
|
|
63
|
+
new Proxy(original, {
|
|
64
|
+
apply(target, thisArg, args) {
|
|
65
|
+
const [err, context] = args;
|
|
56
66
|
|
|
57
|
-
|
|
58
|
-
},
|
|
59
|
-
});
|
|
67
|
+
hono.getHonoIntegration()?.handleHonoException(err, context);
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
return Reflect.apply(target, thisArg, args);
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
62
73
|
}
|
|
63
74
|
}
|
|
64
75
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withSentry.js","sources":["../../src/withSentry.ts"],"sourcesContent":["import type { env } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport {
|
|
1
|
+
{"version":3,"file":"withSentry.js","sources":["../../src/withSentry.ts"],"sourcesContent":["import type { env as cloudflareEnv } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { ensureInstrumented } from './instrument';\nimport { instrumentExportedHandlerEmail } from './instrumentations/worker/instrumentEmail';\nimport { instrumentExportedHandlerFetch } from './instrumentations/worker/instrumentFetch';\nimport { instrumentExportedHandlerQueue } from './instrumentations/worker/instrumentQueue';\nimport { instrumentExportedHandlerScheduled } from './instrumentations/worker/instrumentScheduled';\nimport { instrumentExportedHandlerTail } from './instrumentations/worker/instrumentTail';\nimport { getHonoIntegration } from './integrations/hono';\nimport { isCloudflareClass } from './utils/isCloudflareClass';\nimport {\n instrumentWorkerEntrypoint,\n type WorkerEntrypointConstructor,\n} from './instrumentations/instrumentWorkerEntrypoint';\n\n/**\n * Wrapper for Cloudflare handlers.\n *\n * Initializes the SDK and wraps the handler with Sentry instrumentation.\n *\n * Automatically instruments the `fetch` method of the handler.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param handler {ExportedHandler} The handler to wrap.\n * @returns The wrapped handler.\n */\n// TODO(v11): The generic types need to be rewritten to following to improve type safety:\n// T extends ExportedHandler<any, any, any> | WorkerEntrypointConstructor<any, any>\nexport function withSentry<\n Env = typeof cloudflareEnv,\n QueueHandlerMessage = unknown,\n CfHostMetadata = unknown,\n T extends ExportedHandler<Env, QueueHandlerMessage, CfHostMetadata> | WorkerEntrypointConstructor = ExportedHandler<\n Env,\n QueueHandlerMessage,\n CfHostMetadata\n >,\n>(optionsCallback: (env: Env) => CloudflareOptions | undefined, handler: T): T {\n if (isCloudflareClass(handler, 'WorkerEntrypoint')) {\n // oxlint-disable-next-line typescript/no-explicit-any\n return instrumentWorkerEntrypoint(optionsCallback as any, handler);\n }\n\n setAsyncLocalStorageAsyncContextStrategy();\n\n try {\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerFetch(handler, optionsCallback as any);\n instrumentHonoErrorHandler(handler);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerScheduled(handler, optionsCallback as any);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerEmail(handler, optionsCallback as any);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerQueue(handler, optionsCallback as any);\n // oxlint-disable-next-line typescript/no-explicit-any\n instrumentExportedHandlerTail(handler, optionsCallback as any);\n // This is here because Miniflare sometimes cannot get instrumented\n } catch {\n // Do not console anything here, we don't want to spam the console with errors\n }\n\n return handler;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction instrumentHonoErrorHandler<T extends ExportedHandler<any, any, any>>(handler: T): void {\n if ('onError' in handler && 'errorHandler' in handler && typeof handler.errorHandler === 'function') {\n handler.errorHandler = ensureInstrumented(\n handler.errorHandler,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args) {\n const [err, context] = args;\n\n getHonoIntegration()?.handleHonoException(err, context);\n\n return Reflect.apply(target, thisArg, args);\n },\n }),\n );\n }\n}\n"],"names":["isCloudflareClass","instrumentWorkerEntrypoint","setAsyncLocalStorageAsyncContextStrategy","instrumentExportedHandlerFetch","instrumentExportedHandlerScheduled","instrumentExportedHandlerEmail","instrumentExportedHandlerQueue","instrumentExportedHandlerTail","ensureInstrumented","getHonoIntegration"],"mappings":";;;;;;;;;;;;;AAgBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS;;AAShB,CAAE,eAAe,EAA+C,OAAO,EAAQ;AAC/E,EAAE,IAAIA,mCAAiB,CAAC,OAAO,EAAE,kBAAkB,CAAC,EAAE;AACtD;AACA,IAAI,OAAOC,qDAA0B,CAAC,eAAA,GAAwB,OAAO,CAAC;AACtE,EAAE;;AAEF,EAAEC,8CAAwC,EAAE;;AAE5C,EAAE,IAAI;AACN;AACA,IAAIC,8CAA8B,CAAC,OAAO,EAAE,iBAAuB;AACnE,IAAI,0BAA0B,CAAC,OAAO,CAAC;AACvC;AACA,IAAIC,sDAAkC,CAAC,OAAO,EAAE,iBAAuB;AACvE;AACA,IAAIC,8CAA8B,CAAC,OAAO,EAAE,iBAAuB;AACnE;AACA,IAAIC,8CAA8B,CAAC,OAAO,EAAE,iBAAuB;AACnE;AACA,IAAIC,4CAA6B,CAAC,OAAO,EAAE,iBAAuB;AAClE;AACA,EAAE,EAAE,MAAM;AACV;AACA,EAAE;;AAEF,EAAE,OAAO,OAAO;AAChB;;AAEA;AACA,SAAS,0BAA0B,CAA2C,OAAO,EAAW;AAChG,EAAE,IAAI,SAAA,IAAa,OAAA,IAAW,cAAA,IAAkB,OAAA,IAAW,OAAO,OAAO,CAAC,YAAA,KAAiB,UAAU,EAAE;AACvG,IAAI,OAAO,CAAC,YAAA,GAAeC,6BAAkB;AAC7C,MAAM,OAAO,CAAC,YAAY;AAC1B,MAAM,QAAA;AACN,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE;AAC5B,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;AACvC,YAAY,MAAM,CAAC,GAAG,EAAE,OAAO,CAAA,GAAI,IAAI;;AAEvC,YAAYC,uBAAkB,EAAE,EAAE,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC;;AAEnE,YAAY,OAAO,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AACvD,UAAU,CAAC;AACX,SAAS,CAAC;AACV,KAAK;AACL,EAAE;AACF;;;;"}
|
package/build/cjs/workflows.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
const async = require('./async.js');
|
|
5
5
|
const flush = require('./flush.js');
|
|
6
|
+
const instrumentEnv = require('./instrumentations/worker/instrumentEnv.js');
|
|
6
7
|
const scopeUtils = require('./scope-utils.js');
|
|
7
8
|
const sdk = require('./sdk.js');
|
|
8
9
|
const instrumentContext = require('./utils/instrumentContext.js');
|
|
@@ -133,9 +134,9 @@ function instrumentWorkflowWithSentry
|
|
|
133
134
|
construct(target, args, newTarget) {
|
|
134
135
|
const [ctx, env] = args;
|
|
135
136
|
const context = instrumentContext.instrumentContext(ctx);
|
|
136
|
-
args[0] = context;
|
|
137
|
-
|
|
138
137
|
const options = optionsCallback(env);
|
|
138
|
+
args[0] = context;
|
|
139
|
+
args[1] = instrumentEnv.instrumentEnv(env , options) ;
|
|
139
140
|
const instance = Reflect.construct(target, args, newTarget) ;
|
|
140
141
|
return new Proxy(instance, {
|
|
141
142
|
get(obj, prop, receiver) {
|