@sentry/cloudflare 11.0.0-beta.1 → 11.0.0-rc.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/dev/durableobject.js +6 -2
- package/build/cjs/dev/durableobject.js.map +1 -1
- package/build/cjs/dev/index.js +19 -13
- package/build/cjs/dev/index.js.map +1 -1
- package/build/cjs/dev/instrument.js +4 -0
- package/build/cjs/dev/instrument.js.map +1 -1
- package/build/cjs/dev/instrumentations/instrumentSqlStorage.js +3 -3
- package/build/cjs/dev/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/cjs/dev/instrumentations/instrumentWorkerEntrypoint.js +4 -1
- package/build/cjs/dev/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/cjs/dev/instrumentations/worker/instrumentD1.js +20 -18
- package/build/cjs/dev/instrumentations/worker/instrumentD1.js.map +1 -1
- package/build/cjs/dev/instrumentations/worker/instrumentEmail.js +4 -3
- package/build/cjs/dev/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/cjs/dev/instrumentations/worker/instrumentScheduled.js +10 -5
- package/build/cjs/dev/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/cjs/dev/orchestrion-deferred-channels.js +39 -0
- package/build/cjs/dev/orchestrion-deferred-channels.js.map +1 -0
- package/build/cjs/dev/orchestrion-diagnostics-channel.js +83 -0
- package/build/cjs/dev/orchestrion-diagnostics-channel.js.map +1 -0
- package/build/cjs/dev/vite/agentClass.js +3 -2
- package/build/cjs/dev/vite/agentClass.js.map +1 -1
- package/build/cjs/dev/vite/autoInstrument.js +1 -1
- package/build/cjs/dev/vite/autoInstrument.js.map +1 -1
- package/build/cjs/dev/vite/index.js +6 -1
- package/build/cjs/dev/vite/index.js.map +1 -1
- package/build/cjs/dev/vite/mastraObservability.js +39 -0
- package/build/cjs/dev/vite/mastraObservability.js.map +1 -0
- package/build/cjs/dev/vite/transform.js +79 -16
- package/build/cjs/dev/vite/transform.js.map +1 -1
- package/build/cjs/dev/workflows.js +4 -1
- package/build/cjs/dev/workflows.js.map +1 -1
- package/build/cjs/dev/wrapMethodWithSentry.js +8 -4
- package/build/cjs/dev/wrapMethodWithSentry.js.map +1 -1
- package/build/cjs/dev/wrapRequestHandlerWithInit.js +2 -0
- package/build/cjs/dev/wrapRequestHandlerWithInit.js.map +1 -1
- package/build/cjs/prod/durableobject.js +6 -2
- package/build/cjs/prod/durableobject.js.map +1 -1
- package/build/cjs/prod/index.js +19 -13
- package/build/cjs/prod/index.js.map +1 -1
- package/build/cjs/prod/instrument.js +4 -0
- package/build/cjs/prod/instrument.js.map +1 -1
- package/build/cjs/prod/instrumentations/instrumentSqlStorage.js +3 -3
- package/build/cjs/prod/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/cjs/prod/instrumentations/instrumentWorkerEntrypoint.js +4 -1
- package/build/cjs/prod/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/cjs/prod/instrumentations/worker/instrumentD1.js +20 -18
- package/build/cjs/prod/instrumentations/worker/instrumentD1.js.map +1 -1
- package/build/cjs/prod/instrumentations/worker/instrumentEmail.js +4 -3
- package/build/cjs/prod/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/cjs/prod/instrumentations/worker/instrumentScheduled.js +10 -5
- package/build/cjs/prod/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/cjs/prod/orchestrion-deferred-channels.js +39 -0
- package/build/cjs/prod/orchestrion-deferred-channels.js.map +1 -0
- package/build/cjs/prod/orchestrion-diagnostics-channel.js +83 -0
- package/build/cjs/prod/orchestrion-diagnostics-channel.js.map +1 -0
- package/build/cjs/prod/vite/agentClass.js +3 -2
- package/build/cjs/prod/vite/agentClass.js.map +1 -1
- package/build/cjs/prod/vite/autoInstrument.js +1 -1
- package/build/cjs/prod/vite/autoInstrument.js.map +1 -1
- package/build/cjs/prod/vite/index.js +6 -1
- package/build/cjs/prod/vite/index.js.map +1 -1
- package/build/cjs/prod/vite/mastraObservability.js +39 -0
- package/build/cjs/prod/vite/mastraObservability.js.map +1 -0
- package/build/cjs/prod/vite/transform.js +79 -16
- package/build/cjs/prod/vite/transform.js.map +1 -1
- package/build/cjs/prod/workflows.js +4 -1
- package/build/cjs/prod/workflows.js.map +1 -1
- package/build/cjs/prod/wrapMethodWithSentry.js +8 -4
- package/build/cjs/prod/wrapMethodWithSentry.js.map +1 -1
- package/build/cjs/prod/wrapRequestHandlerWithInit.js +2 -0
- package/build/cjs/prod/wrapRequestHandlerWithInit.js.map +1 -1
- package/build/esm/dev/durableobject.js +6 -2
- package/build/esm/dev/durableobject.js.map +1 -1
- package/build/esm/dev/index.js +3 -2
- package/build/esm/dev/index.js.map +1 -1
- package/build/esm/dev/instrument.js +4 -1
- package/build/esm/dev/instrument.js.map +1 -1
- package/build/esm/dev/instrumentations/instrumentSqlStorage.js +3 -3
- package/build/esm/dev/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/esm/dev/instrumentations/instrumentWorkerEntrypoint.js +4 -1
- package/build/esm/dev/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/esm/dev/instrumentations/worker/instrumentD1.js +20 -18
- package/build/esm/dev/instrumentations/worker/instrumentD1.js.map +1 -1
- package/build/esm/dev/instrumentations/worker/instrumentEmail.js +6 -5
- package/build/esm/dev/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/esm/dev/instrumentations/worker/instrumentScheduled.js +12 -7
- package/build/esm/dev/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/esm/dev/orchestrion-deferred-channels.js +35 -0
- package/build/esm/dev/orchestrion-deferred-channels.js.map +1 -0
- package/build/esm/dev/orchestrion-diagnostics-channel.js +77 -0
- package/build/esm/dev/orchestrion-diagnostics-channel.js.map +1 -0
- package/build/esm/dev/package.json +1 -1
- package/build/esm/dev/vite/agentClass.js +3 -2
- package/build/esm/dev/vite/agentClass.js.map +1 -1
- package/build/esm/dev/vite/autoInstrument.js +1 -1
- package/build/esm/dev/vite/autoInstrument.js.map +1 -1
- package/build/esm/dev/vite/index.js +6 -1
- package/build/esm/dev/vite/index.js.map +1 -1
- package/build/esm/dev/vite/mastraObservability.js +36 -0
- package/build/esm/dev/vite/mastraObservability.js.map +1 -0
- package/build/esm/dev/vite/transform.js +79 -16
- package/build/esm/dev/vite/transform.js.map +1 -1
- package/build/esm/dev/workflows.js +4 -1
- package/build/esm/dev/workflows.js.map +1 -1
- package/build/esm/dev/wrapMethodWithSentry.js +7 -3
- package/build/esm/dev/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/dev/wrapRequestHandlerWithInit.js +2 -0
- package/build/esm/dev/wrapRequestHandlerWithInit.js.map +1 -1
- package/build/esm/prod/durableobject.js +6 -2
- package/build/esm/prod/durableobject.js.map +1 -1
- package/build/esm/prod/index.js +3 -2
- package/build/esm/prod/index.js.map +1 -1
- package/build/esm/prod/instrument.js +4 -1
- package/build/esm/prod/instrument.js.map +1 -1
- package/build/esm/prod/instrumentations/instrumentSqlStorage.js +3 -3
- package/build/esm/prod/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/esm/prod/instrumentations/instrumentWorkerEntrypoint.js +4 -1
- package/build/esm/prod/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/esm/prod/instrumentations/worker/instrumentD1.js +20 -18
- package/build/esm/prod/instrumentations/worker/instrumentD1.js.map +1 -1
- package/build/esm/prod/instrumentations/worker/instrumentEmail.js +6 -5
- package/build/esm/prod/instrumentations/worker/instrumentEmail.js.map +1 -1
- package/build/esm/prod/instrumentations/worker/instrumentScheduled.js +12 -7
- package/build/esm/prod/instrumentations/worker/instrumentScheduled.js.map +1 -1
- package/build/esm/prod/orchestrion-deferred-channels.js +35 -0
- package/build/esm/prod/orchestrion-deferred-channels.js.map +1 -0
- package/build/esm/prod/orchestrion-diagnostics-channel.js +77 -0
- package/build/esm/prod/orchestrion-diagnostics-channel.js.map +1 -0
- package/build/esm/prod/package.json +1 -1
- package/build/esm/prod/vite/agentClass.js +3 -2
- package/build/esm/prod/vite/agentClass.js.map +1 -1
- package/build/esm/prod/vite/autoInstrument.js +1 -1
- package/build/esm/prod/vite/autoInstrument.js.map +1 -1
- package/build/esm/prod/vite/index.js +6 -1
- package/build/esm/prod/vite/index.js.map +1 -1
- package/build/esm/prod/vite/mastraObservability.js +36 -0
- package/build/esm/prod/vite/mastraObservability.js.map +1 -0
- package/build/esm/prod/vite/transform.js +79 -16
- package/build/esm/prod/vite/transform.js.map +1 -1
- package/build/esm/prod/workflows.js +4 -1
- package/build/esm/prod/workflows.js.map +1 -1
- package/build/esm/prod/wrapMethodWithSentry.js +7 -3
- package/build/esm/prod/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/prod/wrapRequestHandlerWithInit.js +2 -0
- package/build/esm/prod/wrapRequestHandlerWithInit.js.map +1 -1
- package/build/types/durableobject.d.ts.map +1 -1
- package/build/types/index.d.ts +4 -2
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrument.d.ts +10 -0
- package/build/types/instrument.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentD1.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEmail.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentScheduled.d.ts.map +1 -1
- package/build/types/orchestrion-deferred-channels.d.ts +26 -0
- package/build/types/orchestrion-deferred-channels.d.ts.map +1 -0
- package/build/types/orchestrion-diagnostics-channel.d.ts +44 -0
- package/build/types/orchestrion-diagnostics-channel.d.ts.map +1 -0
- package/build/types/vite/agentClass.d.ts +4 -3
- package/build/types/vite/agentClass.d.ts.map +1 -1
- package/build/types/vite/autoInstrument.d.ts.map +1 -1
- package/build/types/vite/index.d.ts.map +1 -1
- package/build/types/vite/mastraObservability.d.ts +27 -0
- package/build/types/vite/mastraObservability.d.ts.map +1 -0
- package/build/types/vite/transform.d.ts +5 -4
- package/build/types/vite/transform.d.ts.map +1 -1
- package/build/types/workflows.d.ts.map +1 -1
- package/build/types/wrapMethodWithSentry.d.ts.map +1 -1
- package/build/types/wrapRequestHandlerWithInit.d.ts.map +1 -1
- package/package.json +10 -5
package/build/esm/prod/index.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SENTRY_SEGMENT_NAME_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, bindScopeToEmitter, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createTransport, dedupeIntegration, eventFiltersIntegration, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, growthbookIntegration, instrumentSupabaseClient, isEnabled, isInitialized, lastEventId, linkedErrorsIntegration, logger, metrics, moduleMetadataIntegration, requestDataIntegration, rewriteFramesIntegration, setAttribute, setAttributes, setContext, setConversationId, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, spanStreamingIntegration, spanToBaggageHeader, spanToJSON, spanToStaticSpanJSON, spanToTraceHeader, startInactiveSpan, startNewTrace, startSpan, startSpanManual, supabaseIntegration, suppressTracing, updateSpanName, withActiveSpan, withIsolationScope, withMonitor, withScope, withStaticSpan, withStreamedSpan, zodErrorsIntegration } from '@sentry/core';
|
|
2
|
-
export {
|
|
2
|
+
export { trpcMiddleware, wrapMcpServerWithSentry } from '@sentry/core/server';
|
|
3
|
+
export { createFlueInstrumentation, createLangChainCallbackHandler, eveConversationHook, getInstrumentedModuleNames, getOtlpTracesEndpoint, instrumentAnthropicAiClient, instrumentCreateReactAgent, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentMistralAiClient, instrumentOpenAiClient, instrumentPostgresJsSql, instrumentStateGraph, instrumentWorkersAiClient, openTelemetryIntegration, prismaIntegration, vercelAIIntegration } from '@sentry/server-utils';
|
|
3
4
|
export { withSentry } from './withSentry.js';
|
|
4
5
|
export { defineCloudflareOptions } from './defineCloudflareOptions.js';
|
|
5
6
|
export { instrumentAgentWithSentry, instrumentDurableObjectWithSentry } from './durableobject.js';
|
|
7
|
+
export { _INTERNAL_wrapUnlessInstrumented } from './instrument.js';
|
|
6
8
|
export { sentryPagesPlugin } from './pages-plugin.js';
|
|
7
9
|
export { CloudflareClient } from './client.js';
|
|
8
10
|
export { _INTERNAL_wrapRequestHandler, getDefaultIntegrations } from './sdk.js';
|
|
9
11
|
export { httpServerIntegration } from './integrations/httpServer.js';
|
|
10
12
|
export { fetchIntegration } from './integrations/fetch.js';
|
|
11
13
|
export { spotlightIntegration } from './integrations/spotlight.js';
|
|
12
|
-
export { createLangChainCallbackHandler, getOtlpTracesEndpoint, instrumentAnthropicAiClient, instrumentCreateReactAgent, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentOpenAiClient, instrumentStateGraph, instrumentWorkersAiClient, openTelemetryIntegration, prismaIntegration, vercelAIIntegration } from '@sentry/server-utils';
|
|
13
14
|
export { instrumentWorkflowWithSentry } from './workflows.js';
|
|
14
15
|
export { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils/no-diagnostic-channels';
|
|
15
16
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
|
|
@@ -43,6 +43,9 @@ function ensureInstrumented(original, instrumentFn, noMark) {
|
|
|
43
43
|
}
|
|
44
44
|
return instrumented;
|
|
45
45
|
}
|
|
46
|
+
function _INTERNAL_wrapUnlessInstrumented(wrap, optionsCallback, Class) {
|
|
47
|
+
return getInstrumented(Class) === Class ? Class : wrap(optionsCallback, Class);
|
|
48
|
+
}
|
|
46
49
|
|
|
47
|
-
export { ensureInstrumented, getInstrumented, markAsInstrumented };
|
|
50
|
+
export { _INTERNAL_wrapUnlessInstrumented, ensureInstrumented, getInstrumented, markAsInstrumented };
|
|
48
51
|
//# sourceMappingURL=instrument.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrument.js","sources":["../../../src/instrument.ts"],"sourcesContent":["// Use a global WeakMap to track instrumented objects across module instances.\n// This is important for Cloudflare Workers where the module may be bundled\n// separately for workers and Durable Objects, but they share the same global scope.\n// The WeakMap stores original -> instrumented mappings so we can retrieve the\n// instrumented version even if we only have a reference to the original.\nimport { isObjectLike } from '@sentry/core';\n\nconst GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getInstrumentedMap(): WeakMap<any, any> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObj = globalThis as typeof globalThis & { [GLOBAL_KEY]?: WeakMap<any, any> };\n if (!globalObj[GLOBAL_KEY]) {\n globalObj[GLOBAL_KEY] = new WeakMap();\n }\n return globalObj[GLOBAL_KEY];\n}\n\n/**\n * Check if a value can be used as a WeakMap key.\n * WeakMap keys must be objects or non-registered symbols.\n */\nfunction isWeakMapKey(value: unknown): value is object {\n return isObjectLike(value) || typeof value === 'function';\n}\n\n/**\n * Mark an object as instrumented, storing the instrumented version.\n * @param original The original uninstrumented object\n * @param instrumented The instrumented version (defaults to original if not provided)\n */\nexport function markAsInstrumented<T>(original: T, instrumented?: T): void {\n try {\n if (isWeakMapKey(original)) {\n // Store mapping from original to instrumented version\n // If instrumented is not provided, store original (for backwards compat)\n getInstrumentedMap().set(original, instrumented ?? original);\n }\n // Also mark the instrumented version itself so we recognize it\n if (isWeakMapKey(instrumented) && instrumented !== original) {\n getInstrumentedMap().set(instrumented, instrumented);\n }\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Get the instrumented version of an object, if available.\n * Returns the instrumented version if the object was previously instrumented,\n * or undefined if not found.\n */\nexport function getInstrumented<T>(obj: T): T | undefined {\n try {\n if (isWeakMapKey(obj)) {\n return getInstrumentedMap().get(obj) as T | undefined;\n }\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns the already-instrumented version of `original` if one exists,\n * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.\n *\n * @param noMark - If true, skips storing the original→instrumented mapping.\n */\nexport function ensureInstrumented<T>(original: T, instrumentFn: (original: T) => T, noMark?: boolean): T {\n const existing = getInstrumented(original);\n\n if (existing) {\n return existing;\n }\n\n const instrumented = instrumentFn(original);\n\n if (!noMark) {\n markAsInstrumented(original, instrumented);\n }\n\n return instrumented;\n}\n"],"names":[],"mappings":";;AAOA,MAAM,UAAA,GAAa,6BAAA;AAGnB,SAAS,kBAAA,GAAwC;AAE/C,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,IAAI,CAAC,SAAA,CAAU,UAAU,CAAA,EAAG;AAC1B,IAAA,SAAA,CAAU,UAAU,CAAA,mBAAI,IAAI,OAAA,EAAQ;AAAA,EACtC;AACA,EAAA,OAAO,UAAU,UAAU,CAAA;AAC7B;AAMA,SAAS,aAAa,KAAA,EAAiC;AACrD,EAAA,OAAO,YAAA,CAAa,KAAK,CAAA,IAAK,OAAO,KAAA,KAAU,UAAA;AACjD;AAOO,SAAS,kBAAA,CAAsB,UAAa,YAAA,EAAwB;AACzE,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,EAAG;AAG1B,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,QAAA,EAAU,YAAA,IAAgB,QAAQ,CAAA;AAAA,IAC7D;AAEA,IAAA,IAAI,YAAA,CAAa,YAAY,CAAA,IAAK,YAAA,KAAiB,QAAA,EAAU;AAC3D,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,YAAA,EAAc,YAAY,CAAA;AAAA,IACrD;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAOO,SAAS,gBAAmB,GAAA,EAAuB;AACxD,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,GAAG,CAAA,EAAG;AACrB,MAAA,OAAO,kBAAA,EAAmB,CAAE,GAAA,CAAI,GAAG,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAQO,SAAS,kBAAA,CAAsB,QAAA,EAAa,YAAA,EAAkC,MAAA,EAAqB;AACxG,EAAA,MAAM,QAAA,GAAW,gBAAgB,QAAQ,CAAA;AAEzC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,aAAa,QAAQ,CAAA;AAE1C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,kBAAA,CAAmB,UAAU,YAAY,CAAA;AAAA,EAC3C;AAEA,EAAA,OAAO,YAAA;AACT;;;;"}
|
|
1
|
+
{"version":3,"file":"instrument.js","sources":["../../../src/instrument.ts"],"sourcesContent":["// Use a global WeakMap to track instrumented objects across module instances.\n// This is important for Cloudflare Workers where the module may be bundled\n// separately for workers and Durable Objects, but they share the same global scope.\n// The WeakMap stores original -> instrumented mappings so we can retrieve the\n// instrumented version even if we only have a reference to the original.\nimport { isObjectLike } from '@sentry/core';\n\nconst GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getInstrumentedMap(): WeakMap<any, any> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObj = globalThis as typeof globalThis & { [GLOBAL_KEY]?: WeakMap<any, any> };\n if (!globalObj[GLOBAL_KEY]) {\n globalObj[GLOBAL_KEY] = new WeakMap();\n }\n return globalObj[GLOBAL_KEY];\n}\n\n/**\n * Check if a value can be used as a WeakMap key.\n * WeakMap keys must be objects or non-registered symbols.\n */\nfunction isWeakMapKey(value: unknown): value is object {\n return isObjectLike(value) || typeof value === 'function';\n}\n\n/**\n * Mark an object as instrumented, storing the instrumented version.\n * @param original The original uninstrumented object\n * @param instrumented The instrumented version (defaults to original if not provided)\n */\nexport function markAsInstrumented<T>(original: T, instrumented?: T): void {\n try {\n if (isWeakMapKey(original)) {\n // Store mapping from original to instrumented version\n // If instrumented is not provided, store original (for backwards compat)\n getInstrumentedMap().set(original, instrumented ?? original);\n }\n // Also mark the instrumented version itself so we recognize it\n if (isWeakMapKey(instrumented) && instrumented !== original) {\n getInstrumentedMap().set(instrumented, instrumented);\n }\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Get the instrumented version of an object, if available.\n * Returns the instrumented version if the object was previously instrumented,\n * or undefined if not found.\n */\nexport function getInstrumented<T>(obj: T): T | undefined {\n try {\n if (isWeakMapKey(obj)) {\n return getInstrumentedMap().get(obj) as T | undefined;\n }\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns the already-instrumented version of `original` if one exists,\n * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.\n *\n * @param noMark - If true, skips storing the original→instrumented mapping.\n */\nexport function ensureInstrumented<T>(original: T, instrumentFn: (original: T) => T, noMark?: boolean): T {\n const existing = getInstrumented(original);\n\n if (existing) {\n return existing;\n }\n\n const instrumented = instrumentFn(original);\n\n if (!noMark) {\n markAsInstrumented(original, instrumented);\n }\n\n return instrumented;\n}\n\n/**\n * Applies `wrap` to `Class` unless `Class` is already an instrumented wrapper.\n *\n * Emitted by the Vite auto-instrumentation transform for classes the worker entry only re-exports:\n * such a class may already be hand-wrapped with `instrument*WithSentry` in the module it comes\n * from, which the build cannot see. Wrapping again would nest two proxies and instrument the same\n * work twice, duplicated child spans, so the hand-wrapped class is returned as-is. Not part of the\n * public API, hand-written wrapper calls are deliberately left untouched by this guard.\n */\nexport function _INTERNAL_wrapUnlessInstrumented<C>(\n wrap: (optionsCallback: (env: never) => unknown, Class: C) => C,\n optionsCallback: (env: never) => unknown,\n Class: C,\n): C {\n return getInstrumented(Class) === Class ? Class : wrap(optionsCallback, Class);\n}\n"],"names":[],"mappings":";;AAOA,MAAM,UAAA,GAAa,6BAAA;AAGnB,SAAS,kBAAA,GAAwC;AAE/C,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,IAAI,CAAC,SAAA,CAAU,UAAU,CAAA,EAAG;AAC1B,IAAA,SAAA,CAAU,UAAU,CAAA,mBAAI,IAAI,OAAA,EAAQ;AAAA,EACtC;AACA,EAAA,OAAO,UAAU,UAAU,CAAA;AAC7B;AAMA,SAAS,aAAa,KAAA,EAAiC;AACrD,EAAA,OAAO,YAAA,CAAa,KAAK,CAAA,IAAK,OAAO,KAAA,KAAU,UAAA;AACjD;AAOO,SAAS,kBAAA,CAAsB,UAAa,YAAA,EAAwB;AACzE,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,EAAG;AAG1B,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,QAAA,EAAU,YAAA,IAAgB,QAAQ,CAAA;AAAA,IAC7D;AAEA,IAAA,IAAI,YAAA,CAAa,YAAY,CAAA,IAAK,YAAA,KAAiB,QAAA,EAAU;AAC3D,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,YAAA,EAAc,YAAY,CAAA;AAAA,IACrD;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAOO,SAAS,gBAAmB,GAAA,EAAuB;AACxD,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,GAAG,CAAA,EAAG;AACrB,MAAA,OAAO,kBAAA,EAAmB,CAAE,GAAA,CAAI,GAAG,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAQO,SAAS,kBAAA,CAAsB,QAAA,EAAa,YAAA,EAAkC,MAAA,EAAqB;AACxG,EAAA,MAAM,QAAA,GAAW,gBAAgB,QAAQ,CAAA;AAEzC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,aAAa,QAAQ,CAAA;AAE1C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,kBAAA,CAAmB,UAAU,YAAY,CAAA;AAAA,EAC3C;AAEA,EAAA,OAAO,YAAA;AACT;AAWO,SAAS,gCAAA,CACd,IAAA,EACA,eAAA,EACA,KAAA,EACG;AACH,EAAA,OAAO,gBAAgB,KAAK,CAAA,KAAM,QAAQ,KAAA,GAAQ,IAAA,CAAK,iBAAiB,KAAK,CAAA;AAC/E;;;;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SENTRY_OP } from '@sentry/conventions/attributes';
|
|
2
2
|
import { DB_QUERY } from '@sentry/conventions/op';
|
|
3
3
|
import { getClient, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
|
|
4
|
-
import {
|
|
4
|
+
import { sanitizeSqlQuery, getSqlQuerySummary } from '@sentry/server-utils';
|
|
5
5
|
import { targetsCloudflareInternalTable } from '../utils/internalSqlQuery.js';
|
|
6
6
|
|
|
7
7
|
function instrumentSqlStorage(sql) {
|
|
@@ -13,8 +13,8 @@ function instrumentSqlStorage(sql) {
|
|
|
13
13
|
}
|
|
14
14
|
return function(...args) {
|
|
15
15
|
const [query, ...bindings] = args;
|
|
16
|
-
const sanitizedQuery =
|
|
17
|
-
const querySummary =
|
|
16
|
+
const sanitizedQuery = sanitizeSqlQuery(query);
|
|
17
|
+
const querySummary = getSqlQuerySummary(sanitizedQuery);
|
|
18
18
|
const allowlist = getClient()?.getOptions()?.durableObjectSqlSpanAllowlist;
|
|
19
19
|
if (targetsCloudflareInternalTable(querySummary, allowlist, sanitizedQuery)) {
|
|
20
20
|
return original.apply(target, args);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentSqlStorage.js","sources":["../../../../src/instrumentations/instrumentSqlStorage.ts"],"sourcesContent":["import type { SqlStorage } from '@cloudflare/workers-types';\nimport { SENTRY_OP } from '@sentry/conventions/attributes';\nimport { DB_QUERY } from '@sentry/conventions/op';\nimport { getClient, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\nimport {
|
|
1
|
+
{"version":3,"file":"instrumentSqlStorage.js","sources":["../../../../src/instrumentations/instrumentSqlStorage.ts"],"sourcesContent":["import type { SqlStorage } from '@cloudflare/workers-types';\nimport { SENTRY_OP } from '@sentry/conventions/attributes';\nimport { DB_QUERY } from '@sentry/conventions/op';\nimport { getClient, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\nimport { getSqlQuerySummary, sanitizeSqlQuery } from '@sentry/server-utils';\nimport type { CloudflareClientOptions } from '../client';\nimport { targetsCloudflareInternalTable } from '../utils/internalSqlQuery';\n\n/**\n * Instruments the Durable Object SqlStorage `exec` method with Sentry spans.\n *\n * @param sql - The SqlStorage instance to instrument\n * @returns An instrumented SqlStorage instance\n */\nexport function instrumentSqlStorage(sql: SqlStorage): SqlStorage {\n return new Proxy(sql, {\n get(target, prop, _receiver) {\n const original = Reflect.get(target, prop, target);\n\n if (prop !== 'exec' || typeof original !== 'function') {\n return original;\n }\n\n return function (this: unknown, ...args: unknown[]) {\n const [query, ...bindings] = args as [string, ...unknown[]];\n\n const sanitizedQuery = sanitizeSqlQuery(query);\n const querySummary = getSqlQuerySummary(sanitizedQuery);\n\n // oxlint-disable-next-line typescript/no-unnecessary-type-assertion -- rule false positive: the cast reaches the Cloudflare-only `durableObjectSqlSpanAllowlist`; tsc errors without it\n const allowlist = (getClient()?.getOptions() as CloudflareClientOptions | undefined)\n ?.durableObjectSqlSpanAllowlist;\n\n if (targetsCloudflareInternalTable(querySummary, allowlist, sanitizedQuery)) {\n return (original as (...a: unknown[]) => ReturnType<SqlStorage['exec']>).apply(target, args);\n }\n\n return startSpan(\n {\n name: querySummary || sanitizedQuery,\n attributes: {\n [SENTRY_OP]: DB_QUERY,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.durable_object.sql',\n 'db.system.name': 'cloudflare-durable-object-sql',\n 'db.operation.name': 'exec',\n 'db.query.text': sanitizedQuery,\n 'db.query.summary': querySummary,\n 'cloudflare.durable_object.query.bindings': bindings.length,\n },\n },\n () => (original as (...a: unknown[]) => ReturnType<SqlStorage['exec']>).apply(target, args),\n );\n };\n },\n });\n}\n"],"names":[],"mappings":";;;;;;AAcO,SAAS,qBAAqB,GAAA,EAA6B;AAChE,EAAA,OAAO,IAAI,MAAM,GAAA,EAAK;AAAA,IACpB,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW;AAC3B,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,MAAM,MAAM,CAAA;AAEjD,MAAA,IAAI,IAAA,KAAS,MAAA,IAAU,OAAO,QAAA,KAAa,UAAA,EAAY;AACrD,QAAA,OAAO,QAAA;AAAA,MACT;AAEA,MAAA,OAAO,YAA4B,IAAA,EAAiB;AAClD,QAAA,MAAM,CAAC,KAAA,EAAO,GAAG,QAAQ,CAAA,GAAI,IAAA;AAE7B,QAAA,MAAM,cAAA,GAAiB,iBAAiB,KAAK,CAAA;AAC7C,QAAA,MAAM,YAAA,GAAe,mBAAmB,cAAc,CAAA;AAGtD,QAAA,MAAM,SAAA,GAAa,SAAA,EAAU,EAAG,UAAA,EAAW,EACvC,6BAAA;AAEJ,QAAA,IAAI,8BAAA,CAA+B,YAAA,EAAc,SAAA,EAAW,cAAc,CAAA,EAAG;AAC3E,UAAA,OAAQ,QAAA,CAAiE,KAAA,CAAM,MAAA,EAAQ,IAAI,CAAA;AAAA,QAC7F;AAEA,QAAA,OAAO,SAAA;AAAA,UACL;AAAA,YACE,MAAM,YAAA,IAAgB,cAAA;AAAA,YACtB,UAAA,EAAY;AAAA,cACV,CAAC,SAAS,GAAG,QAAA;AAAA,cACb,CAAC,gCAAgC,GAAG,uCAAA;AAAA,cACpC,gBAAA,EAAkB,+BAAA;AAAA,cAClB,mBAAA,EAAqB,MAAA;AAAA,cACrB,eAAA,EAAiB,cAAA;AAAA,cACjB,kBAAA,EAAoB,YAAA;AAAA,cACpB,4CAA4C,QAAA,CAAS;AAAA;AACvD,WACF;AAAA,UACA,MAAO,QAAA,CAAiE,KAAA,CAAM,MAAA,EAAQ,IAAI;AAAA,SAC5F;AAAA,MACF,CAAA;AAAA,IACF;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RPC } from '@sentry/conventions/op';
|
|
2
2
|
import { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils/no-diagnostic-channels';
|
|
3
|
+
import { markAsInstrumented } from '../instrument.js';
|
|
3
4
|
import { getFinalOptions } from '../options.js';
|
|
4
5
|
import { instrumentContext } from '../utils/instrumentContext.js';
|
|
5
6
|
import { wrapMethodWithSentry } from '../wrapMethodWithSentry.js';
|
|
@@ -65,7 +66,7 @@ function instrumentMethod(instance, proxy, prop, method, options, context) {
|
|
|
65
66
|
}
|
|
66
67
|
function instrumentWorkerEntrypoint(optionsCallback, WorkerEntrypointClass) {
|
|
67
68
|
setAsyncLocalStorageAsyncContextStrategy();
|
|
68
|
-
|
|
69
|
+
const InstrumentedClass = new Proxy(WorkerEntrypointClass, {
|
|
69
70
|
construct(target, [ctx, env]) {
|
|
70
71
|
const context = instrumentContext(ctx);
|
|
71
72
|
const options = getFinalOptions(optionsCallback(env), env);
|
|
@@ -124,6 +125,8 @@ function instrumentWorkerEntrypoint(optionsCallback, WorkerEntrypointClass) {
|
|
|
124
125
|
return proxy;
|
|
125
126
|
}
|
|
126
127
|
});
|
|
128
|
+
markAsInstrumented(InstrumentedClass);
|
|
129
|
+
return InstrumentedClass;
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
export { instrumentWorkerEntrypoint };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentWorkerEntrypoint.js","sources":["../../../../src/instrumentations/instrumentWorkerEntrypoint.ts"],"sourcesContent":["import type { RpcStub, WorkerEntrypoint } from 'cloudflare:workers';\nimport { RPC } from '@sentry/conventions/op';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils/no-diagnostic-channels';\nimport type { CloudflareOptions } from '../client';\nimport { getFinalOptions } from '../options';\nimport type { DefaultEnv, ResolveEnv, StrictCloudflareOptions } from '../types';\nimport { instrumentContext } from '../utils/instrumentContext';\nimport { type UncheckedMethod, wrapMethodWithSentry } from '../wrapMethodWithSentry';\nimport { instrumentEnv } from './worker/instrumentEnv';\nimport { instrumentWorkerEntrypointFetch } from './worker/instrumentFetch';\nimport { instrumentWorkerEntrypointQueue } from './worker/instrumentQueue';\nimport { instrumentWorkerEntrypointScheduled } from './worker/instrumentScheduled';\nimport { instrumentWorkerEntrypointTail } from './worker/instrumentTail';\n\nconst WORKER_ENTRYPOINT_ORIGIN = 'auto.faas.cloudflare.worker_entrypoint';\n\ntype ReservedMethod =\n | Exclude<Extract<keyof WorkerEntrypoint, string>, '__WORKER_ENTRYPOINT_BRAND'>\n | Extract<keyof ExportedHandler, string>\n | Exclude<Extract<keyof RpcStub<(...args: unknown[]) => unknown>, string>, '__RPC_STUB_BRAND'>\n | 'constructor';\n\nconst RESERVED_METHODS = new Set<string>([\n 'connect',\n 'constructor',\n 'dup',\n 'email',\n 'fetch',\n 'queue',\n 'scheduled',\n 'tail',\n 'tailStream',\n 'test',\n 'trace',\n] satisfies ReservedMethod[]);\n\ninterface CachedMethod {\n source: UncheckedMethod;\n wrapped: UncheckedMethod;\n}\n\nexport type WorkerEntrypointConstructor<Env = unknown, Props = {}> = new (\n ctx: ExecutionContext,\n // WorkerEntrypoint subclasses can define different `env` shapes, so this constructor must accept all of them.\n // oxlint-disable-next-line typescript/no-explicit-any\n env: any,\n) => InstanceType<typeof WorkerEntrypoint<Env, Props>>;\n\nfunction isPrototypeMethod(instance: object, prop: string, method: UncheckedMethod): boolean {\n let prototype = Object.getPrototypeOf(instance);\n\n while (prototype && prototype !== Object.prototype) {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, prop);\n if (descriptor) {\n return descriptor.value === method;\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n\n return false;\n}\n\nfunction bindToInstance(instance: object, proxy: object, method: UncheckedMethod): UncheckedMethod {\n return new Proxy(method, {\n apply(target, thisArg, args) {\n return Reflect.apply(target, thisArg === proxy ? instance : thisArg, args);\n },\n });\n}\n\nfunction instrumentMethod(\n instance: object,\n proxy: object,\n prop: PropertyKey,\n method: UncheckedMethod,\n options: CloudflareOptions,\n context: ExecutionContext,\n): UncheckedMethod {\n const ownDescriptor = Object.getOwnPropertyDescriptor(instance, prop);\n if (ownDescriptor && 'value' in ownDescriptor && !ownDescriptor.configurable && !ownDescriptor.writable) {\n return method;\n }\n\n const boundMethod = bindToInstance(instance, proxy, method);\n\n if (typeof prop !== 'string' || RESERVED_METHODS.has(prop) || !isPrototypeMethod(instance, prop, method)) {\n return boundMethod;\n }\n\n return wrapMethodWithSentry(\n {\n options,\n context,\n spanName: rpcMeta => (rpcMeta ? prop : undefined),\n spanOp: RPC,\n origin: WORKER_ENTRYPOINT_ORIGIN,\n },\n boundMethod,\n undefined,\n true,\n );\n}\n\n/**\n * Instruments a WorkerEntrypoint class to capture errors and performance data.\n *\n * Instruments the following methods (same as `withSentry` for ExportedHandler):\n * - fetch (HTTP requests)\n * - scheduled (cron triggers)\n * - queue (queue consumers)\n * - email (email handlers)\n * - tail (tail workers)\n *\n * as well as any other public RPC methods on the WorkerEntrypoint instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param WorkerEntrypointClass The WorkerEntrypoint class to instrument.\n * @returns The instrumented WorkerEntrypoint class.\n *\n * @example\n * ```ts\n * class MyWorkerBase extends WorkerEntrypoint<Env> {\n * async fetch(request: Request): Promise<Response> {\n * return new Response('Hello World!');\n * }\n *\n * async myRpcMethod(arg: string): Promise<string> {\n * return `Hello ${arg}!`;\n * }\n * }\n *\n * export default instrumentWorkerEntrypoint(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyWorkerBase,\n * );\n * ```\n */\nexport function instrumentWorkerEntrypoint<\n Env = DefaultEnv,\n Props = {},\n // oxlint-disable-next-line typescript/no-explicit-any\n T extends WorkerEntrypoint<any, any> = WorkerEntrypoint<Env, Props>,\n // oxlint-disable-next-line typescript/no-explicit-any\n C extends new (ctx: ExecutionContext, env: any) => T = new (ctx: ExecutionContext, env: any) => T,\n O = unknown,\n>(optionsCallback: (env: ResolveEnv<C, Env>) => StrictCloudflareOptions<O> | undefined, WorkerEntrypointClass: C): C {\n // Set up AsyncLocalStorage strategy ONCE at instrumentation time, not per-request\n // This is critical - calling this per-request would create a new AsyncLocalStorage\n // each time, breaking scope isolation for concurrent requests\n setAsyncLocalStorageAsyncContextStrategy();\n\n return new Proxy(WorkerEntrypointClass, {\n construct(target, [ctx, env]) {\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n const obj = new target(context, instrumentedEnv);\n\n // Override this.ctx to ensure the instrumented context is used\n // This is necessary because the base WorkerEntrypoint class sets this.ctx\n // from the constructor parameter, but we want users accessing this.ctx\n // to get the instrumented version\n if ('ctx' in obj) {\n Object.defineProperty(obj, 'ctx', {\n value: context,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n if ('env' in obj) {\n Object.defineProperty(obj, 'env', {\n value: instrumentedEnv,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n const entrypoint = obj as WorkerEntrypoint;\n instrumentWorkerEntrypointFetch(entrypoint, options, context);\n instrumentWorkerEntrypointScheduled(entrypoint, options, context);\n instrumentWorkerEntrypointQueue(entrypoint, options, context);\n instrumentWorkerEntrypointTail(entrypoint, options, context);\n\n // workerd resolves RPC methods through property access.\n const methodCache = new Map<PropertyKey, CachedMethod>();\n\n const proxy: typeof obj = new Proxy(obj, {\n get(instance, prop) {\n const value = Reflect.get(instance, prop, instance);\n\n if (typeof value !== 'function') {\n return value;\n }\n\n const method = value as UncheckedMethod;\n\n const cached = methodCache.get(prop);\n if (cached?.source === method) {\n return cached.wrapped;\n }\n\n const wrapped = instrumentMethod(instance, proxy, prop, method, options, context);\n methodCache.set(prop, { source: method, wrapped });\n return wrapped;\n },\n });\n\n return proxy;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instrumentWorkerEntrypoint.js","sources":["../../../../src/instrumentations/instrumentWorkerEntrypoint.ts"],"sourcesContent":["import type { RpcStub, WorkerEntrypoint } from 'cloudflare:workers';\nimport { RPC } from '@sentry/conventions/op';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils/no-diagnostic-channels';\nimport type { CloudflareOptions } from '../client';\nimport { markAsInstrumented } from '../instrument';\nimport { getFinalOptions } from '../options';\nimport type { DefaultEnv, ResolveEnv, StrictCloudflareOptions } from '../types';\nimport { instrumentContext } from '../utils/instrumentContext';\nimport { type UncheckedMethod, wrapMethodWithSentry } from '../wrapMethodWithSentry';\nimport { instrumentEnv } from './worker/instrumentEnv';\nimport { instrumentWorkerEntrypointFetch } from './worker/instrumentFetch';\nimport { instrumentWorkerEntrypointQueue } from './worker/instrumentQueue';\nimport { instrumentWorkerEntrypointScheduled } from './worker/instrumentScheduled';\nimport { instrumentWorkerEntrypointTail } from './worker/instrumentTail';\n\nconst WORKER_ENTRYPOINT_ORIGIN = 'auto.faas.cloudflare.worker_entrypoint';\n\ntype ReservedMethod =\n | Exclude<Extract<keyof WorkerEntrypoint, string>, '__WORKER_ENTRYPOINT_BRAND'>\n | Extract<keyof ExportedHandler, string>\n | Exclude<Extract<keyof RpcStub<(...args: unknown[]) => unknown>, string>, '__RPC_STUB_BRAND'>\n | 'constructor';\n\nconst RESERVED_METHODS = new Set<string>([\n 'connect',\n 'constructor',\n 'dup',\n 'email',\n 'fetch',\n 'queue',\n 'scheduled',\n 'tail',\n 'tailStream',\n 'test',\n 'trace',\n] satisfies ReservedMethod[]);\n\ninterface CachedMethod {\n source: UncheckedMethod;\n wrapped: UncheckedMethod;\n}\n\nexport type WorkerEntrypointConstructor<Env = unknown, Props = {}> = new (\n ctx: ExecutionContext,\n // WorkerEntrypoint subclasses can define different `env` shapes, so this constructor must accept all of them.\n // oxlint-disable-next-line typescript/no-explicit-any\n env: any,\n) => InstanceType<typeof WorkerEntrypoint<Env, Props>>;\n\nfunction isPrototypeMethod(instance: object, prop: string, method: UncheckedMethod): boolean {\n let prototype = Object.getPrototypeOf(instance);\n\n while (prototype && prototype !== Object.prototype) {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, prop);\n if (descriptor) {\n return descriptor.value === method;\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n\n return false;\n}\n\nfunction bindToInstance(instance: object, proxy: object, method: UncheckedMethod): UncheckedMethod {\n return new Proxy(method, {\n apply(target, thisArg, args) {\n return Reflect.apply(target, thisArg === proxy ? instance : thisArg, args);\n },\n });\n}\n\nfunction instrumentMethod(\n instance: object,\n proxy: object,\n prop: PropertyKey,\n method: UncheckedMethod,\n options: CloudflareOptions,\n context: ExecutionContext,\n): UncheckedMethod {\n const ownDescriptor = Object.getOwnPropertyDescriptor(instance, prop);\n if (ownDescriptor && 'value' in ownDescriptor && !ownDescriptor.configurable && !ownDescriptor.writable) {\n return method;\n }\n\n const boundMethod = bindToInstance(instance, proxy, method);\n\n if (typeof prop !== 'string' || RESERVED_METHODS.has(prop) || !isPrototypeMethod(instance, prop, method)) {\n return boundMethod;\n }\n\n return wrapMethodWithSentry(\n {\n options,\n context,\n spanName: rpcMeta => (rpcMeta ? prop : undefined),\n spanOp: RPC,\n origin: WORKER_ENTRYPOINT_ORIGIN,\n },\n boundMethod,\n undefined,\n true,\n );\n}\n\n/**\n * Instruments a WorkerEntrypoint class to capture errors and performance data.\n *\n * Instruments the following methods (same as `withSentry` for ExportedHandler):\n * - fetch (HTTP requests)\n * - scheduled (cron triggers)\n * - queue (queue consumers)\n * - email (email handlers)\n * - tail (tail workers)\n *\n * as well as any other public RPC methods on the WorkerEntrypoint instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param WorkerEntrypointClass The WorkerEntrypoint class to instrument.\n * @returns The instrumented WorkerEntrypoint class.\n *\n * @example\n * ```ts\n * class MyWorkerBase extends WorkerEntrypoint<Env> {\n * async fetch(request: Request): Promise<Response> {\n * return new Response('Hello World!');\n * }\n *\n * async myRpcMethod(arg: string): Promise<string> {\n * return `Hello ${arg}!`;\n * }\n * }\n *\n * export default instrumentWorkerEntrypoint(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyWorkerBase,\n * );\n * ```\n */\nexport function instrumentWorkerEntrypoint<\n Env = DefaultEnv,\n Props = {},\n // oxlint-disable-next-line typescript/no-explicit-any\n T extends WorkerEntrypoint<any, any> = WorkerEntrypoint<Env, Props>,\n // oxlint-disable-next-line typescript/no-explicit-any\n C extends new (ctx: ExecutionContext, env: any) => T = new (ctx: ExecutionContext, env: any) => T,\n O = unknown,\n>(optionsCallback: (env: ResolveEnv<C, Env>) => StrictCloudflareOptions<O> | undefined, WorkerEntrypointClass: C): C {\n // Set up AsyncLocalStorage strategy ONCE at instrumentation time, not per-request\n // This is critical - calling this per-request would create a new AsyncLocalStorage\n // each time, breaking scope isolation for concurrent requests\n setAsyncLocalStorageAsyncContextStrategy();\n\n const InstrumentedClass = new Proxy(WorkerEntrypointClass, {\n construct(target, [ctx, env]) {\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n const obj = new target(context, instrumentedEnv);\n\n // Override this.ctx to ensure the instrumented context is used\n // This is necessary because the base WorkerEntrypoint class sets this.ctx\n // from the constructor parameter, but we want users accessing this.ctx\n // to get the instrumented version\n if ('ctx' in obj) {\n Object.defineProperty(obj, 'ctx', {\n value: context,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n if ('env' in obj) {\n Object.defineProperty(obj, 'env', {\n value: instrumentedEnv,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n const entrypoint = obj as WorkerEntrypoint;\n instrumentWorkerEntrypointFetch(entrypoint, options, context);\n instrumentWorkerEntrypointScheduled(entrypoint, options, context);\n instrumentWorkerEntrypointQueue(entrypoint, options, context);\n instrumentWorkerEntrypointTail(entrypoint, options, context);\n\n // workerd resolves RPC methods through property access.\n const methodCache = new Map<PropertyKey, CachedMethod>();\n\n const proxy: typeof obj = new Proxy(obj, {\n get(instance, prop) {\n const value = Reflect.get(instance, prop, instance);\n\n if (typeof value !== 'function') {\n return value;\n }\n\n const method = value as UncheckedMethod;\n\n const cached = methodCache.get(prop);\n if (cached?.source === method) {\n return cached.wrapped;\n }\n\n const wrapped = instrumentMethod(instance, proxy, prop, method, options, context);\n methodCache.set(prop, { source: method, wrapped });\n return wrapped;\n },\n });\n\n return proxy;\n },\n });\n // Recognizable for `_INTERNAL_wrapUnlessInstrumented`, so auto-instrumentation never nests wrappers.\n markAsInstrumented(InstrumentedClass);\n return InstrumentedClass;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SENTRY_OP } from '@sentry/conventions/attributes';
|
|
2
2
|
import { DB_QUERY } from '@sentry/conventions/op';
|
|
3
3
|
import { startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getClient, hasSpanStreamingEnabled, addBreadcrumb, SPAN_STATUS_ERROR } from '@sentry/core';
|
|
4
|
-
import {
|
|
4
|
+
import { sanitizeSqlQuery, getSqlQuerySummary } from '@sentry/server-utils';
|
|
5
5
|
import { ensureInstrumented } from '../../instrument.js';
|
|
6
6
|
|
|
7
7
|
const patchedStatement = /* @__PURE__ */ new WeakSet();
|
|
@@ -9,40 +9,41 @@ function instrumentD1PreparedStatementQueries(statement, query) {
|
|
|
9
9
|
if (patchedStatement.has(statement)) {
|
|
10
10
|
return statement;
|
|
11
11
|
}
|
|
12
|
+
const queryText = query ? sanitizeSqlQuery(query) : void 0;
|
|
12
13
|
statement.first = new Proxy(statement.first, {
|
|
13
14
|
apply(target, thisArg, args) {
|
|
14
|
-
return startSpan(createStartSpanOptions(
|
|
15
|
+
return startSpan(createStartSpanOptions(queryText, "first"), async () => {
|
|
15
16
|
const res = await Reflect.apply(target, thisArg, args);
|
|
16
|
-
createD1Breadcrumb(
|
|
17
|
+
createD1Breadcrumb(queryText, "first");
|
|
17
18
|
return res;
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
21
|
});
|
|
21
22
|
statement.run = new Proxy(statement.run, {
|
|
22
23
|
apply(target, thisArg, args) {
|
|
23
|
-
return startSpan(createStartSpanOptions(
|
|
24
|
+
return startSpan(createStartSpanOptions(queryText, "run"), async (span) => {
|
|
24
25
|
const d1Response = await Reflect.apply(target, thisArg, args);
|
|
25
26
|
applyD1ReturnObjectToSpan(span, d1Response);
|
|
26
|
-
createD1Breadcrumb(
|
|
27
|
+
createD1Breadcrumb(queryText, "run", d1Response);
|
|
27
28
|
return d1Response;
|
|
28
29
|
});
|
|
29
30
|
}
|
|
30
31
|
});
|
|
31
32
|
statement.all = new Proxy(statement.all, {
|
|
32
33
|
apply(target, thisArg, args) {
|
|
33
|
-
return startSpan(createStartSpanOptions(
|
|
34
|
+
return startSpan(createStartSpanOptions(queryText, "all"), async (span) => {
|
|
34
35
|
const d1Result = await Reflect.apply(target, thisArg, args);
|
|
35
36
|
applyD1ReturnObjectToSpan(span, d1Result);
|
|
36
|
-
createD1Breadcrumb(
|
|
37
|
+
createD1Breadcrumb(queryText, "all", d1Result);
|
|
37
38
|
return d1Result;
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
});
|
|
41
42
|
statement.raw = new Proxy(statement.raw, {
|
|
42
43
|
apply(target, thisArg, args) {
|
|
43
|
-
return startSpan(createStartSpanOptions(
|
|
44
|
+
return startSpan(createStartSpanOptions(queryText, "raw"), async () => {
|
|
44
45
|
const res = await Reflect.apply(target, thisArg, args);
|
|
45
|
-
createD1Breadcrumb(
|
|
46
|
+
createD1Breadcrumb(queryText, "raw");
|
|
46
47
|
return res;
|
|
47
48
|
});
|
|
48
49
|
}
|
|
@@ -71,27 +72,27 @@ function getAttributesFromD1Response(d1Result) {
|
|
|
71
72
|
"cloudflare.d1.rows_written": d1Result.meta.rows_written
|
|
72
73
|
};
|
|
73
74
|
}
|
|
74
|
-
function createD1Breadcrumb(
|
|
75
|
+
function createD1Breadcrumb(message, type, d1Result) {
|
|
75
76
|
addBreadcrumb({
|
|
76
77
|
category: "query",
|
|
77
|
-
message
|
|
78
|
+
message,
|
|
78
79
|
data: {
|
|
79
80
|
...d1Result ? getAttributesFromD1Response(d1Result) : {},
|
|
80
81
|
"db.operation.name": type
|
|
81
82
|
}
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
|
-
function createStartSpanOptions(
|
|
85
|
-
const querySummary =
|
|
85
|
+
function createStartSpanOptions(queryText, type) {
|
|
86
|
+
const querySummary = queryText ? getSqlQuerySummary(queryText) : void 0;
|
|
86
87
|
const client = getClient();
|
|
87
|
-
const name = client && hasSpanStreamingEnabled(client) ? querySummary || "cloudflare-d1" :
|
|
88
|
+
const name = client && hasSpanStreamingEnabled(client) ? querySummary || "cloudflare-d1" : queryText ?? "cloudflare-d1";
|
|
88
89
|
return {
|
|
89
90
|
name,
|
|
90
91
|
attributes: {
|
|
91
92
|
[SENTRY_OP]: DB_QUERY,
|
|
92
93
|
"db.system.name": "cloudflare-d1",
|
|
93
94
|
"db.operation.name": type,
|
|
94
|
-
"db.query.text":
|
|
95
|
+
"db.query.text": queryText,
|
|
95
96
|
"db.query.summary": querySummary,
|
|
96
97
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.db.cloudflare.d1"
|
|
97
98
|
}
|
|
@@ -109,7 +110,7 @@ function instrumentBatch(batch) {
|
|
|
109
110
|
return new Proxy(batch, {
|
|
110
111
|
apply(target, thisArg, args) {
|
|
111
112
|
const statements = args[0];
|
|
112
|
-
const queryText = statements.map((statement) => statement.statement ?? "").filter(Boolean).join("\n");
|
|
113
|
+
const queryText = statements.map((statement) => statement.statement ?? "").filter(Boolean).map((statement) => sanitizeSqlQuery(statement)).join("\n");
|
|
113
114
|
return startSpan(
|
|
114
115
|
{
|
|
115
116
|
name: "D1 batch",
|
|
@@ -142,9 +143,10 @@ function _instrumentD1(db) {
|
|
|
142
143
|
db.exec = new Proxy(db.exec, {
|
|
143
144
|
apply(target, thisArg, args) {
|
|
144
145
|
const [query] = args;
|
|
145
|
-
|
|
146
|
+
const queryText = query ? sanitizeSqlQuery(query) : void 0;
|
|
147
|
+
return startSpan(createStartSpanOptions(queryText, "exec"), async () => {
|
|
146
148
|
const res = await Reflect.apply(target, thisArg, args);
|
|
147
|
-
createD1Breadcrumb(
|
|
149
|
+
createD1Breadcrumb(queryText, "exec");
|
|
148
150
|
return res;
|
|
149
151
|
});
|
|
150
152
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentD1.js","sources":["../../../../../src/instrumentations/worker/instrumentD1.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport type { D1Database, D1DatabaseSession, D1PreparedStatement, D1Response } from '@cloudflare/workers-types';\nimport { SENTRY_OP } from '@sentry/conventions/attributes';\nimport { DB_QUERY } from '@sentry/conventions/op';\nimport type { Span, SpanAttributes, StartSpanOptions } from '@sentry/core';\nimport {\n addBreadcrumb,\n getClient,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startSpan,\n} from '@sentry/core';\nimport { _INTERNAL_getSqlQuerySummary, _INTERNAL_sanitizeSqlQuery } from '@sentry/core/server';\nimport { ensureInstrumented } from '../../instrument';\n\n// Patching is based on internal Cloudflare D1 API\n// https://github.com/cloudflare/workerd/blob/cd5279e7b305003f1d9c851e73efa9d67e4b68b2/src/cloudflare/internal/d1-api.ts\n\nconst patchedStatement = new WeakSet<D1PreparedStatement>();\n\n/**\n * Patches the query methods of a Cloudflare D1 prepared statement with Sentry.\n */\nfunction instrumentD1PreparedStatementQueries(statement: D1PreparedStatement, query: string): D1PreparedStatement {\n if (patchedStatement.has(statement)) {\n return statement;\n }\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.first = new Proxy(statement.first, {\n apply(target, thisArg, args: Parameters<typeof statement.first>) {\n return startSpan(createStartSpanOptions(query, 'first'), async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb(query, 'first');\n return res;\n });\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.run = new Proxy(statement.run, {\n apply(target, thisArg, args: Parameters<typeof statement.run>) {\n return startSpan(createStartSpanOptions(query, 'run'), async span => {\n const d1Response = await Reflect.apply(target, thisArg, args);\n applyD1ReturnObjectToSpan(span, d1Response);\n createD1Breadcrumb(query, 'run', d1Response);\n return d1Response;\n });\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.all = new Proxy(statement.all, {\n apply(target, thisArg, args: Parameters<typeof statement.all>) {\n return startSpan(createStartSpanOptions(query, 'all'), async span => {\n const d1Result = await Reflect.apply(target, thisArg, args);\n applyD1ReturnObjectToSpan(span, d1Result);\n createD1Breadcrumb(query, 'all', d1Result);\n return d1Result;\n });\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.raw = new Proxy(statement.raw, {\n apply(target, thisArg, args: Parameters<typeof statement.raw>) {\n return startSpan(createStartSpanOptions(query, 'raw'), async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb(query, 'raw');\n return res;\n });\n },\n });\n\n patchedStatement.add(statement);\n\n return statement;\n}\n\n/**\n * Instruments a Cloudflare D1 prepared statement with Sentry.\n *\n * This is meant to be used as a top-level call, under the hood it calls `instrumentD1PreparedStatementQueries`\n * to patch the query methods. The reason for this abstraction is to ensure that the `bind` method is also patched.\n */\nfunction instrumentD1PreparedStatement(statement: D1PreparedStatement, query: string): D1PreparedStatement {\n // statement.bind() returns a new instance of D1PreparedStatement, so we have to patch it as well.\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.bind = new Proxy(statement.bind, {\n apply(target, thisArg, args: Parameters<typeof statement.bind>) {\n return instrumentD1PreparedStatementQueries(Reflect.apply(target, thisArg, args), query);\n },\n });\n\n return instrumentD1PreparedStatementQueries(statement, query);\n}\n\n/**\n * Add D1Response meta information to a span.\n *\n * See: https://developers.cloudflare.com/d1/build-with-d1/d1-client-api/#return-object\n */\nfunction applyD1ReturnObjectToSpan(span: Span, d1Result: D1Response): void {\n if (!d1Result.success) {\n span.setStatus({ code: SPAN_STATUS_ERROR });\n }\n\n span.setAttributes(getAttributesFromD1Response(d1Result));\n}\n\nfunction getAttributesFromD1Response(d1Result: D1Response): SpanAttributes {\n return {\n 'cloudflare.d1.duration': d1Result.meta.duration,\n 'cloudflare.d1.rows_read': d1Result.meta.rows_read,\n 'cloudflare.d1.rows_written': d1Result.meta.rows_written,\n };\n}\n\ntype D1QueryType = 'first' | 'run' | 'all' | 'raw' | 'batch' | 'exec';\n\nfunction createD1Breadcrumb(query: string, type: D1QueryType, d1Result?: D1Response): void {\n addBreadcrumb({\n category: 'query',\n message: query,\n data: {\n ...(d1Result ? getAttributesFromD1Response(d1Result) : {}),\n 'db.operation.name': type,\n },\n });\n}\n\nfunction createStartSpanOptions(query: string, type: D1QueryType): StartSpanOptions {\n const querySummary = query ? _INTERNAL_getSqlQuerySummary(_INTERNAL_sanitizeSqlQuery(query)) : undefined;\n\n const client = getClient();\n const name = client && hasSpanStreamingEnabled(client) ? querySummary || 'cloudflare-d1' : query;\n\n return {\n name,\n attributes: {\n [SENTRY_OP]: DB_QUERY,\n 'db.system.name': 'cloudflare-d1',\n 'db.operation.name': type,\n 'db.query.text': query,\n 'db.query.summary': querySummary,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.d1',\n },\n };\n}\n\nfunction instrumentPrepare(\n prepare: D1Database['prepare'] | D1DatabaseSession['prepare'],\n): D1Database['prepare'] | D1DatabaseSession['prepare'] {\n return new Proxy(prepare, {\n apply(target, thisArg, args: Parameters<typeof prepare>) {\n const [query] = args;\n return instrumentD1PreparedStatement(Reflect.apply(target, thisArg, args), query);\n },\n });\n}\n\nfunction instrumentBatch(\n batch: D1Database['batch'] | D1DatabaseSession['batch'],\n): D1Database['batch'] | D1DatabaseSession['batch'] {\n return new Proxy(batch, {\n apply(target, thisArg, args: Parameters<typeof batch>) {\n const statements = args[0];\n // D1PreparedStatement exposes a `statement` property at runtime, but it's not in @cloudflare/workers-types.\n // https://github.com/cloudflare/workerd/blob/dc12d7650b4f5d4f9ba6a47aa45fad769cdf8db4/src/cloudflare/internal/d1-api.ts#L210\n const queryText = statements\n .map(statement => (statement as unknown as { statement?: string }).statement ?? '')\n .filter(Boolean)\n .join('\\n');\n\n return startSpan(\n {\n name: 'D1 batch',\n attributes: {\n [SENTRY_OP]: DB_QUERY,\n 'db.system.name': 'cloudflare-d1',\n 'db.operation.name': 'batch',\n 'db.query.text': queryText || undefined,\n 'db.operation.batch.size': statements.length,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.d1',\n },\n },\n async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb('D1 batch', 'batch');\n return res;\n },\n );\n },\n });\n}\n\nfunction instrumentD1Session(session: D1DatabaseSession): D1DatabaseSession {\n session.prepare = instrumentPrepare(session.prepare);\n session.batch = instrumentBatch(session.batch);\n return session;\n}\n\nfunction _instrumentD1(db: D1Database): D1Database {\n db.prepare = instrumentPrepare(db.prepare);\n db.batch = instrumentBatch(db.batch);\n\n db.exec = new Proxy(db.exec, {\n apply(target, thisArg, args: Parameters<typeof db.exec>) {\n const [query] = args;\n return startSpan(createStartSpanOptions(query, 'exec'), async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb(query, 'exec');\n return res;\n });\n },\n });\n\n if ('withSession' in db && typeof db.withSession === 'function') {\n db.withSession = new Proxy(db.withSession, {\n apply(target, thisArg, args: [unknown]) {\n return instrumentD1Session(Reflect.apply(target, thisArg, args) as D1DatabaseSession);\n },\n });\n }\n\n return db;\n}\n\nexport function instrumentD1(db: D1Database): D1Database {\n return ensureInstrumented(db, _instrumentD1);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instrumentD1.js","sources":["../../../../../src/instrumentations/worker/instrumentD1.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport type { D1Database, D1DatabaseSession, D1PreparedStatement, D1Response } from '@cloudflare/workers-types';\nimport { SENTRY_OP } from '@sentry/conventions/attributes';\nimport { DB_QUERY } from '@sentry/conventions/op';\nimport type { Span, SpanAttributes, StartSpanOptions } from '@sentry/core';\nimport {\n addBreadcrumb,\n getClient,\n hasSpanStreamingEnabled,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startSpan,\n} from '@sentry/core';\nimport { getSqlQuerySummary, sanitizeSqlQuery } from '@sentry/server-utils';\nimport { ensureInstrumented } from '../../instrument';\n\n// Patching is based on internal Cloudflare D1 API\n// https://github.com/cloudflare/workerd/blob/cd5279e7b305003f1d9c851e73efa9d67e4b68b2/src/cloudflare/internal/d1-api.ts\n\nconst patchedStatement = new WeakSet<D1PreparedStatement>();\n\n/**\n * Patches the query methods of a Cloudflare D1 prepared statement with Sentry.\n */\nfunction instrumentD1PreparedStatementQueries(statement: D1PreparedStatement, query: string): D1PreparedStatement {\n if (patchedStatement.has(statement)) {\n return statement;\n }\n\n const queryText = query ? sanitizeSqlQuery(query) : undefined;\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.first = new Proxy(statement.first, {\n apply(target, thisArg, args: Parameters<typeof statement.first>) {\n return startSpan(createStartSpanOptions(queryText, 'first'), async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb(queryText, 'first');\n return res;\n });\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.run = new Proxy(statement.run, {\n apply(target, thisArg, args: Parameters<typeof statement.run>) {\n return startSpan(createStartSpanOptions(queryText, 'run'), async span => {\n const d1Response = await Reflect.apply(target, thisArg, args);\n applyD1ReturnObjectToSpan(span, d1Response);\n createD1Breadcrumb(queryText, 'run', d1Response);\n return d1Response;\n });\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.all = new Proxy(statement.all, {\n apply(target, thisArg, args: Parameters<typeof statement.all>) {\n return startSpan(createStartSpanOptions(queryText, 'all'), async span => {\n const d1Result = await Reflect.apply(target, thisArg, args);\n applyD1ReturnObjectToSpan(span, d1Result);\n createD1Breadcrumb(queryText, 'all', d1Result);\n return d1Result;\n });\n },\n });\n\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.raw = new Proxy(statement.raw, {\n apply(target, thisArg, args: Parameters<typeof statement.raw>) {\n return startSpan(createStartSpanOptions(queryText, 'raw'), async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb(queryText, 'raw');\n return res;\n });\n },\n });\n\n patchedStatement.add(statement);\n\n return statement;\n}\n\n/**\n * Instruments a Cloudflare D1 prepared statement with Sentry.\n *\n * This is meant to be used as a top-level call, under the hood it calls `instrumentD1PreparedStatementQueries`\n * to patch the query methods. The reason for this abstraction is to ensure that the `bind` method is also patched.\n */\nfunction instrumentD1PreparedStatement(statement: D1PreparedStatement, query: string): D1PreparedStatement {\n // statement.bind() returns a new instance of D1PreparedStatement, so we have to patch it as well.\n // eslint-disable-next-line @typescript-eslint/unbound-method\n statement.bind = new Proxy(statement.bind, {\n apply(target, thisArg, args: Parameters<typeof statement.bind>) {\n return instrumentD1PreparedStatementQueries(Reflect.apply(target, thisArg, args), query);\n },\n });\n\n return instrumentD1PreparedStatementQueries(statement, query);\n}\n\n/**\n * Add D1Response meta information to a span.\n *\n * See: https://developers.cloudflare.com/d1/build-with-d1/d1-client-api/#return-object\n */\nfunction applyD1ReturnObjectToSpan(span: Span, d1Result: D1Response): void {\n if (!d1Result.success) {\n span.setStatus({ code: SPAN_STATUS_ERROR });\n }\n\n span.setAttributes(getAttributesFromD1Response(d1Result));\n}\n\nfunction getAttributesFromD1Response(d1Result: D1Response): SpanAttributes {\n return {\n 'cloudflare.d1.duration': d1Result.meta.duration,\n 'cloudflare.d1.rows_read': d1Result.meta.rows_read,\n 'cloudflare.d1.rows_written': d1Result.meta.rows_written,\n };\n}\n\ntype D1QueryType = 'first' | 'run' | 'all' | 'raw' | 'batch' | 'exec';\n\n/** The message is the span's query text (already sanitized) or a static label such as `D1 batch`. */\nfunction createD1Breadcrumb(message: string | undefined, type: D1QueryType, d1Result?: D1Response): void {\n addBreadcrumb({\n category: 'query',\n message,\n data: {\n ...(d1Result ? getAttributesFromD1Response(d1Result) : {}),\n 'db.operation.name': type,\n },\n });\n}\n\nfunction createStartSpanOptions(queryText: string | undefined, type: D1QueryType): StartSpanOptions {\n const querySummary = queryText ? getSqlQuerySummary(queryText) : undefined;\n\n const client = getClient();\n const name =\n client && hasSpanStreamingEnabled(client) ? querySummary || 'cloudflare-d1' : (queryText ?? 'cloudflare-d1');\n\n return {\n name,\n attributes: {\n [SENTRY_OP]: DB_QUERY,\n 'db.system.name': 'cloudflare-d1',\n 'db.operation.name': type,\n 'db.query.text': queryText,\n 'db.query.summary': querySummary,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.d1',\n },\n };\n}\n\nfunction instrumentPrepare(\n prepare: D1Database['prepare'] | D1DatabaseSession['prepare'],\n): D1Database['prepare'] | D1DatabaseSession['prepare'] {\n return new Proxy(prepare, {\n apply(target, thisArg, args: Parameters<typeof prepare>) {\n const [query] = args;\n return instrumentD1PreparedStatement(Reflect.apply(target, thisArg, args), query);\n },\n });\n}\n\nfunction instrumentBatch(\n batch: D1Database['batch'] | D1DatabaseSession['batch'],\n): D1Database['batch'] | D1DatabaseSession['batch'] {\n return new Proxy(batch, {\n apply(target, thisArg, args: Parameters<typeof batch>) {\n const statements = args[0];\n // D1PreparedStatement exposes a `statement` property at runtime, but it's not in @cloudflare/workers-types.\n // https://github.com/cloudflare/workerd/blob/dc12d7650b4f5d4f9ba6a47aa45fad769cdf8db4/src/cloudflare/internal/d1-api.ts#L210\n const queryText = statements\n .map(statement => (statement as unknown as { statement?: string }).statement ?? '')\n .filter(Boolean)\n .map(statement => sanitizeSqlQuery(statement))\n .join('\\n');\n\n return startSpan(\n {\n name: 'D1 batch',\n attributes: {\n [SENTRY_OP]: DB_QUERY,\n 'db.system.name': 'cloudflare-d1',\n 'db.operation.name': 'batch',\n 'db.query.text': queryText || undefined,\n 'db.operation.batch.size': statements.length,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.cloudflare.d1',\n },\n },\n async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb('D1 batch', 'batch');\n return res;\n },\n );\n },\n });\n}\n\nfunction instrumentD1Session(session: D1DatabaseSession): D1DatabaseSession {\n session.prepare = instrumentPrepare(session.prepare);\n session.batch = instrumentBatch(session.batch);\n return session;\n}\n\nfunction _instrumentD1(db: D1Database): D1Database {\n db.prepare = instrumentPrepare(db.prepare);\n db.batch = instrumentBatch(db.batch);\n\n db.exec = new Proxy(db.exec, {\n apply(target, thisArg, args: Parameters<typeof db.exec>) {\n const [query] = args;\n const queryText = query ? sanitizeSqlQuery(query) : undefined;\n return startSpan(createStartSpanOptions(queryText, 'exec'), async () => {\n const res = await Reflect.apply(target, thisArg, args);\n createD1Breadcrumb(queryText, 'exec');\n return res;\n });\n },\n });\n\n if ('withSession' in db && typeof db.withSession === 'function') {\n db.withSession = new Proxy(db.withSession, {\n apply(target, thisArg, args: [unknown]) {\n return instrumentD1Session(Reflect.apply(target, thisArg, args) as D1DatabaseSession);\n },\n });\n }\n\n return db;\n}\n\nexport function instrumentD1(db: D1Database): D1Database {\n return ensureInstrumented(db, _instrumentD1);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SENTRY_SEGMENT_NAME_SOURCE, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
1
|
+
import { SENTRY_SEGMENT_NAME_SOURCE, SENTRY_ORIGIN, FAAS_TRIGGER, CODE_FUNCTION_NAME, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
2
2
|
import { FUNCTION } from '@sentry/conventions/op';
|
|
3
|
-
import { withIsolationScope, startSpan,
|
|
3
|
+
import { withIsolationScope, startSpan, captureException } from '@sentry/core';
|
|
4
4
|
import { flushAndDispose } from '../../flush.js';
|
|
5
5
|
import { ensureInstrumented } from '../../instrument.js';
|
|
6
6
|
import { getFinalOptions } from '../../options.js';
|
|
@@ -19,11 +19,12 @@ function wrapEmailHandler(emailMessage, options, context, fn) {
|
|
|
19
19
|
addCloudResourceContext(isolationScope);
|
|
20
20
|
return startSpan(
|
|
21
21
|
{
|
|
22
|
-
name:
|
|
22
|
+
name: "email",
|
|
23
23
|
attributes: {
|
|
24
24
|
[SENTRY_OP]: FUNCTION,
|
|
25
|
-
|
|
26
|
-
[
|
|
25
|
+
[CODE_FUNCTION_NAME]: "email",
|
|
26
|
+
[FAAS_TRIGGER]: "email",
|
|
27
|
+
[SENTRY_ORIGIN]: "auto.faas.cloudflare.email",
|
|
27
28
|
[SENTRY_SEGMENT_NAME_SOURCE]: "task"
|
|
28
29
|
}
|
|
29
30
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentEmail.js","sources":["../../../../../src/instrumentations/worker/instrumentEmail.ts"],"sourcesContent":["import type { EmailMessage } from '@cloudflare/workers-types';\nimport type { AnyExportedHandler } from '../../types';\nimport type { env as cloudflareEnv } from 'cloudflare:workers';\nimport {
|
|
1
|
+
{"version":3,"file":"instrumentEmail.js","sources":["../../../../../src/instrumentations/worker/instrumentEmail.ts"],"sourcesContent":["import type { EmailMessage } from '@cloudflare/workers-types';\nimport type { AnyExportedHandler } from '../../types';\nimport type { env as cloudflareEnv } from 'cloudflare:workers';\nimport {\n SENTRY_SEGMENT_NAME_SOURCE,\n CODE_FUNCTION_NAME,\n SENTRY_OP,\n FAAS_TRIGGER,\n SENTRY_ORIGIN,\n} from '@sentry/conventions/attributes';\nimport { FUNCTION } from '@sentry/conventions/op';\nimport { captureException, startSpan, withIsolationScope } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { flushAndDispose } from '../../flush';\nimport { ensureInstrumented } from '../../instrument';\nimport { getFinalOptions } from '../../options';\nimport { addCloudResourceContext } from '../../scope-utils';\nimport { init } from '../../sdk';\nimport { instrumentContext } from '../../utils/instrumentContext';\nimport { setInvocationState } from '../../utils/invocationContext';\nimport { instrumentEnv } from './instrumentEnv';\n\n/**\n * Core email handler logic - wraps execution with Sentry instrumentation.\n */\nfunction wrapEmailHandler(\n emailMessage: EmailMessage,\n options: CloudflareOptions,\n context: ExecutionContext,\n fn: () => unknown,\n): unknown {\n return withIsolationScope(isolationScope => {\n const waitUntil = context.waitUntil.bind(context);\n\n setInvocationState(isolationScope, { ctx: context });\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return startSpan(\n {\n name: 'email',\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: 'email',\n [FAAS_TRIGGER]: 'email',\n [SENTRY_ORIGIN]: 'auto.faas.cloudflare.email',\n [SENTRY_SEGMENT_NAME_SOURCE]: 'task',\n },\n },\n async () => {\n try {\n return await fn();\n } catch (e) {\n captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.email' } });\n throw e;\n } finally {\n waitUntil(flushAndDispose(client));\n }\n },\n );\n });\n}\n\n/**\n * Instruments an email handler for ExportedHandler (env/ctx come from args).\n */\nexport function instrumentExportedHandlerEmail<T extends AnyExportedHandler>(\n handler: T,\n optionsCallback: (env: typeof cloudflareEnv) => CloudflareOptions | undefined,\n): void {\n if (!('email' in handler) || typeof handler.email !== 'function') {\n return;\n }\n\n handler.email = ensureInstrumented(\n handler.email,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args: Parameters<NonNullable<T['email']>>) {\n const [emailMessage, env, ctx] = args;\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n args[1] = instrumentEnv(env, options);\n args[2] = context;\n\n return wrapEmailHandler(emailMessage, options, context, () => target.apply(thisArg, args));\n },\n }),\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;;AAyBA,SAAS,gBAAA,CACP,YAAA,EACA,OAAA,EACA,OAAA,EACA,EAAA,EACS;AACT,EAAA,OAAO,mBAAmB,CAAA,cAAA,KAAkB;AAC1C,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA,CAAU,IAAA,CAAK,OAAO,CAAA;AAEhD,IAAA,kBAAA,CAAmB,cAAA,EAAgB,EAAE,GAAA,EAAK,OAAA,EAAS,CAAA;AAEnD,IAAA,MAAM,SAAS,IAAA,CAAK,EAAE,GAAG,OAAA,EAAS,GAAA,EAAK,SAAS,CAAA;AAChD,IAAA,cAAA,CAAe,UAAU,MAAM,CAAA;AAE/B,IAAA,uBAAA,CAAwB,cAAc,CAAA;AAEtC,IAAA,OAAO,SAAA;AAAA,MACL;AAAA,QACE,IAAA,EAAM,OAAA;AAAA,QACN,UAAA,EAAY;AAAA,UACV,CAAC,SAAS,GAAG,QAAA;AAAA,UACb,CAAC,kBAAkB,GAAG,OAAA;AAAA,UACtB,CAAC,YAAY,GAAG,OAAA;AAAA,UAChB,CAAC,aAAa,GAAG,4BAAA;AAAA,UACjB,CAAC,0BAA0B,GAAG;AAAA;AAChC,OACF;AAAA,MACA,YAAY;AACV,QAAA,IAAI;AACF,UAAA,OAAO,MAAM,EAAA,EAAG;AAAA,QAClB,SAAS,CAAA,EAAG;AACV,UAAA,gBAAA,CAAiB,CAAA,EAAG,EAAE,SAAA,EAAW,EAAE,SAAS,KAAA,EAAO,IAAA,EAAM,4BAAA,EAA6B,EAAG,CAAA;AACzF,UAAA,MAAM,CAAA;AAAA,QACR,CAAA,SAAE;AACA,UAAA,SAAA,CAAU,eAAA,CAAgB,MAAM,CAAC,CAAA;AAAA,QACnC;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AACH;AAKO,SAAS,8BAAA,CACd,SACA,eAAA,EACM;AACN,EAAA,IAAI,EAAE,OAAA,IAAW,OAAA,CAAA,IAAY,OAAO,OAAA,CAAQ,UAAU,UAAA,EAAY;AAChE,IAAA;AAAA,EACF;AAEA,EAAA,OAAA,CAAQ,KAAA,GAAQ,kBAAA;AAAA,IACd,OAAA,CAAQ,KAAA;AAAA,IACR,CAAA,QAAA,KACE,IAAI,KAAA,CAAM,QAAA,EAAU;AAAA,MAClB,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,IAAA,EAA2C;AAChE,QAAA,MAAM,CAAC,YAAA,EAAc,GAAA,EAAK,GAAG,CAAA,GAAI,IAAA;AACjC,QAAA,MAAM,OAAA,GAAU,kBAAkB,GAAG,CAAA;AACrC,QAAA,MAAM,OAAA,GAAU,eAAA,CAAgB,eAAA,CAAgB,GAAG,GAAG,GAAG,CAAA;AACzD,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,aAAA,CAAc,GAAA,EAAK,OAAO,CAAA;AACpC,QAAA,IAAA,CAAK,CAAC,CAAA,GAAI,OAAA;AAEV,QAAA,OAAO,gBAAA,CAAiB,cAAc,OAAA,EAAS,OAAA,EAAS,MAAM,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS,IAAI,CAAC,CAAA;AAAA,MAC3F;AAAA,KACD;AAAA,GACL;AACF;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { SENTRY_SEGMENT_NAME_SOURCE, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
1
|
+
import { SENTRY_SEGMENT_NAME_SOURCE, SENTRY_ORIGIN, FAAS_TRIGGER, FAAS_TIME, FAAS_CRON, CODE_FUNCTION_NAME, SENTRY_DESCRIPTION, SENTRY_OP } from '@sentry/conventions/attributes';
|
|
2
2
|
import { FUNCTION } from '@sentry/conventions/op';
|
|
3
|
-
import { withIsolationScope, startSpan,
|
|
3
|
+
import { withIsolationScope, startSpan, hasSpanStreamingEnabled, captureException } from '@sentry/core';
|
|
4
4
|
import { flushAndDispose } from '../../flush.js';
|
|
5
5
|
import { ensureInstrumented } from '../../instrument.js';
|
|
6
6
|
import { getFinalOptions } from '../../options.js';
|
|
@@ -17,15 +17,20 @@ function wrapScheduledHandler(controller, options, context, fn) {
|
|
|
17
17
|
const client = init({ ...options, ctx: context });
|
|
18
18
|
isolationScope.setClient(client);
|
|
19
19
|
addCloudResourceContext(isolationScope);
|
|
20
|
+
const description = `Scheduled Cron ${controller.cron}`;
|
|
20
21
|
return startSpan(
|
|
21
22
|
{
|
|
22
|
-
name:
|
|
23
|
+
name: client && hasSpanStreamingEnabled(client) ? "scheduled" : description,
|
|
23
24
|
attributes: {
|
|
24
25
|
[SENTRY_OP]: FUNCTION,
|
|
25
|
-
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
[
|
|
26
|
+
// override description inference by Relay to preserve the original (transaction-based) description.
|
|
27
|
+
// sentry-conventions can't map the special case for the "Scheduled Cron" prefix and the chron string.
|
|
28
|
+
[SENTRY_DESCRIPTION]: description,
|
|
29
|
+
[CODE_FUNCTION_NAME]: "scheduled",
|
|
30
|
+
[FAAS_CRON]: controller.cron,
|
|
31
|
+
[FAAS_TIME]: new Date(controller.scheduledTime).toISOString(),
|
|
32
|
+
[FAAS_TRIGGER]: "timer",
|
|
33
|
+
[SENTRY_ORIGIN]: "auto.faas.cloudflare.scheduled",
|
|
29
34
|
[SENTRY_SEGMENT_NAME_SOURCE]: "task"
|
|
30
35
|
}
|
|
31
36
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentScheduled.js","sources":["../../../../../src/instrumentations/worker/instrumentScheduled.ts"],"sourcesContent":["import type { ScheduledController } from '@cloudflare/workers-types';\nimport type { AnyExportedHandler } from '../../types';\nimport type { env as cloudflareEnv, WorkerEntrypoint } from 'cloudflare:workers';\nimport {
|
|
1
|
+
{"version":3,"file":"instrumentScheduled.js","sources":["../../../../../src/instrumentations/worker/instrumentScheduled.ts"],"sourcesContent":["import type { ScheduledController } from '@cloudflare/workers-types';\nimport type { AnyExportedHandler } from '../../types';\nimport type { env as cloudflareEnv, WorkerEntrypoint } from 'cloudflare:workers';\nimport {\n SENTRY_SEGMENT_NAME_SOURCE,\n CODE_FUNCTION_NAME,\n SENTRY_OP,\n FAAS_CRON,\n FAAS_TIME,\n FAAS_TRIGGER,\n SENTRY_DESCRIPTION,\n SENTRY_ORIGIN,\n} from '@sentry/conventions/attributes';\nimport { FUNCTION } from '@sentry/conventions/op';\nimport { captureException, hasSpanStreamingEnabled, startSpan, withIsolationScope } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { flushAndDispose } from '../../flush';\nimport { ensureInstrumented } from '../../instrument';\nimport { getFinalOptions } from '../../options';\nimport { addCloudResourceContext } from '../../scope-utils';\nimport { init } from '../../sdk';\nimport { instrumentContext } from '../../utils/instrumentContext';\nimport { setInvocationState } from '../../utils/invocationContext';\nimport { instrumentEnv } from './instrumentEnv';\n\nfunction wrapScheduledHandler(\n controller: ScheduledController,\n options: CloudflareOptions,\n context: ExecutionContext,\n fn: () => unknown,\n): unknown {\n return withIsolationScope(isolationScope => {\n const waitUntil = context.waitUntil.bind(context);\n\n setInvocationState(isolationScope, { ctx: context });\n\n const client = init({ ...options, ctx: context });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n const description = `Scheduled Cron ${controller.cron}`;\n\n return startSpan(\n {\n name: client && hasSpanStreamingEnabled(client) ? 'scheduled' : description,\n attributes: {\n [SENTRY_OP]: FUNCTION,\n // override description inference by Relay to preserve the original (transaction-based) description.\n // sentry-conventions can't map the special case for the \"Scheduled Cron\" prefix and the chron string.\n [SENTRY_DESCRIPTION]: description,\n [CODE_FUNCTION_NAME]: 'scheduled',\n [FAAS_CRON]: controller.cron,\n [FAAS_TIME]: new Date(controller.scheduledTime).toISOString(),\n [FAAS_TRIGGER]: 'timer',\n [SENTRY_ORIGIN]: 'auto.faas.cloudflare.scheduled',\n [SENTRY_SEGMENT_NAME_SOURCE]: 'task',\n },\n },\n async () => {\n try {\n return await fn();\n } catch (e) {\n captureException(e, { mechanism: { handled: false, type: 'auto.faas.cloudflare.scheduled' } });\n throw e;\n } finally {\n waitUntil(flushAndDispose(client));\n }\n },\n );\n });\n}\n\n/**\n * Instruments a scheduled handler for ExportedHandler (env/ctx come from args).\n */\nexport function instrumentExportedHandlerScheduled<T extends AnyExportedHandler>(\n handler: T,\n optionsCallback: (env: typeof cloudflareEnv) => CloudflareOptions | undefined,\n): void {\n if (!('scheduled' in handler) || typeof handler.scheduled !== 'function') {\n return;\n }\n\n handler.scheduled = ensureInstrumented(\n handler.scheduled,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args: Parameters<NonNullable<T['scheduled']>>) {\n const [controller, env, ctx] = args;\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n args[1] = instrumentEnv(env, options);\n args[2] = context;\n\n return wrapScheduledHandler(controller, options, context, () => target.apply(thisArg, args));\n },\n }),\n );\n}\n\n/**\n * Instruments a scheduled method for WorkerEntrypoint (options/context already available).\n */\nexport function instrumentWorkerEntrypointScheduled<T extends WorkerEntrypoint>(\n instance: T,\n options: CloudflareOptions,\n context: ExecutionContext,\n): void {\n if (!instance.scheduled) {\n return;\n }\n\n const original = instance.scheduled.bind(instance);\n instance.scheduled = new Proxy(original, {\n apply(target, thisArg, args: [ScheduledController]) {\n const [controller] = args;\n\n return wrapScheduledHandler(controller, options, context, () => Reflect.apply(target, thisArg, args));\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { debug } from '@sentry/core';
|
|
2
|
+
import { DEBUG_BUILD } from './debug-build.js';
|
|
3
|
+
|
|
4
|
+
const deferred = [];
|
|
5
|
+
const DEFERRED = /* @__PURE__ */ Symbol("sentryOrchestrionDeferred");
|
|
6
|
+
function isGlobalScopeError(error) {
|
|
7
|
+
return error instanceof Error && /within global scope/.test(error.message);
|
|
8
|
+
}
|
|
9
|
+
function deferChannelEvent(channel, ctx) {
|
|
10
|
+
if (ctx[DEFERRED]) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
ctx[DEFERRED] = true;
|
|
14
|
+
deferred.push({ channel, ctx, hadError: "error" in ctx });
|
|
15
|
+
}
|
|
16
|
+
function flushDeferredChannelEvents() {
|
|
17
|
+
if (deferred.length === 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const pending = deferred.splice(0, deferred.length);
|
|
21
|
+
for (const { channel, ctx, hadError } of pending) {
|
|
22
|
+
try {
|
|
23
|
+
channel.start.publish(ctx);
|
|
24
|
+
if (hadError) {
|
|
25
|
+
channel.error.publish(ctx);
|
|
26
|
+
}
|
|
27
|
+
channel.end.publish(ctx);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
DEBUG_BUILD && debug.warn("[orchestrion] failed to emit a deferred channel event", error);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export { deferChannelEvent, flushDeferredChannelEvents, isGlobalScopeError };
|
|
35
|
+
//# sourceMappingURL=orchestrion-deferred-channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrion-deferred-channels.js","sources":["../../../src/orchestrion-deferred-channels.ts"],"sourcesContent":["/**\n * Deferral for orchestrion channel events that could not be published when they occurred.\n *\n * On workerd, `channel.publish()`/`runStores()` throw at module/global scope, so a library\n * instantiated at module scope (`const app = new Hono()`) cannot emit its wrapping event\n * there. {@link ./orchestrion-diagnostics-channel} defers those events here;\n * {@link flushDeferredChannelEvents} emits them once a request is being handled (where\n * publish works) and the SDK's `init()` has registered subscribers.\n *\n * This module imports NO `node:*` builtin, so it is safe to pull into the request wrapper on\n * runtimes without `nodejs_compat` — there the queue is always empty (no channels were ever\n * injected) and the flush is a no-op.\n */\nimport { debug } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\n\ntype Ctx = Record<string, unknown>;\n\n// The minimal slice of a `node:diagnostics_channel` TracingChannel we emit on. Declared locally\n// (rather than imported from `node:diagnostics_channel`) so this module's graph carries no `node:`\n// specifier — `wrapRequestHandler` must load on runtimes without `nodejs_compat`, and the\n// module-graph test forbids any `node:` import reachable from it.\ninterface PublishableTracingChannel {\n start: { publish(ctx: Ctx): void };\n end: { publish(ctx: Ctx): void };\n error: { publish(ctx: Ctx): void };\n}\n\ninterface DeferredChannelEvent {\n channel: PublishableTracingChannel;\n ctx: Ctx;\n hadError: boolean;\n}\n\nconst deferred: DeferredChannelEvent[] = [];\nconst DEFERRED = Symbol('sentryOrchestrionDeferred');\n\n/** workerd's global-scope guard is the only error we degrade on; anything else is a real fault. */\nexport function isGlobalScopeError(error: unknown): boolean {\n return error instanceof Error && /within global scope/.test(error.message);\n}\n\n/** Queue a channel event that could not be published now, at most once per context object. */\nexport function deferChannelEvent(channel: PublishableTracingChannel, ctx: Ctx): void {\n if ((ctx as Record<symbol, unknown>)[DEFERRED]) {\n return;\n }\n (ctx as Record<symbol, unknown>)[DEFERRED] = true;\n deferred.push({ channel, ctx, hadError: 'error' in ctx });\n}\n\n/**\n * Emit every deferred channel event via the real channel. Called at the top of the request\n * handler, after `init()` has subscribed. Uses bare `start`/`end` publish (never `runStores`),\n * so no `bindStore` producer runs and no span is parented to this request — only the plain\n * subscribers (the instance patchers) fire. Idempotent: it drains the queue, so later requests\n * and re-entrant calls are no-ops.\n */\nexport function flushDeferredChannelEvents(): void {\n if (deferred.length === 0) {\n return;\n }\n const pending = deferred.splice(0, deferred.length);\n for (const { channel, ctx, hadError } of pending) {\n try {\n channel.start.publish(ctx);\n if (hadError) {\n channel.error.publish(ctx);\n }\n channel.end.publish(ctx);\n } catch (error) {\n DEBUG_BUILD && debug.warn('[orchestrion] failed to emit a deferred channel event', error);\n }\n }\n}\n"],"names":[],"mappings":";;;AAkCA,MAAM,WAAmC,EAAC;AAC1C,MAAM,QAAA,0BAAkB,2BAA2B,CAAA;AAG5C,SAAS,mBAAmB,KAAA,EAAyB;AAC1D,EAAA,OAAO,KAAA,YAAiB,KAAA,IAAS,qBAAA,CAAsB,IAAA,CAAK,MAAM,OAAO,CAAA;AAC3E;AAGO,SAAS,iBAAA,CAAkB,SAAoC,GAAA,EAAgB;AACpF,EAAA,IAAK,GAAA,CAAgC,QAAQ,CAAA,EAAG;AAC9C,IAAA;AAAA,EACF;AACA,EAAC,GAAA,CAAgC,QAAQ,CAAA,GAAI,IAAA;AAC7C,EAAA,QAAA,CAAS,KAAK,EAAE,OAAA,EAAS,KAAK,QAAA,EAAU,OAAA,IAAW,KAAK,CAAA;AAC1D;AASO,SAAS,0BAAA,GAAmC;AACjD,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA;AAAA,EACF;AACA,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,MAAA,CAAO,CAAA,EAAG,SAAS,MAAM,CAAA;AAClD,EAAA,KAAA,MAAW,EAAE,OAAA,EAAS,GAAA,EAAK,QAAA,MAAc,OAAA,EAAS;AAChD,IAAA,IAAI;AACF,MAAA,OAAA,CAAQ,KAAA,CAAM,QAAQ,GAAG,CAAA;AACzB,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,QAAQ,GAAG,CAAA;AAAA,MAC3B;AACA,MAAA,OAAA,CAAQ,GAAA,CAAI,QAAQ,GAAG,CAAA;AAAA,IACzB,SAAS,KAAA,EAAO;AACd,MAAA,WAAA,IAAe,KAAA,CAAM,IAAA,CAAK,uDAAA,EAAyD,KAAK,CAAA;AAAA,IAC1F;AAAA,EACF;AACF;;;;"}
|