@sentry/cloudflare 10.66.0 → 10.68.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/defineCloudflareOptions.js +11 -0
- package/build/cjs/defineCloudflareOptions.js.map +1 -0
- package/build/cjs/durableobject.js +19 -9
- 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/instrumentations/instrumentSqlStorage.js +5 -0
- package/build/cjs/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js +89 -8
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEnv.js +12 -0
- package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentRateLimit.js +29 -0
- package/build/cjs/instrumentations/worker/instrumentRateLimit.js.map +1 -0
- package/build/cjs/integrations/tracing/vercelai.js.map +1 -1
- package/build/cjs/nodejs_compat/index.js +5 -2
- package/build/cjs/nodejs_compat/index.js.map +1 -1
- package/build/cjs/nodejs_compat/integrations/tracing/vercelai.js.map +1 -1
- package/build/cjs/sdk.js +12 -1
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/utils/internalSqlQuery.js +19 -0
- package/build/cjs/utils/internalSqlQuery.js.map +1 -0
- package/build/cjs/utils/isBinding.js +8 -0
- package/build/cjs/utils/isBinding.js.map +1 -1
- package/build/cjs/vite/autoInstrument.js +81 -0
- package/build/cjs/vite/autoInstrument.js.map +1 -0
- package/build/cjs/vite/index.js +14 -0
- package/build/cjs/vite/index.js.map +1 -0
- package/build/cjs/vite/instrumentFile.js +31 -0
- package/build/cjs/vite/instrumentFile.js.map +1 -0
- package/build/cjs/vite/transform.js +144 -0
- package/build/cjs/vite/transform.js.map +1 -0
- package/build/cjs/vite/workerEntrypoint.js +66 -0
- package/build/cjs/vite/workerEntrypoint.js.map +1 -0
- package/build/cjs/vite/wranglerConfig.js +54 -0
- package/build/cjs/vite/wranglerConfig.js.map +1 -0
- package/build/cjs/wrapMethodWithSentry.js +4 -4
- package/build/cjs/wrapMethodWithSentry.js.map +1 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/defineCloudflareOptions.js +9 -0
- package/build/esm/defineCloudflareOptions.js.map +1 -0
- package/build/esm/durableobject.js +19 -9
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/index.js +2 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/instrumentations/instrumentSqlStorage.js +6 -1
- package/build/esm/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js +89 -8
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEnv.js +14 -2
- package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentRateLimit.js +27 -0
- package/build/esm/instrumentations/worker/instrumentRateLimit.js.map +1 -0
- package/build/esm/integrations/tracing/vercelai.js.map +1 -1
- package/build/esm/nodejs_compat/index.js +3 -2
- package/build/esm/nodejs_compat/index.js.map +1 -1
- package/build/esm/nodejs_compat/integrations/tracing/vercelai.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/sdk.js +13 -2
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/utils/internalSqlQuery.js +17 -0
- package/build/esm/utils/internalSqlQuery.js.map +1 -0
- package/build/esm/utils/isBinding.js +7 -1
- package/build/esm/utils/isBinding.js.map +1 -1
- package/build/esm/vite/autoInstrument.js +79 -0
- package/build/esm/vite/autoInstrument.js.map +1 -0
- package/build/esm/vite/index.js +12 -0
- package/build/esm/vite/index.js.map +1 -0
- package/build/esm/vite/instrumentFile.js +27 -0
- package/build/esm/vite/instrumentFile.js.map +1 -0
- package/build/esm/vite/transform.js +142 -0
- package/build/esm/vite/transform.js.map +1 -0
- package/build/esm/vite/workerEntrypoint.js +64 -0
- package/build/esm/vite/workerEntrypoint.js.map +1 -0
- package/build/esm/vite/wranglerConfig.js +52 -0
- package/build/esm/vite/wranglerConfig.js.map +1 -0
- package/build/esm/wrapMethodWithSentry.js +5 -5
- package/build/esm/wrapMethodWithSentry.js.map +1 -1
- package/build/types/client.d.ts +31 -2
- package/build/types/client.d.ts.map +1 -1
- package/build/types/defineCloudflareOptions.d.ts +38 -0
- package/build/types/defineCloudflareOptions.d.ts.map +1 -0
- package/build/types/durableobject.d.ts.map +1 -1
- package/build/types/index.d.ts +2 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentSqlStorage.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts +3 -3
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEnv.d.ts +2 -0
- package/build/types/instrumentations/worker/instrumentEnv.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentRateLimit.d.ts +6 -0
- package/build/types/instrumentations/worker/instrumentRateLimit.d.ts.map +1 -0
- package/build/types/integrations/tracing/vercelai.d.ts.map +1 -1
- package/build/types/nodejs_compat/index.d.ts +1 -1
- package/build/types/nodejs_compat/index.d.ts.map +1 -1
- package/build/types/nodejs_compat/integrations/tracing/vercelai.d.ts +1 -8
- package/build/types/nodejs_compat/integrations/tracing/vercelai.d.ts.map +1 -1
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types/utils/internalSqlQuery.d.ts +18 -0
- package/build/types/utils/internalSqlQuery.d.ts.map +1 -0
- package/build/types/utils/isBinding.d.ts +14 -1
- package/build/types/utils/isBinding.d.ts.map +1 -1
- package/build/types/vite/autoInstrument.d.ts +21 -0
- package/build/types/vite/autoInstrument.d.ts.map +1 -0
- package/build/types/vite/index.d.ts +88 -0
- package/build/types/vite/index.d.ts.map +1 -0
- package/build/types/vite/instrumentFile.d.ts +22 -0
- package/build/types/vite/instrumentFile.d.ts.map +1 -0
- package/build/types/vite/transform.d.ts +60 -0
- package/build/types/vite/transform.d.ts.map +1 -0
- package/build/types/vite/workerEntrypoint.d.ts +12 -0
- package/build/types/vite/workerEntrypoint.d.ts.map +1 -0
- package/build/types/vite/wranglerConfig.d.ts +43 -0
- package/build/types/vite/wranglerConfig.d.ts.map +1 -0
- package/build/types/wrapMethodWithSentry.d.ts +5 -0
- package/build/types/wrapMethodWithSentry.d.ts.map +1 -1
- package/build/types-ts3.8/client.d.ts +31 -2
- package/build/types-ts3.8/defineCloudflareOptions.d.ts +38 -0
- package/build/types-ts3.8/index.d.ts +2 -1
- package/build/types-ts3.8/instrumentations/instrumentWorkerEntrypoint.d.ts +3 -3
- package/build/types-ts3.8/instrumentations/worker/instrumentEnv.d.ts +2 -0
- package/build/types-ts3.8/instrumentations/worker/instrumentRateLimit.d.ts +6 -0
- package/build/types-ts3.8/nodejs_compat/index.d.ts +1 -1
- package/build/types-ts3.8/nodejs_compat/integrations/tracing/vercelai.d.ts +7 -14
- package/build/types-ts3.8/utils/internalSqlQuery.d.ts +18 -0
- package/build/types-ts3.8/utils/isBinding.d.ts +14 -1
- package/build/types-ts3.8/vite/autoInstrument.d.ts +21 -0
- package/build/types-ts3.8/vite/index.d.ts +88 -0
- package/build/types-ts3.8/vite/instrumentFile.d.ts +22 -0
- package/build/types-ts3.8/vite/transform.d.ts +60 -0
- package/build/types-ts3.8/vite/workerEntrypoint.d.ts +12 -0
- package/build/types-ts3.8/vite/wranglerConfig.d.ts +43 -0
- package/build/types-ts3.8/wrapMethodWithSentry.d.ts +5 -0
- package/package.json +19 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercelai.js","sources":["../../../../../src/nodejs_compat/integrations/tracing/vercelai.ts"],"sourcesContent":["/**\n * This is a copy of the Vercel AI integration from the Cloudflare SDK (src/integrations/tracing/vercelai.ts).\n *\n * The only difference is that it includes tracing channel support\n * because the default Vercel AI integration needs `nodejs_als`, while this one uses `nodejs_compat`.\n */\n\nimport type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\nimport { vercelAiIntegration as serverUtilsVercelAiIntegration } from '@sentry/server-utils';\nimport { vercelAIIntegration as cloudflareVercelAIIntegration } from '../../../integrations/tracing/vercelai';\n\
|
|
1
|
+
{"version":3,"file":"vercelai.js","sources":["../../../../../src/nodejs_compat/integrations/tracing/vercelai.ts"],"sourcesContent":["/**\n * This is a copy of the Vercel AI integration from the Cloudflare SDK (src/integrations/tracing/vercelai.ts).\n *\n * The only difference is that it includes tracing channel support\n * because the default Vercel AI integration needs `nodejs_als`, while this one uses `nodejs_compat`.\n */\n\nimport type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\nimport { vercelAiIntegration as serverUtilsVercelAiIntegration, type VercelAiOptions } from '@sentry/server-utils';\nimport { vercelAIIntegration as cloudflareVercelAIIntegration } from '../../../integrations/tracing/vercelai';\n\nconst _vercelAIIntegration = ((options: VercelAiOptions = {}) => {\n const inner = serverUtilsVercelAiIntegration(options);\n const instrumentation = cloudflareVercelAIIntegration(options);\n\n return {\n ...inner,\n ...instrumentation,\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":["serverUtilsVercelAiIntegration","cloudflareVercelAIIntegration","defineIntegration"],"mappings":";;;;;;AAYA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,MAAM,KAAA,GAAQA,gCAA+B,OAAO,CAAA;AACpD,EAAA,MAAM,eAAA,GAAkBC,6BAA8B,OAAO,CAAA;AAE7D,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,GAAG;AAAA,GACL;AACF,CAAA,CAAA;AA4BO,MAAM,mBAAA,GAAsBC,uBAAkB,oBAAoB;;;;"}
|
package/build/cjs/sdk.js
CHANGED
|
@@ -10,6 +10,10 @@ const tracer = require('./opentelemetry/tracer.js');
|
|
|
10
10
|
const transport = require('./transport.js');
|
|
11
11
|
const stacktrace = require('./vendor/stacktrace.js');
|
|
12
12
|
|
|
13
|
+
function getRegisteredChannelIntegrations() {
|
|
14
|
+
const registered = core.GLOBAL_OBJ.__SENTRY_ORCHESTRION__?.integrations;
|
|
15
|
+
return registered ? [...registered.values()].map((factory) => factory()) : [];
|
|
16
|
+
}
|
|
13
17
|
function getDefaultIntegrations(options) {
|
|
14
18
|
const cookiesEnabled = options.sendDefaultPii || options.dataCollection?.cookies != null;
|
|
15
19
|
return [
|
|
@@ -27,7 +31,14 @@ function getDefaultIntegrations(options) {
|
|
|
27
31
|
hono.honoIntegration(),
|
|
28
32
|
httpServer.httpServerIntegration(),
|
|
29
33
|
core.requestDataIntegration(cookiesEnabled ? void 0 : { include: { cookies: false } }),
|
|
30
|
-
core.consoleIntegration()
|
|
34
|
+
core.consoleIntegration(),
|
|
35
|
+
// The orchestrion diagnostics-channel subscribers (mysql, pg, …). The
|
|
36
|
+
// `@sentry/cloudflare/vite` plugin injects the channels at build time and,
|
|
37
|
+
// next to each, a snippet that registers the matching subscriber factory on
|
|
38
|
+
// the global marker. Read from there instead of importing them so bundles
|
|
39
|
+
// built without the plugin — where the channels would never fire — don't
|
|
40
|
+
// ship the code.
|
|
41
|
+
...getRegisteredChannelIntegrations()
|
|
31
42
|
];
|
|
32
43
|
}
|
|
33
44
|
function init(options) {
|
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 { httpServerIntegration } from './integrations/httpServer';\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 // TODO(v11): Drop this transitional gating and let `requestDataIntegration` rely on the resolved\n // `dataCollection` defaults directly. Until then, preserve the historical Cloudflare behavior of not\n // attaching cookies unless the user explicitly opts in via `sendDefaultPii` or `dataCollection.cookies`.\n // eslint-disable-next-line typescript/no-deprecated\n const cookiesEnabled = options.sendDefaultPii || options.dataCollection?.cookies != null;\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 typescript/no-deprecated\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n linkedErrorsIntegration(),\n fetchIntegration(),\n // eslint-disable-next-line typescript/no-deprecated\n honoIntegration(),\n httpServerIntegration(),\n requestDataIntegration(cookiesEnabled ? 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: getIntegrationsToSetup(options),\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","httpServerIntegration","requestDataIntegration","consoleIntegration","makeFlushLock","stackParserFromStackParserOptions","defaultStackParser","getIntegrationsToSetup","makeCloudflareTransport","setupOpenTelemetryTracer","initAndBind","CloudflareClient"],"mappings":";;;;;;;;;;;;
|
|
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 GLOBAL_OBJ,\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 { httpServerIntegration } from './integrations/httpServer';\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/**\n * Instantiate the channel-subscriber factories the `@sentry/cloudflare/vite`\n * plugin registered on the global marker. The plugin splices a small snippet\n * into each instrumented module that `.set`s its factory here (keyed by export\n * name), so the marker holds one factory per package actually bundled.\n *\n * The marker is read directly instead of importing the factories, so a worker\n * built without the plugin — where the channels never fire — ships none of this\n * code.\n * TODO(v11): Use `@sentry/server-utils/orchestrion` once we move to `nodejs_compat` by default.\n */\nfunction getRegisteredChannelIntegrations(): Integration[] {\n const registered = GLOBAL_OBJ.__SENTRY_ORCHESTRION__?.integrations;\n\n return registered ? [...registered.values()].map(factory => factory()) : [];\n}\n\n/** Get the default integrations for the Cloudflare SDK. */\nexport function getDefaultIntegrations(options: CloudflareOptions): Integration[] {\n // TODO(v11): Drop this transitional gating and let `requestDataIntegration` rely on the resolved\n // `dataCollection` defaults directly. Until then, preserve the historical Cloudflare behavior of not\n // attaching cookies unless the user explicitly opts in via `sendDefaultPii` or `dataCollection.cookies`.\n // eslint-disable-next-line typescript/no-deprecated\n const cookiesEnabled = options.sendDefaultPii || options.dataCollection?.cookies != null;\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 typescript/no-deprecated\n inboundFiltersIntegration(),\n functionToStringIntegration(),\n conversationIdIntegration(),\n linkedErrorsIntegration(),\n fetchIntegration(),\n // eslint-disable-next-line typescript/no-deprecated\n honoIntegration(),\n httpServerIntegration(),\n requestDataIntegration(cookiesEnabled ? undefined : { include: { cookies: false } }),\n consoleIntegration(),\n // The orchestrion diagnostics-channel subscribers (mysql, pg, …). The\n // `@sentry/cloudflare/vite` plugin injects the channels at build time and,\n // next to each, a snippet that registers the matching subscriber factory on\n // the global marker. Read from there instead of importing them so bundles\n // built without the plugin — where the channels would never fire — don't\n // ship the code.\n ...getRegisteredChannelIntegrations(),\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: getIntegrationsToSetup(options),\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":["GLOBAL_OBJ","dedupeIntegration","inboundFiltersIntegration","functionToStringIntegration","conversationIdIntegration","linkedErrorsIntegration","fetchIntegration","honoIntegration","httpServerIntegration","requestDataIntegration","consoleIntegration","makeFlushLock","stackParserFromStackParserOptions","defaultStackParser","getIntegrationsToSetup","makeCloudflareTransport","setupOpenTelemetryTracer","initAndBind","CloudflareClient"],"mappings":";;;;;;;;;;;;AAmCA,SAAS,gCAAA,GAAkD;AACzD,EAAA,MAAM,UAAA,GAAaA,gBAAW,sBAAA,EAAwB,YAAA;AAEtD,EAAA,OAAO,UAAA,GAAa,CAAC,GAAG,UAAA,CAAW,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,CAAA,OAAA,KAAW,OAAA,EAAS,CAAA,GAAI,EAAC;AAC5E;AAGO,SAAS,uBAAuB,OAAA,EAA2C;AAKhF,EAAA,MAAM,cAAA,GAAiB,OAAA,CAAQ,cAAA,IAAkB,OAAA,CAAQ,gBAAgB,OAAA,IAAW,IAAA;AACpF,EAAA,OAAO;AAAA;AAAA;AAAA,IAGL,GAAI,QAAQ,YAAA,KAAiB,KAAA,GAAQ,EAAC,GAAI,CAACC,wBAAmB,CAAA;AAAA;AAAA;AAAA,IAG9DC,8BAAA,EAA0B;AAAA,IAC1BC,gCAAA,EAA4B;AAAA,IAC5BC,8BAAA,EAA0B;AAAA,IAC1BC,4BAAA,EAAwB;AAAA,IACxBC,sBAAA,EAAiB;AAAA;AAAA,IAEjBC,oBAAA,EAAgB;AAAA,IAChBC,gCAAA,EAAsB;AAAA,IACtBC,2BAAA,CAAuB,iBAAiB,MAAA,GAAY,EAAE,SAAS,EAAE,OAAA,EAAS,KAAA,EAAM,EAAG,CAAA;AAAA,IACnFC,uBAAA,EAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOnB,GAAG,gCAAA;AAAiC,GACtC;AACF;AAKO,SAAS,KAAK,OAAA,EAA0D;AAC7E,EAAA,IAAI,OAAA,CAAQ,wBAAwB,MAAA,EAAW;AAC7C,IAAA,OAAA,CAAQ,mBAAA,GAAsB,uBAAuB,OAAO,CAAA;AAAA,EAC9D;AAEA,EAAA,MAAM,YAAY,OAAA,CAAQ,GAAA,GAAMC,mBAAA,CAAc,OAAA,CAAQ,GAAG,CAAA,GAAI,MAAA;AAC7D,EAAA,OAAO,OAAA,CAAQ,GAAA;AAEf,EAAA,MAAM,aAAA,GAAyC;AAAA,IAC7C,GAAG,OAAA;AAAA,IACH,WAAA,EAAaC,sCAAA,CAAkC,OAAA,CAAQ,WAAA,IAAeC,6BAAkB,CAAA;AAAA,IACxF,YAAA,EAAcC,4BAAuB,OAAO,CAAA;AAAA,IAC5C,SAAA,EAAW,QAAQ,SAAA,IAAaC,iCAAA;AAAA,IAChC;AAAA,GACF;AASA,EAAA,IAAI,CAAC,QAAQ,sBAAA,EAAwB;AACnC,IAAAC,+BAAA,EAAyB;AAAA,EAC3B;AAEA,EAAA,OAAOC,gBAAA,CAAYC,yBAAkB,aAAa,CAAA;AACpD;;;;;"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
|
|
5
|
+
function targetsCloudflareInternalTable(querySummary, allowlist) {
|
|
6
|
+
if (!querySummary) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const [, ...tables] = querySummary.split(" ");
|
|
10
|
+
return tables.some((table) => {
|
|
11
|
+
if (!table.toLowerCase().startsWith("cf_")) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
return !allowlist?.length || !core.stringMatchesSomePattern(table, allowlist, true);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
exports.targetsCloudflareInternalTable = targetsCloudflareInternalTable;
|
|
19
|
+
//# sourceMappingURL=internalSqlQuery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internalSqlQuery.js","sources":["../../../src/utils/internalSqlQuery.ts"],"sourcesContent":["import { stringMatchesSomePattern } from '@sentry/core';\n\n/**\n * Cloudflare frameworks that build on Durable Objects (`agents`, `partyserver`, ...) manage their\n * own internal SQLite tables, all namespaced with a `cf_` prefix — e.g. `cf_agents_schedules`,\n * `cf_agent_state`, `cf_ai_chat_stream_chunks`. Queries against them (schedule polling, chat-stream\n * persistence, state bookkeeping) are framework implementation details that otherwise flood traces\n * with dozens of zero-signal `db.query` spans per request. The exact set of tables even varies\n * between framework versions, so we match the reserved prefix rather than an enumerated list.\n *\n * The `cf_` prefix is a reserved convention for framework-managed tables, so user tables should not\n * use it. In case a user table does collide with the prefix, the `durableObjectSqlSpanAllowlist`\n * option lets them opt those tables back into instrumentation.\n *\n * The check operates on the query summary produced by `getSqlQuerySummary` (`{operation} {table} ...`,\n * the same value used as the span name), so table targets are already isolated from the rest of the\n * query.\n */\nexport function targetsCloudflareInternalTable(\n querySummary: string | undefined,\n allowlist?: Array<string | RegExp>,\n): boolean {\n if (!querySummary) {\n return false;\n }\n\n const [, ...tables] = querySummary.split(' ');\n\n return tables.some(table => {\n if (!table.toLowerCase().startsWith('cf_')) {\n return false;\n }\n\n // A table on the allowlist is treated as a user table and stays instrumented, even though it\n // matches the reserved prefix.\n return !allowlist?.length || !stringMatchesSomePattern(table, allowlist, true);\n });\n}\n"],"names":["stringMatchesSomePattern"],"mappings":";;;;AAkBO,SAAS,8BAAA,CACd,cACA,SAAA,EACS;AACT,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAG,GAAG,MAAM,CAAA,GAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AAE5C,EAAA,OAAO,MAAA,CAAO,KAAK,CAAA,KAAA,KAAS;AAC1B,IAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAY,CAAE,UAAA,CAAW,KAAK,CAAA,EAAG;AAC1C,MAAA,OAAO,KAAA;AAAA,IACT;AAIA,IAAA,OAAO,CAAC,SAAA,EAAW,MAAA,IAAU,CAACA,6BAAA,CAAyB,KAAA,EAAO,WAAW,IAAI,CAAA;AAAA,EAC/E,CAAC,CAAA;AACH;;;;"}
|
|
@@ -17,13 +17,21 @@ function isQueue(item) {
|
|
|
17
17
|
function isD1Database(item) {
|
|
18
18
|
return item != null && isNotJSRPC(item) && typeof item.prepare === "function" && typeof item.batch === "function" && typeof item.exec === "function";
|
|
19
19
|
}
|
|
20
|
+
function isAiBinding(item) {
|
|
21
|
+
return item != null && isNotJSRPC(item) && typeof item.run === "function" && typeof item.gateway === "function" && typeof item.toMarkdown === "function";
|
|
22
|
+
}
|
|
20
23
|
function isR2Bucket(item) {
|
|
21
24
|
return item != null && isNotJSRPC(item) && typeof item.head === "function" && typeof item.put === "function" && typeof item.createMultipartUpload === "function";
|
|
22
25
|
}
|
|
26
|
+
function isRateLimit(item) {
|
|
27
|
+
return item != null && isNotJSRPC(item) && typeof item.limit === "function";
|
|
28
|
+
}
|
|
23
29
|
|
|
30
|
+
exports.isAiBinding = isAiBinding;
|
|
24
31
|
exports.isD1Database = isD1Database;
|
|
25
32
|
exports.isDurableObjectNamespace = isDurableObjectNamespace;
|
|
26
33
|
exports.isJSRPC = isJSRPC;
|
|
27
34
|
exports.isQueue = isQueue;
|
|
28
35
|
exports.isR2Bucket = isR2Bucket;
|
|
36
|
+
exports.isRateLimit = isRateLimit;
|
|
29
37
|
//# sourceMappingURL=isBinding.js.map
|
|
@@ -1 +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 { D1Database, DurableObjectNamespace, Queue, R2Bucket } 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\n/**\n * Duck-type check for Queue producer bindings.\n * Queue has `send` and `sendBatch` async methods.\n */\nexport function isQueue(item: unknown): item is Queue {\n return item != null && isNotJSRPC(item) && typeof item.send === 'function' && typeof item.sendBatch === 'function';\n}\n\n/**\n * Duck-type check for D1Database bindings.\n * D1Database has `prepare`, `batch`, and `exec` methods.\n */\nexport function isD1Database(item: unknown): item is D1Database {\n return (\n item != null &&\n isNotJSRPC(item) &&\n typeof item.prepare === 'function' &&\n typeof item.batch === 'function' &&\n typeof item.exec === 'function'\n );\n}\n\n/**\n * Duck-type check for R2 Bucket bindings.\n * R2Bucket has `head`, `put`, and `createMultipartUpload` methods.\n */\nexport function isR2Bucket(item: unknown): item is R2Bucket {\n return (\n item != null &&\n isNotJSRPC(item) &&\n typeof item.head === 'function' &&\n typeof item.put === 'function' &&\n typeof item.createMultipartUpload === 'function'\n );\n}\n"],"names":[],"mappings":";;AA4CO,SAAS,QAAQ,IAAA,EAAgC;AACtD,EAAA,IAAI;AACF,IAAA,OAAO,CAAC,CAAE,IAAA,CAAiC,0CAA0C,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,CAAA;AAAA,EACtG,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,MAAM,UAAA,GAAa,CAAC,IAAA,KAAmD,CAAC,QAAQ,IAAI,CAAA;AAM7E,SAAS,yBAAyB,IAAA,EAA+C;AACtF,EAAA,OAAO,QAAQ,IAAA,IAAQ,UAAA,CAAW,IAAI,CAAA,IAAK,OAAO,KAAK,UAAA,KAAe,UAAA;AACxE;AAMO,SAAS,QAAQ,IAAA,EAA8B;AACpD,EAAA,OAAO,IAAA,IAAQ,IAAA,IAAQ,UAAA,CAAW,IAAI,CAAA,IAAK,OAAO,IAAA,CAAK,IAAA,KAAS,UAAA,IAAc,OAAO,IAAA,CAAK,SAAA,KAAc,UAAA;AAC1G;AAMO,SAAS,aAAa,IAAA,EAAmC;AAC9D,EAAA,OACE,IAAA,IAAQ,IAAA,IACR,UAAA,CAAW,IAAI,KACf,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,IACxB,OAAO,IAAA,CAAK,KAAA,KAAU,UAAA,IACtB,OAAO,KAAK,IAAA,KAAS,UAAA;AAEzB;AAMO,SAAS,WAAW,IAAA,EAAiC;AAC1D,EAAA,OACE,IAAA,IAAQ,IAAA,IACR,UAAA,CAAW,IAAI,KACf,OAAO,IAAA,CAAK,IAAA,KAAS,UAAA,IACrB,OAAO,IAAA,CAAK,GAAA,KAAQ,UAAA,IACpB,OAAO,KAAK,qBAAA,KAA0B,UAAA;AAE1C
|
|
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 { Ai, D1Database, DurableObjectNamespace, Queue, R2Bucket, RateLimit } 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\n/**\n * Duck-type check for Queue producer bindings.\n * Queue has `send` and `sendBatch` async methods.\n */\nexport function isQueue(item: unknown): item is Queue {\n return item != null && isNotJSRPC(item) && typeof item.send === 'function' && typeof item.sendBatch === 'function';\n}\n\n/**\n * Duck-type check for D1Database bindings.\n * D1Database has `prepare`, `batch`, and `exec` methods.\n */\nexport function isD1Database(item: unknown): item is D1Database {\n return (\n item != null &&\n isNotJSRPC(item) &&\n typeof item.prepare === 'function' &&\n typeof item.batch === 'function' &&\n typeof item.exec === 'function'\n );\n}\n\n/**\n * Duck-type check for Workers AI bindings.\n * The Ai binding has `run`, `gateway`, and `toMarkdown` methods.\n */\nexport function isAiBinding(item: unknown): item is Ai {\n return (\n item != null &&\n isNotJSRPC(item) &&\n typeof item.run === 'function' &&\n typeof item.gateway === 'function' &&\n typeof item.toMarkdown === 'function'\n );\n}\n\n/**\n * Duck-type check for R2 Bucket bindings.\n * R2Bucket has `head`, `put`, and `createMultipartUpload` methods.\n */\nexport function isR2Bucket(item: unknown): item is R2Bucket {\n return (\n item != null &&\n isNotJSRPC(item) &&\n typeof item.head === 'function' &&\n typeof item.put === 'function' &&\n typeof item.createMultipartUpload === 'function'\n );\n}\n\n/**\n * Duck-type check for RateLimit bindings.\n * RateLimit only exposes a single `limit` method. Because that is a fairly\n * common method name, this check is intentionally run after the more specific\n * binding checks (Queue, R2, D1) in `instrumentEnv`, so those win when a binding\n * also happens to expose `limit`.\n */\nexport function isRateLimit(item: unknown): item is RateLimit {\n return item != null && isNotJSRPC(item) && typeof item.limit === 'function';\n}\n"],"names":[],"mappings":";;AA4CO,SAAS,QAAQ,IAAA,EAAgC;AACtD,EAAA,IAAI;AACF,IAAA,OAAO,CAAC,CAAE,IAAA,CAAiC,0CAA0C,IAAA,CAAK,MAAA,EAAQ,CAAA,CAAE,CAAA;AAAA,EACtG,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,MAAM,UAAA,GAAa,CAAC,IAAA,KAAmD,CAAC,QAAQ,IAAI,CAAA;AAM7E,SAAS,yBAAyB,IAAA,EAA+C;AACtF,EAAA,OAAO,QAAQ,IAAA,IAAQ,UAAA,CAAW,IAAI,CAAA,IAAK,OAAO,KAAK,UAAA,KAAe,UAAA;AACxE;AAMO,SAAS,QAAQ,IAAA,EAA8B;AACpD,EAAA,OAAO,IAAA,IAAQ,IAAA,IAAQ,UAAA,CAAW,IAAI,CAAA,IAAK,OAAO,IAAA,CAAK,IAAA,KAAS,UAAA,IAAc,OAAO,IAAA,CAAK,SAAA,KAAc,UAAA;AAC1G;AAMO,SAAS,aAAa,IAAA,EAAmC;AAC9D,EAAA,OACE,IAAA,IAAQ,IAAA,IACR,UAAA,CAAW,IAAI,KACf,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,IACxB,OAAO,IAAA,CAAK,KAAA,KAAU,UAAA,IACtB,OAAO,KAAK,IAAA,KAAS,UAAA;AAEzB;AAMO,SAAS,YAAY,IAAA,EAA2B;AACrD,EAAA,OACE,IAAA,IAAQ,IAAA,IACR,UAAA,CAAW,IAAI,KACf,OAAO,IAAA,CAAK,GAAA,KAAQ,UAAA,IACpB,OAAO,IAAA,CAAK,OAAA,KAAY,UAAA,IACxB,OAAO,KAAK,UAAA,KAAe,UAAA;AAE/B;AAMO,SAAS,WAAW,IAAA,EAAiC;AAC1D,EAAA,OACE,IAAA,IAAQ,IAAA,IACR,UAAA,CAAW,IAAI,KACf,OAAO,IAAA,CAAK,IAAA,KAAS,UAAA,IACrB,OAAO,IAAA,CAAK,GAAA,KAAQ,UAAA,IACpB,OAAO,KAAK,qBAAA,KAA0B,UAAA;AAE1C;AASO,SAAS,YAAY,IAAA,EAAkC;AAC5D,EAAA,OAAO,QAAQ,IAAA,IAAQ,UAAA,CAAW,IAAI,CAAA,IAAK,OAAO,KAAK,KAAA,KAAU,UAAA;AACnE;;;;;;;;;;"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const instrumentFile = require('./instrumentFile.js');
|
|
4
|
+
const transform = require('./transform.js');
|
|
5
|
+
const wranglerConfig = require('./wranglerConfig.js');
|
|
6
|
+
|
|
7
|
+
function normalizePath(path) {
|
|
8
|
+
return path.replace(/\\/g, "/");
|
|
9
|
+
}
|
|
10
|
+
const JS_EXTENSION_REGEX = /\.[cm]?[jt]sx?$/;
|
|
11
|
+
function sentryCloudflareAutoInstrumentPlugin() {
|
|
12
|
+
let wranglerConfig$1;
|
|
13
|
+
let entryFilePath;
|
|
14
|
+
let optionsFn = instrumentFile.ENV_FALLBACK_OPTIONS_FN;
|
|
15
|
+
let optionsImport;
|
|
16
|
+
return {
|
|
17
|
+
name: "sentry-cloudflare-auto-instrument",
|
|
18
|
+
configResolved(config) {
|
|
19
|
+
const result = wranglerConfig.resolveWranglerConfig(config.root);
|
|
20
|
+
if (!result) {
|
|
21
|
+
config.logger?.warn("[sentry] No parseable wrangler config found \u2014 auto-instrumentation disabled.");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
wranglerConfig$1 = result.config;
|
|
25
|
+
if (wranglerConfig$1.main) {
|
|
26
|
+
entryFilePath = normalizePath(wranglerConfig$1.main);
|
|
27
|
+
}
|
|
28
|
+
if (entryFilePath) {
|
|
29
|
+
const instrumentFilePath = instrumentFile.resolveInstrumentFile(entryFilePath);
|
|
30
|
+
if (instrumentFilePath) {
|
|
31
|
+
const built = instrumentFile.buildOptionsImport(entryFilePath, instrumentFilePath);
|
|
32
|
+
optionsFn = built.optionsFn;
|
|
33
|
+
optionsImport = built.importStmt;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
transform(code, id) {
|
|
38
|
+
if (!wranglerConfig$1 || !entryFilePath) return void 0;
|
|
39
|
+
if (this.environment?.name === "client") return void 0;
|
|
40
|
+
const normalizedId = normalizePath(id.replace(/[?#].*$/, ""));
|
|
41
|
+
if (normalizedId !== entryFilePath) {
|
|
42
|
+
if (!JS_EXTENSION_REGEX.test(normalizedId) || !JS_EXTENSION_REGEX.test(entryFilePath)) return void 0;
|
|
43
|
+
if (normalizedId.replace(JS_EXTENSION_REGEX, "") !== entryFilePath.replace(JS_EXTENSION_REGEX, "")) {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
let ast;
|
|
48
|
+
try {
|
|
49
|
+
ast = this.parse(code);
|
|
50
|
+
} catch {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
const classWrappers = /* @__PURE__ */ new Map();
|
|
54
|
+
for (const { className } of wranglerConfig$1.durableObjects) {
|
|
55
|
+
classWrappers.set(className, "durableObject");
|
|
56
|
+
}
|
|
57
|
+
for (const { className } of wranglerConfig$1.workflows) {
|
|
58
|
+
classWrappers.set(className, "workflow");
|
|
59
|
+
}
|
|
60
|
+
for (const className of wranglerConfig$1.workerEntrypoints) {
|
|
61
|
+
classWrappers.set(className, "workerEntrypoint");
|
|
62
|
+
}
|
|
63
|
+
const result = transform.applyAutoInstrumentTransforms(code, ast, {
|
|
64
|
+
classWrappers,
|
|
65
|
+
optionsFn,
|
|
66
|
+
optionsImport
|
|
67
|
+
});
|
|
68
|
+
const wrappedClasses = result?.wrappedClasses ?? /* @__PURE__ */ new Set();
|
|
69
|
+
const missing = [...classWrappers.keys()].filter((name) => !wrappedClasses.has(name));
|
|
70
|
+
if (missing.length > 0) {
|
|
71
|
+
this.warn?.(
|
|
72
|
+
`[sentry] Could not auto-instrument class(es) ${missing.join(", ")}: no matching exported class declaration found in the worker entry (re-exports from other modules cannot be wrapped automatically). Wrap them manually with the matching \`instrument*WithSentry\` helper.`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return result ?? void 0;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
exports.sentryCloudflareAutoInstrumentPlugin = sentryCloudflareAutoInstrumentPlugin;
|
|
81
|
+
//# sourceMappingURL=autoInstrument.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autoInstrument.js","sources":["../../../src/vite/autoInstrument.ts"],"sourcesContent":["import { buildOptionsImport, ENV_FALLBACK_OPTIONS_FN, resolveInstrumentFile } from './instrumentFile';\nimport { applyAutoInstrumentTransforms, type ClassWrapperKind, type ProgramBody } from './transform';\nimport { resolveWranglerConfig, type WranglerConfig } from './wranglerConfig';\n\n// Vite normalizes module IDs to posix separators even on Windows, while\n// `path.resolve` yields backslashes there — normalize before comparing.\nfunction normalizePath(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\n// Extensions the entry-module match may tolerate swapping (e.g. wrangler's\n// `main` says `.ts` but the served module is `.js`). Anything else — `.css`,\n// `.html`, … — sharing the entry's basename must never be treated as the entry.\nconst JS_EXTENSION_REGEX = /\\.[cm]?[jt]sx?$/;\n\nexport function sentryCloudflareAutoInstrumentPlugin() {\n let wranglerConfig: WranglerConfig | undefined;\n let entryFilePath: string | undefined;\n\n let optionsFn = ENV_FALLBACK_OPTIONS_FN;\n let optionsImport: string | undefined;\n\n return {\n name: 'sentry-cloudflare-auto-instrument',\n\n configResolved(config: { root: string; logger?: { warn(msg: string): void } }): void {\n const result = resolveWranglerConfig(config.root);\n if (!result) {\n config.logger?.warn('[sentry] No parseable wrangler config found — auto-instrumentation disabled.');\n return;\n }\n\n wranglerConfig = result.config;\n if (wranglerConfig.main) {\n // `main` is already absolute (wrangler resolves it); just normalize\n // separators so the entry-module comparison holds on Windows.\n entryFilePath = normalizePath(wranglerConfig.main);\n }\n\n if (entryFilePath) {\n const instrumentFilePath = resolveInstrumentFile(entryFilePath);\n if (instrumentFilePath) {\n const built = buildOptionsImport(entryFilePath, instrumentFilePath);\n optionsFn = built.optionsFn;\n optionsImport = built.importStmt;\n }\n }\n },\n\n transform(\n this: { parse(code: string): ProgramBody; warn?(msg: string): void; environment?: { name?: string } },\n code: string,\n id: string,\n ): { code: string; map: unknown } | undefined {\n if (!wranglerConfig || !entryFilePath) return undefined;\n\n // The worker entry never belongs to the client (browser) environment.\n // Skipping it keeps a same-basename sibling (e.g. a `src/index.tsx`\n // client entry next to a `src/index.ts` worker) out of the browser bundle.\n if (this.environment?.name === 'client') return undefined;\n\n // Vite may append query/hash params to the module ID.\n const normalizedId = normalizePath(id.replace(/[?#].*$/, ''));\n if (normalizedId !== entryFilePath) {\n // Tolerate a differing JS-flavored extension (e.g. `.js` vs `.ts`).\n if (!JS_EXTENSION_REGEX.test(normalizedId) || !JS_EXTENSION_REGEX.test(entryFilePath)) return undefined;\n if (normalizedId.replace(JS_EXTENSION_REGEX, '') !== entryFilePath.replace(JS_EXTENSION_REGEX, '')) {\n return undefined;\n }\n }\n\n let ast: ProgramBody;\n try {\n ast = this.parse(code);\n } catch {\n // Raw TypeScript or syntax error — esbuild hasn't run yet (unlikely)\n // or the file is genuinely broken. Either way, skip silently.\n return undefined;\n }\n\n const classWrappers = new Map<string, ClassWrapperKind>();\n for (const { className } of wranglerConfig.durableObjects) {\n classWrappers.set(className, 'durableObject');\n }\n for (const { className } of wranglerConfig.workflows) {\n classWrappers.set(className, 'workflow');\n }\n for (const className of wranglerConfig.workerEntrypoints) {\n classWrappers.set(className, 'workerEntrypoint');\n }\n\n // No registration import is injected here: the orchestrion plugin's\n // subscribe-injection makes each bundled package self-register its channel\n // subscriber on the global marker, so wrapping the entry with `withSentry`\n // is all this plugin needs to do.\n const result = applyAutoInstrumentTransforms(code, ast, {\n classWrappers,\n optionsFn,\n optionsImport,\n });\n\n const wrappedClasses = result?.wrappedClasses ?? new Set<string>();\n const missing = [...classWrappers.keys()].filter(name => !wrappedClasses.has(name));\n if (missing.length > 0) {\n this.warn?.(\n `[sentry] Could not auto-instrument class(es) ${missing.join(', ')}: no matching exported class ` +\n 'declaration found in the worker entry (re-exports from other modules cannot be wrapped ' +\n 'automatically). Wrap them manually with the matching `instrument*WithSentry` helper.',\n );\n }\n\n return result ?? undefined;\n },\n };\n}\n"],"names":["wranglerConfig","ENV_FALLBACK_OPTIONS_FN","resolveWranglerConfig","resolveInstrumentFile","buildOptionsImport","applyAutoInstrumentTransforms"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const vite = require('@sentry/server-utils/orchestrion/vite');
|
|
4
|
+
const autoInstrument = require('./autoInstrument.js');
|
|
5
|
+
|
|
6
|
+
function sentryCloudflareVitePlugin(options = {}) {
|
|
7
|
+
return [
|
|
8
|
+
...options._experimental?.useDiagnosticsChannelInjection ? [vite.sentryOrchestrionPlugin({ injectChannelSubscribers: true })] : [],
|
|
9
|
+
...options._experimental?.autoInstrumentation ? [autoInstrument.sentryCloudflareAutoInstrumentPlugin()] : []
|
|
10
|
+
];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
exports.sentryCloudflareVitePlugin = sentryCloudflareVitePlugin;
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/vite/index.ts"],"sourcesContent":["// Published ESM-only via the `@sentry/cloudflare/vite` subpath export:\n// `@sentry/server-utils/orchestrion/vite` exposes no `require` condition, so a\n// CJS entry here would fail at resolution time (ERR_PACKAGE_PATH_NOT_EXPORTED).\n// The CJS rollup variant still emits this file, but `package.json` doesn't\n// expose it — same setup as `@sentry/server-utils/orchestrion/vite` itself.\nimport { sentryOrchestrionPlugin } from '@sentry/server-utils/orchestrion/vite';\nimport { sentryCloudflareAutoInstrumentPlugin } from './autoInstrument';\n\n/**\n * Options for {@link sentryCloudflareVitePlugin}.\n */\nexport interface SentryCloudflareVitePluginOptions {\n /**\n * Experimental options that may change or be removed without notice.\n */\n _experimental?: {\n /**\n * Enables build-time automatic instrumentation of supported dependencies\n * (e.g. database clients like `mysql`) so the Sentry Cloudflare SDK can\n * trace them without monkey-patching, which wouldn't work in workerd anyway.\n *\n * When enabled, the plugin injects `diagnostics_channel.tracingChannel`\n * calls into the bundled packages and, next to each, a snippet that\n * registers the matching Sentry channel-subscriber factory on the global\n * marker, which the SDK picks up in `Sentry.withSentry()`. Both `vite build`\n * and `vite dev` are instrumented.\n *\n * @default false\n * @experimental May change or be removed in any release.\n */\n useDiagnosticsChannelInjection?: boolean;\n /**\n * Automatically wraps your Worker at build time so you don't have to edit\n * your entry: the plugin reads your wrangler config, wraps the default\n * export with `Sentry.withSentry()` (sourcing options from a co-located\n * `instrument.*` file, falling back to env), and wraps any configured\n * Durable Object class with `instrumentDurableObjectWithSentry`. Both\n * `vite build` and `vite dev` are instrumented.\n *\n * @default false\n * @experimental May change or be removed in any release.\n */\n autoInstrumentation?: boolean;\n };\n}\n\n/**\n * Sentry Vite plugin for Cloudflare Workers.\n *\n * Add this plugin to your Vite configuration to enable additional Sentry\n * instrumentation for Cloudflare Workers built with Vite. Configure the Sentry\n * SDK in your Worker as usual with `Sentry.withSentry()`.\n *\n * Currently, the only functionality is the experimental\n * `_experimental.useDiagnosticsChannelInjection` option, which traces supported\n * dependencies (such as database clients) without changing your application\n * code. Without it, the plugin is a no-op.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { cloudflare } from '@cloudflare/vite-plugin';\n * import { sentryCloudflareVitePlugin } from '@sentry/cloudflare/vite';\n * import { defineConfig } from 'vite';\n *\n * export default defineConfig({\n * plugins: [\n * cloudflare(),\n * sentryCloudflareVitePlugin({\n * _experimental: {\n * useDiagnosticsChannelInjection: true,\n * },\n * }),\n * ],\n * });\n * ```\n */\nexport function sentryCloudflareVitePlugin(options: SentryCloudflareVitePluginOptions = {}) {\n return [\n ...(options._experimental?.useDiagnosticsChannelInjection\n ? [sentryOrchestrionPlugin({ injectChannelSubscribers: true })]\n : []),\n ...(options._experimental?.autoInstrumentation ? [sentryCloudflareAutoInstrumentPlugin()] : []),\n ];\n}\n"],"names":["sentryOrchestrionPlugin","sentryCloudflareAutoInstrumentPlugin"],"mappings":";;;;;AA6EO,SAAS,0BAAA,CAA2B,OAAA,GAA6C,EAAC,EAAG;AAC1F,EAAA,OAAO;AAAA,IACL,GAAI,OAAA,CAAQ,aAAA,EAAe,8BAAA,GACvB,CAACA,4BAAA,CAAwB,EAAE,wBAAA,EAA0B,IAAA,EAAM,CAAC,CAAA,GAC5D,EAAC;AAAA,IACL,GAAI,QAAQ,aAAA,EAAe,mBAAA,GAAsB,CAACC,mDAAA,EAAsC,IAAI;AAAC,GAC/F;AACF;;;;"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const node_fs = require('node:fs');
|
|
4
|
+
const node_path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const ENV_FALLBACK_OPTIONS_FN = "() => undefined";
|
|
7
|
+
const OPTIONS_IMPORT_IDENTIFIER = "__SENTRY_OPTIONS_CALLBACK__";
|
|
8
|
+
const INSTRUMENT_FILE_BASENAME = "instrument.server";
|
|
9
|
+
const INSTRUMENT_FILE_EXTENSIONS = ["ts", "mts", "js", "mjs", "cjs"];
|
|
10
|
+
function resolveInstrumentFile(entryFilePath) {
|
|
11
|
+
const dir = node_path.dirname(entryFilePath);
|
|
12
|
+
for (const ext of INSTRUMENT_FILE_EXTENSIONS) {
|
|
13
|
+
const candidate = node_path.resolve(dir, `${INSTRUMENT_FILE_BASENAME}.${ext}`);
|
|
14
|
+
if (node_fs.existsSync(candidate)) return candidate;
|
|
15
|
+
}
|
|
16
|
+
return void 0;
|
|
17
|
+
}
|
|
18
|
+
function buildOptionsImport(entryFilePath, instrumentFilePath) {
|
|
19
|
+
let relativePath = node_path.relative(node_path.dirname(entryFilePath), instrumentFilePath).replace(/\\/g, "/");
|
|
20
|
+
if (!relativePath.startsWith(".")) relativePath = `./${relativePath}`;
|
|
21
|
+
return {
|
|
22
|
+
optionsFn: OPTIONS_IMPORT_IDENTIFIER,
|
|
23
|
+
importStmt: `import ${OPTIONS_IMPORT_IDENTIFIER} from '${relativePath}';
|
|
24
|
+
`
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.ENV_FALLBACK_OPTIONS_FN = ENV_FALLBACK_OPTIONS_FN;
|
|
29
|
+
exports.buildOptionsImport = buildOptionsImport;
|
|
30
|
+
exports.resolveInstrumentFile = resolveInstrumentFile;
|
|
31
|
+
//# sourceMappingURL=instrumentFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentFile.js","sources":["../../../src/vite/instrumentFile.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, relative, resolve } from 'node:path';\n\n// Fallback options callback used when no instrument file is present. Returning\n// `undefined` makes the SDK read all configuration (DSN, release, environment,\n// sample rate, …) from the worker's `env` at runtime.\nexport const ENV_FALLBACK_OPTIONS_FN = '() => undefined';\n\n// Identifier the generated import binds the user's options module to.\nconst OPTIONS_IMPORT_IDENTIFIER = '__SENTRY_OPTIONS_CALLBACK__';\n\n// Conventional, non-configurable name of the Sentry options module. It is\n// looked up next to the worker entry file; its default export is the options\n// callback `(env) => CloudflareOptions`.\nconst INSTRUMENT_FILE_BASENAME = 'instrument.server';\nconst INSTRUMENT_FILE_EXTENSIONS = ['ts', 'mts', 'js', 'mjs', 'cjs'];\n\n/**\n * Locate the conventional `instrument.server.*` module sitting next to the\n * worker entry file. Returns its absolute path, or `undefined` when absent.\n */\nexport function resolveInstrumentFile(entryFilePath: string): string | undefined {\n const dir = dirname(entryFilePath);\n for (const ext of INSTRUMENT_FILE_EXTENSIONS) {\n const candidate = resolve(dir, `${INSTRUMENT_FILE_BASENAME}.${ext}`);\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\n/**\n * Build the `optionsFn` reference and `import` statement for the instrument\n * module whose **default export** is the options callback\n * `(env) => CloudflareOptions`.\n *\n * The import is emitted relative to `entryFilePath` because it is injected into\n * the entry file's source. The file extension is kept: extensionless specifiers\n * only resolve for extensions in Vite's default `resolve.extensions` (which\n * excludes `.cjs`), and keeping it makes our probe order authoritative when\n * several `instrument.server.*` files coexist.\n */\nexport function buildOptionsImport(\n entryFilePath: string,\n instrumentFilePath: string,\n): { optionsFn: string; importStmt: string } {\n let relativePath = relative(dirname(entryFilePath), instrumentFilePath).replace(/\\\\/g, '/');\n if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`;\n\n return {\n optionsFn: OPTIONS_IMPORT_IDENTIFIER,\n importStmt: `import ${OPTIONS_IMPORT_IDENTIFIER} from '${relativePath}';\\n`,\n };\n}\n"],"names":["dirname","resolve","existsSync","relative"],"mappings":";;;;;AAMO,MAAM,uBAAA,GAA0B;AAGvC,MAAM,yBAAA,GAA4B,6BAAA;AAKlC,MAAM,wBAAA,GAA2B,mBAAA;AACjC,MAAM,6BAA6B,CAAC,IAAA,EAAM,KAAA,EAAO,IAAA,EAAM,OAAO,KAAK,CAAA;AAM5D,SAAS,sBAAsB,aAAA,EAA2C;AAC/E,EAAA,MAAM,GAAA,GAAMA,kBAAQ,aAAa,CAAA;AACjC,EAAA,KAAA,MAAW,OAAO,0BAAA,EAA4B;AAC5C,IAAA,MAAM,YAAYC,iBAAA,CAAQ,GAAA,EAAK,GAAG,wBAAwB,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AACnE,IAAA,IAAIC,kBAAA,CAAW,SAAS,CAAA,EAAG,OAAO,SAAA;AAAA,EACpC;AACA,EAAA,OAAO,MAAA;AACT;AAaO,SAAS,kBAAA,CACd,eACA,kBAAA,EAC2C;AAC3C,EAAA,IAAI,YAAA,GAAeC,mBAASH,iBAAA,CAAQ,aAAa,GAAG,kBAAkB,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA;AAC1F,EAAA,IAAI,CAAC,YAAA,CAAa,UAAA,CAAW,GAAG,CAAA,EAAG,YAAA,GAAe,KAAK,YAAY,CAAA,CAAA;AAEnE,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,yBAAA;AAAA,IACX,UAAA,EAAY,CAAA,OAAA,EAAU,yBAAyB,CAAA,OAAA,EAAU,YAAY,CAAA;AAAA;AAAA,GACvE;AACF;;;;;;"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const MagicString = require('magic-string');
|
|
4
|
+
const workerEntrypoint = require('./workerEntrypoint.js');
|
|
5
|
+
|
|
6
|
+
function isCallToMethod(node, methodName) {
|
|
7
|
+
if (node.type !== "CallExpression") return false;
|
|
8
|
+
const callee = node.callee;
|
|
9
|
+
if (!callee) return false;
|
|
10
|
+
if (callee.type === "Identifier" && callee.name === methodName) return true;
|
|
11
|
+
return callee.type === "MemberExpression" && callee.property?.type === "Identifier" && callee.property.name === methodName;
|
|
12
|
+
}
|
|
13
|
+
const WRAPPER_METHODS = {
|
|
14
|
+
durableObject: "instrumentDurableObjectWithSentry",
|
|
15
|
+
workflow: "instrumentWorkflowWithSentry",
|
|
16
|
+
workerEntrypoint: "withSentry"
|
|
17
|
+
};
|
|
18
|
+
function applyAutoInstrumentTransforms(code, ast, ctx) {
|
|
19
|
+
const ms = new MagicString.default(code);
|
|
20
|
+
const topLevelClasses = collectTopLevelClasses(ast);
|
|
21
|
+
const state = {
|
|
22
|
+
ms,
|
|
23
|
+
needsImport: false,
|
|
24
|
+
wrappedClasses: /* @__PURE__ */ new Set(),
|
|
25
|
+
topLevelClasses,
|
|
26
|
+
renamedLocals: /* @__PURE__ */ new Set(),
|
|
27
|
+
classWrappers: ctx.classWrappers,
|
|
28
|
+
workerEntrypointClasses: workerEntrypoint.detectWorkerEntrypointClasses(ast)
|
|
29
|
+
};
|
|
30
|
+
const { wrappedClasses } = state;
|
|
31
|
+
for (const node of ast.body) {
|
|
32
|
+
if (node.type === "ExportNamedDeclaration") {
|
|
33
|
+
handleNamedExport(node, ctx, state);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const node of ast.body) {
|
|
37
|
+
if (node.type === "ExportDefaultDeclaration") {
|
|
38
|
+
wrapDefaultExport(node, ctx, state);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!state.needsImport) {
|
|
42
|
+
if (wrappedClasses.size === 0) return void 0;
|
|
43
|
+
return { code, map: ms.generateMap({ hires: true }), wrappedClasses };
|
|
44
|
+
}
|
|
45
|
+
if (ctx.optionsImport) ms.prepend(ctx.optionsImport);
|
|
46
|
+
ms.prepend("import * as __SENTRY__ from '@sentry/cloudflare';\n");
|
|
47
|
+
return {
|
|
48
|
+
code: ms.toString(),
|
|
49
|
+
map: ms.generateMap({ hires: true }),
|
|
50
|
+
wrappedClasses
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function resolveWrapperKind(exportedName, localName, state) {
|
|
54
|
+
const configured = state.classWrappers.get(exportedName);
|
|
55
|
+
if (configured) return configured;
|
|
56
|
+
if (localName && state.workerEntrypointClasses.has(localName)) return "workerEntrypoint";
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
function collectTopLevelClasses(ast) {
|
|
60
|
+
const classes = /* @__PURE__ */ new Map();
|
|
61
|
+
for (const node of ast.body) {
|
|
62
|
+
if (node.type !== "ClassDeclaration") continue;
|
|
63
|
+
const classNode = node;
|
|
64
|
+
if (classNode.id?.name) classes.set(classNode.id.name, classNode);
|
|
65
|
+
}
|
|
66
|
+
return classes;
|
|
67
|
+
}
|
|
68
|
+
function wrapDefaultExport(node, ctx, state) {
|
|
69
|
+
const decl = node.declaration;
|
|
70
|
+
if (isCallToMethod(decl, "withSentry")) return;
|
|
71
|
+
if (decl.type === "Identifier" && state.renamedLocals.has(decl.name)) return;
|
|
72
|
+
state.ms.overwrite(node.start, decl.start, "const __SENTRY_DEFAULT_EXPORT__ = ");
|
|
73
|
+
state.ms.append(`
|
|
74
|
+
export default __SENTRY__.withSentry(${ctx.optionsFn}, __SENTRY_DEFAULT_EXPORT__);
|
|
75
|
+
`);
|
|
76
|
+
state.needsImport = true;
|
|
77
|
+
}
|
|
78
|
+
function handleNamedExport(node, ctx, state) {
|
|
79
|
+
const decl = node.declaration;
|
|
80
|
+
if (decl?.type === "VariableDeclaration") {
|
|
81
|
+
collectManuallyWrappedClassExports(decl, ctx, state);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (decl?.type === "ClassDeclaration") {
|
|
85
|
+
wrapInlineClassExport(node, decl, ctx, state);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (node.source) return;
|
|
89
|
+
for (const specifier of node.specifiers ?? []) {
|
|
90
|
+
wrapSpecifierExport(specifier, ctx, state);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function collectManuallyWrappedClassExports(varDecl, ctx, state) {
|
|
94
|
+
for (const declarator of varDecl.declarations ?? []) {
|
|
95
|
+
const name = declarator.id?.type === "Identifier" ? declarator.id.name : void 0;
|
|
96
|
+
const kind = name ? ctx.classWrappers.get(name) : void 0;
|
|
97
|
+
if (name && kind && declarator.init && isCallToMethod(declarator.init, WRAPPER_METHODS[kind])) {
|
|
98
|
+
state.wrappedClasses.add(name);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function wrapInlineClassExport(exportNode, classDecl, ctx, state) {
|
|
103
|
+
const classId = classDecl.id;
|
|
104
|
+
const kind = classId ? resolveWrapperKind(classId.name, classId.name, state) : void 0;
|
|
105
|
+
if (!classId || !kind) return;
|
|
106
|
+
const className = classId.name;
|
|
107
|
+
const renamedClass = `__SENTRY_ORIGINAL_${className}__`;
|
|
108
|
+
state.ms.overwrite(exportNode.start, classDecl.start, "");
|
|
109
|
+
state.ms.overwrite(classId.start, classId.end, renamedClass);
|
|
110
|
+
state.ms.appendLeft(
|
|
111
|
+
exportNode.end,
|
|
112
|
+
`
|
|
113
|
+
export const ${className} = __SENTRY__.${WRAPPER_METHODS[kind]}(${ctx.optionsFn}, ${renamedClass});
|
|
114
|
+
`
|
|
115
|
+
);
|
|
116
|
+
state.wrappedClasses.add(className);
|
|
117
|
+
state.renamedLocals.add(className);
|
|
118
|
+
state.needsImport = true;
|
|
119
|
+
}
|
|
120
|
+
function wrapSpecifierExport(specifier, ctx, state) {
|
|
121
|
+
if (specifier.type !== "ExportSpecifier" || specifier.exported?.type !== "Identifier") return;
|
|
122
|
+
const exportedName = specifier.exported.name;
|
|
123
|
+
if (!exportedName) return;
|
|
124
|
+
const localName = specifier.local?.type === "Identifier" ? specifier.local.name : void 0;
|
|
125
|
+
const kind = resolveWrapperKind(exportedName, localName, state);
|
|
126
|
+
if (!kind) return;
|
|
127
|
+
const localClass = localName ? state.topLevelClasses.get(localName) : void 0;
|
|
128
|
+
if (!localName || !localClass?.id) return;
|
|
129
|
+
state.wrappedClasses.add(exportedName);
|
|
130
|
+
state.needsImport = true;
|
|
131
|
+
if (state.renamedLocals.has(localName)) return;
|
|
132
|
+
state.renamedLocals.add(localName);
|
|
133
|
+
const renamedClass = `__SENTRY_ORIGINAL_${localName}__`;
|
|
134
|
+
state.ms.overwrite(localClass.id.start, localClass.id.end, renamedClass);
|
|
135
|
+
state.ms.appendLeft(
|
|
136
|
+
localClass.end,
|
|
137
|
+
`
|
|
138
|
+
const ${localName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${ctx.optionsFn}, ${renamedClass});
|
|
139
|
+
`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
exports.applyAutoInstrumentTransforms = applyAutoInstrumentTransforms;
|
|
144
|
+
//# sourceMappingURL=transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.js","sources":["../../../src/vite/transform.ts"],"sourcesContent":["import MagicString from 'magic-string';\nimport { detectWorkerEntrypointClasses } from './workerEntrypoint';\n\n// ---------------------------------------------------------------------------\n// Minimal ESTree node types for the AST nodes we inspect.\n// ---------------------------------------------------------------------------\n\nexport interface BaseNode {\n type: string;\n start: number;\n end: number;\n}\n\nexport interface ProgramBody {\n body: BaseNode[];\n}\n\ninterface IdentifierNode extends BaseNode {\n name: string;\n}\n\ninterface CalleeNode {\n type: string;\n name?: string;\n property?: { type: string; name?: string };\n}\n\ninterface CallExpressionNode extends BaseNode {\n callee?: CalleeNode;\n}\n\ninterface ClassDeclarationNode extends BaseNode {\n id?: IdentifierNode | null;\n}\n\ninterface ExportDefaultNode extends BaseNode {\n declaration: BaseNode;\n}\n\ninterface ExportSpecifierNode {\n type: string;\n local?: { type: string; name?: string };\n exported?: { type: string; name?: string };\n}\n\ninterface ExportNamedNode extends BaseNode {\n declaration?: BaseNode | null;\n source?: unknown;\n specifiers?: ExportSpecifierNode[];\n}\n\ninterface VariableDeclaratorNode {\n id?: { type: string; name?: string };\n init?: BaseNode | null;\n}\n\ninterface VariableDeclarationNode extends BaseNode {\n declarations?: VariableDeclaratorNode[];\n}\n\nfunction isCallToMethod(node: BaseNode, methodName: string): boolean {\n if (node.type !== 'CallExpression') return false;\n const callee = (node as CallExpressionNode).callee;\n if (!callee) return false;\n if (callee.type === 'Identifier' && callee.name === methodName) return true;\n return (\n callee.type === 'MemberExpression' && callee.property?.type === 'Identifier' && callee.property.name === methodName\n );\n}\n\n/**\n * The kind of Sentry wrapper to apply to an exported class.\n *\n * `durableObject` and `workflow` are keyed by name from the wrangler config\n * (`durable_objects.bindings`, `workflows`), since those class names are\n * authoritative there. `workerEntrypoint` is different: a worker's own\n * entrypoints aren't enumerated in its config, so they're detected structurally\n * (a class extending `WorkerEntrypoint` from `cloudflare:workers`), with the\n * config providing only a fallback for self-bound entrypoints whose base class\n * lives in another module.\n */\nexport type ClassWrapperKind = 'durableObject' | 'workflow' | 'workerEntrypoint';\n\n/**\n * The `@sentry/cloudflare` helper each wrapper kind emits. All share the same\n * `(optionsCallback, Class)` signature. `WorkerEntrypoint` classes use\n * `withSentry`, which runtime-detects the class type and routes accordingly.\n */\nconst WRAPPER_METHODS: Record<ClassWrapperKind, string> = {\n durableObject: 'instrumentDurableObjectWithSentry',\n workflow: 'instrumentWorkflowWithSentry',\n workerEntrypoint: 'withSentry',\n};\n\nexport interface TransformContext {\n /**\n * Exported class name → the kind of Sentry wrapper to apply. Populated from\n * the wrangler config, so the transform can wrap by name without resolving\n * each class's base type.\n */\n classWrappers: Map<string, ClassWrapperKind>;\n optionsFn: string;\n /** Import statement prepended when `optionsFn` references a separate module. */\n optionsImport?: string;\n}\n\nexport interface TransformResult {\n code: string;\n map: ReturnType<MagicString['generateMap']>;\n /**\n * The configured class names that were actually wrapped. Lets the plugin warn\n * about configured classes it could not find, instead of silently leaving\n * them uninstrumented.\n */\n wrappedClasses: Set<string>;\n}\n\n/**\n * Rewrite the worker entry source to wrap its default export with `withSentry`\n * and any configured class export with its matching Sentry wrapper (see\n * {@link TransformContext.classWrappers}, e.g. Durable Object classes with\n * `instrumentDurableObjectWithSentry`).\n *\n * Handles both `export class MyDO {}` and the specifier form\n * (`class MyDO {}` … `export { MyDO }` / `export { Foo as MyDO }`).\n * Re-exports from other modules (`export { MyDO } from './do'`) cannot be\n * wrapped here and are left alone — the plugin warns about them via\n * {@link TransformResult.wrappedClasses}.\n *\n * Exported (rather than inlined into the plugin) so it can be unit-tested with a\n * plain AST and no Vite context. Returns `undefined` when nothing was wrapped and\n * there are no already-manually-wrapped classes to report.\n */\nexport function applyAutoInstrumentTransforms(\n code: string,\n ast: ProgramBody,\n ctx: TransformContext,\n): TransformResult | undefined {\n const ms = new MagicString(code);\n const topLevelClasses = collectTopLevelClasses(ast);\n const state: TransformState = {\n ms,\n needsImport: false,\n wrappedClasses: new Set<string>(),\n topLevelClasses,\n renamedLocals: new Set<string>(),\n classWrappers: ctx.classWrappers,\n workerEntrypointClasses: detectWorkerEntrypointClasses(ast),\n };\n const { wrappedClasses } = state;\n\n // Named exports first, regardless of source order: the default-export handler\n // needs to know which local bindings a named export already wrapped, so it can\n // skip a class that is both exported by name and re-exported as default (which\n // would otherwise wrap it twice).\n for (const node of ast.body) {\n if (node.type === 'ExportNamedDeclaration') {\n handleNamedExport(node as ExportNamedNode, ctx, state);\n }\n }\n for (const node of ast.body) {\n if (node.type === 'ExportDefaultDeclaration') {\n wrapDefaultExport(node as ExportDefaultNode, ctx, state);\n }\n }\n\n if (!state.needsImport) {\n // Nothing was rewritten. Still surface any classes found already wrapped\n // manually (via `wrappedClasses`) so the caller doesn't warn about them;\n // return undefined only when there was nothing to report either.\n if (wrappedClasses.size === 0) return undefined;\n return { code, map: ms.generateMap({ hires: true }), wrappedClasses };\n }\n\n if (ctx.optionsImport) ms.prepend(ctx.optionsImport);\n ms.prepend(\"import * as __SENTRY__ from '@sentry/cloudflare';\\n\");\n\n return {\n code: ms.toString(),\n map: ms.generateMap({ hires: true }),\n wrappedClasses,\n };\n}\n\ninterface TransformState {\n ms: MagicString;\n needsImport: boolean;\n wrappedClasses: Set<string>;\n /**\n * Top-level (non-exported) class declarations, so specifier exports like\n * `export { MyDO }` can locate the class they refer to.\n */\n topLevelClasses: Map<string, ClassDeclarationNode>;\n /**\n * Local class names already renamed + wrapped, so two specifiers pointing at\n * the same class don't produce duplicate bindings.\n */\n renamedLocals: Set<string>;\n /** Class name → wrapper kind, keyed by the *exported* name (from config). */\n classWrappers: Map<string, ClassWrapperKind>;\n /**\n * Local class names detected as `WorkerEntrypoint` subclasses in this module,\n * so they can be wrapped without a config entry.\n */\n workerEntrypointClasses: Set<string>;\n}\n\n/**\n * Resolve the wrapper kind for a class export.\n *\n * Config (`classWrappers`) wins — it's authoritative for Durable Objects and\n * Workflows, and provides the self-binding fallback for WorkerEntrypoints whose\n * base class this module can't see. Otherwise a structurally-detected\n * `WorkerEntrypoint` subclass (matched by its *local* name) gets wrapped with\n * `withSentry`.\n */\nfunction resolveWrapperKind(\n exportedName: string,\n localName: string | undefined,\n state: TransformState,\n): ClassWrapperKind | undefined {\n const configured = state.classWrappers.get(exportedName);\n if (configured) return configured;\n if (localName && state.workerEntrypointClasses.has(localName)) return 'workerEntrypoint';\n return undefined;\n}\n\nfunction collectTopLevelClasses(ast: ProgramBody): Map<string, ClassDeclarationNode> {\n const classes = new Map<string, ClassDeclarationNode>();\n for (const node of ast.body) {\n if (node.type !== 'ClassDeclaration') continue;\n const classNode = node as ClassDeclarationNode;\n if (classNode.id?.name) classes.set(classNode.id.name, classNode);\n }\n return classes;\n}\n\nfunction wrapDefaultExport(node: ExportDefaultNode, ctx: TransformContext, state: TransformState): void {\n const decl = node.declaration;\n\n // Already wrapped — leave it alone\n if (isCallToMethod(decl, 'withSentry')) return;\n\n // `export default Foo` where `Foo` is a local class already wrapped by a named\n // export (e.g. a self-bound WorkerEntrypoint also used as the default handler).\n // Wrapping again would produce `withSentry(withSentry(...))`.\n if (decl.type === 'Identifier' && state.renamedLocals.has((decl as IdentifierNode).name)) return;\n\n // `export default <expr>` → `const __SENTRY_DEFAULT_EXPORT__ = <expr>`\n // MagicString positions are always relative to the original source.\n state.ms.overwrite(node.start, decl.start, 'const __SENTRY_DEFAULT_EXPORT__ = ');\n state.ms.append(`\\nexport default __SENTRY__.withSentry(${ctx.optionsFn}, __SENTRY_DEFAULT_EXPORT__);\\n`);\n state.needsImport = true;\n}\n\nfunction handleNamedExport(node: ExportNamedNode, ctx: TransformContext, state: TransformState): void {\n const decl = node.declaration;\n\n // ---- Manually wrapped class export ----\n // `export const MyDO = instrumentDurableObjectWithSentry(...)` — count it\n // as wrapped so the plugin doesn't warn about it, but leave it alone.\n if (decl?.type === 'VariableDeclaration') {\n collectManuallyWrappedClassExports(decl as VariableDeclarationNode, ctx, state);\n return;\n }\n\n // ---- Named class export matching a configured binding ----\n if (decl?.type === 'ClassDeclaration') {\n wrapInlineClassExport(node, decl as ClassDeclarationNode, ctx, state);\n return;\n }\n\n // ---- Specifier export of a local class (`export { Foo as MyDO }`) ----\n // Re-exports from another module carry a `source` — nothing local to wrap.\n if (node.source) return;\n for (const specifier of node.specifiers ?? []) {\n wrapSpecifierExport(specifier, ctx, state);\n }\n}\n\nfunction collectManuallyWrappedClassExports(\n varDecl: VariableDeclarationNode,\n ctx: TransformContext,\n state: TransformState,\n): void {\n for (const declarator of varDecl.declarations ?? []) {\n const name = declarator.id?.type === 'Identifier' ? declarator.id.name : undefined;\n const kind = name ? ctx.classWrappers.get(name) : undefined;\n if (name && kind && declarator.init && isCallToMethod(declarator.init, WRAPPER_METHODS[kind])) {\n state.wrappedClasses.add(name);\n }\n }\n}\n\nfunction wrapInlineClassExport(\n exportNode: ExportNamedNode,\n classDecl: ClassDeclarationNode,\n ctx: TransformContext,\n state: TransformState,\n): void {\n const classId = classDecl.id;\n // Inline export: the exported name and the local class name are the same.\n const kind = classId ? resolveWrapperKind(classId.name, classId.name, state) : undefined;\n if (!classId || !kind) return;\n\n const className = classId.name;\n const renamedClass = `__SENTRY_ORIGINAL_${className}__`;\n\n // Strip the `export ` keyword\n state.ms.overwrite(exportNode.start, classDecl.start, '');\n\n // Rename the class to avoid a duplicate binding\n state.ms.overwrite(classId.start, classId.end, renamedClass);\n\n // Insert the wrapped re-export after the class body\n state.ms.appendLeft(\n exportNode.end,\n `\\nexport const ${className} = __SENTRY__.${WRAPPER_METHODS[kind]}(${ctx.optionsFn}, ${renamedClass});\\n`,\n );\n\n state.wrappedClasses.add(className);\n state.renamedLocals.add(className);\n state.needsImport = true;\n}\n\nfunction wrapSpecifierExport(specifier: ExportSpecifierNode, ctx: TransformContext, state: TransformState): void {\n if (specifier.type !== 'ExportSpecifier' || specifier.exported?.type !== 'Identifier') return;\n const exportedName = specifier.exported.name;\n if (!exportedName) return;\n\n const localName = specifier.local?.type === 'Identifier' ? specifier.local.name : undefined;\n const kind = resolveWrapperKind(exportedName, localName, state);\n if (!kind) return;\n\n const localClass = localName ? state.topLevelClasses.get(localName) : undefined;\n if (!localName || !localClass?.id) return;\n\n state.wrappedClasses.add(exportedName);\n state.needsImport = true;\n if (state.renamedLocals.has(localName)) return;\n state.renamedLocals.add(localName);\n\n const renamedClass = `__SENTRY_ORIGINAL_${localName}__`;\n state.ms.overwrite(localClass.id.start, localClass.id.end, renamedClass);\n // The existing `export { ... }` statement keeps exporting the (now\n // wrapped) `localName` binding, so the wrapper is NOT exported here.\n state.ms.appendLeft(\n localClass.end,\n `\\nconst ${localName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${ctx.optionsFn}, ${renamedClass});\\n`,\n );\n}\n"],"names":["MagicString","detectWorkerEntrypointClasses"],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
function detectWorkerEntrypointClasses(ast) {
|
|
4
|
+
const bases = collectWorkerEntrypointImports(ast);
|
|
5
|
+
if (bases.named.size === 0 && bases.namespaces.size === 0) {
|
|
6
|
+
return /* @__PURE__ */ new Set();
|
|
7
|
+
}
|
|
8
|
+
const classes = /* @__PURE__ */ new Map();
|
|
9
|
+
for (const node of ast.body) {
|
|
10
|
+
const classNode = asClassDeclaration(node);
|
|
11
|
+
if (classNode?.id?.name) classes.set(classNode.id.name, classNode);
|
|
12
|
+
}
|
|
13
|
+
const entrypoints = /* @__PURE__ */ new Set();
|
|
14
|
+
let changed = true;
|
|
15
|
+
while (changed) {
|
|
16
|
+
changed = false;
|
|
17
|
+
for (const [name, classNode] of classes) {
|
|
18
|
+
if (entrypoints.has(name)) continue;
|
|
19
|
+
if (extendsWorkerEntrypoint(classNode.superClass, bases, entrypoints)) {
|
|
20
|
+
entrypoints.add(name);
|
|
21
|
+
changed = true;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return entrypoints;
|
|
26
|
+
}
|
|
27
|
+
function asClassDeclaration(node) {
|
|
28
|
+
if (node.type === "ClassDeclaration") return node;
|
|
29
|
+
if (node.type === "ExportNamedDeclaration") {
|
|
30
|
+
const decl = node.declaration;
|
|
31
|
+
if (decl?.type === "ClassDeclaration") return decl;
|
|
32
|
+
}
|
|
33
|
+
return void 0;
|
|
34
|
+
}
|
|
35
|
+
function collectWorkerEntrypointImports(ast) {
|
|
36
|
+
const named = /* @__PURE__ */ new Set();
|
|
37
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
38
|
+
for (const node of ast.body) {
|
|
39
|
+
if (node.type !== "ImportDeclaration") continue;
|
|
40
|
+
const importNode = node;
|
|
41
|
+
if (importNode.source?.value !== "cloudflare:workers") continue;
|
|
42
|
+
for (const specifier of importNode.specifiers ?? []) {
|
|
43
|
+
if (specifier.type === "ImportSpecifier" && specifier.imported?.name === "WorkerEntrypoint" && specifier.local?.name) {
|
|
44
|
+
named.add(specifier.local.name);
|
|
45
|
+
} else if (specifier.type === "ImportNamespaceSpecifier" && specifier.local?.name) {
|
|
46
|
+
namespaces.add(specifier.local.name);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { named, namespaces };
|
|
51
|
+
}
|
|
52
|
+
function extendsWorkerEntrypoint(superClass, bases, detected) {
|
|
53
|
+
if (!superClass) return false;
|
|
54
|
+
if (superClass.type === "Identifier") {
|
|
55
|
+
const name = superClass.name;
|
|
56
|
+
return bases.named.has(name) || detected.has(name);
|
|
57
|
+
}
|
|
58
|
+
if (superClass.type === "MemberExpression") {
|
|
59
|
+
const member = superClass;
|
|
60
|
+
return member.object?.type === "Identifier" && !!member.object.name && bases.namespaces.has(member.object.name) && member.property?.name === "WorkerEntrypoint";
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
exports.detectWorkerEntrypointClasses = detectWorkerEntrypointClasses;
|
|
66
|
+
//# sourceMappingURL=workerEntrypoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workerEntrypoint.js","sources":["../../../src/vite/workerEntrypoint.ts"],"sourcesContent":["import type { BaseNode, ProgramBody } from './transform';\n\n// ---------------------------------------------------------------------------\n// Minimal ESTree node shapes for structural WorkerEntrypoint detection.\n// ---------------------------------------------------------------------------\n\ninterface IdentifierNode extends BaseNode {\n name: string;\n}\n\ninterface MemberExpressionNode extends BaseNode {\n object?: { type: string; name?: string };\n property?: { type: string; name?: string };\n}\n\ninterface ClassDeclarationNode extends BaseNode {\n id?: IdentifierNode | null;\n superClass?: BaseNode | null;\n}\n\ninterface ExportNamedDeclNode extends BaseNode {\n declaration?: BaseNode | null;\n}\n\ninterface ImportSpecifierNode {\n type: string;\n imported?: { type: string; name?: string };\n local?: { type: string; name?: string };\n}\n\ninterface ImportDeclarationNode extends BaseNode {\n source?: { value?: unknown };\n specifiers?: ImportSpecifierNode[];\n}\n\ninterface WorkerEntrypointBases {\n /** Local identifiers bound to the named `WorkerEntrypoint` import. */\n named: Set<string>;\n /** Local identifiers bound to a `* as ns` import of `cloudflare:workers`. */\n namespaces: Set<string>;\n}\n\n/**\n * Find top-level classes that (transitively, within this module) extend\n * `WorkerEntrypoint` imported from `cloudflare:workers`. esbuild has already\n * stripped TypeScript by transform time, so a superclass is a plain identifier\n * (`extends WorkerEntrypoint`) or member access (`extends cf.WorkerEntrypoint`).\n *\n * Only same-file base chains are resolvable here; a base class imported from\n * another module is invisible and relies on the config self-binding fallback.\n */\nexport function detectWorkerEntrypointClasses(ast: ProgramBody): Set<string> {\n const bases = collectWorkerEntrypointImports(ast);\n if (bases.named.size === 0 && bases.namespaces.size === 0) {\n return new Set<string>();\n }\n\n // Every top-level class, including the `export class Foo {}` form (where the\n // class is nested inside an ExportNamedDeclaration) so directly-exported\n // entrypoints are seen too.\n const classes = new Map<string, ClassDeclarationNode>();\n for (const node of ast.body) {\n const classNode = asClassDeclaration(node);\n if (classNode?.id?.name) classes.set(classNode.id.name, classNode);\n }\n\n const entrypoints = new Set<string>();\n // Iterate to a fixed point so an indirect chain (A extends B extends WE) is\n // fully resolved regardless of declaration order.\n let changed = true;\n while (changed) {\n changed = false;\n for (const [name, classNode] of classes) {\n if (entrypoints.has(name)) continue;\n if (extendsWorkerEntrypoint(classNode.superClass, bases, entrypoints)) {\n entrypoints.add(name);\n changed = true;\n }\n }\n }\n return entrypoints;\n}\n\n/** Unwrap `export class Foo {}` to its ClassDeclaration; pass bare classes through. */\nfunction asClassDeclaration(node: BaseNode): ClassDeclarationNode | undefined {\n if (node.type === 'ClassDeclaration') return node as ClassDeclarationNode;\n if (node.type === 'ExportNamedDeclaration') {\n const decl = (node as ExportNamedDeclNode).declaration;\n if (decl?.type === 'ClassDeclaration') return decl as ClassDeclarationNode;\n }\n return undefined;\n}\n\nfunction collectWorkerEntrypointImports(ast: ProgramBody): WorkerEntrypointBases {\n const named = new Set<string>();\n const namespaces = new Set<string>();\n for (const node of ast.body) {\n if (node.type !== 'ImportDeclaration') continue;\n const importNode = node as ImportDeclarationNode;\n if (importNode.source?.value !== 'cloudflare:workers') continue;\n for (const specifier of importNode.specifiers ?? []) {\n if (\n specifier.type === 'ImportSpecifier' &&\n specifier.imported?.name === 'WorkerEntrypoint' &&\n specifier.local?.name\n ) {\n named.add(specifier.local.name);\n } else if (specifier.type === 'ImportNamespaceSpecifier' && specifier.local?.name) {\n namespaces.add(specifier.local.name);\n }\n }\n }\n return { named, namespaces };\n}\n\n/**\n * Whether a superclass expression resolves to `WorkerEntrypoint` — either a bare\n * identifier from the named import (or an already-detected local subclass), or a\n * `ns.WorkerEntrypoint` member access off a namespace import.\n */\nfunction extendsWorkerEntrypoint(\n superClass: BaseNode | null | undefined,\n bases: WorkerEntrypointBases,\n detected: Set<string>,\n): boolean {\n if (!superClass) return false;\n if (superClass.type === 'Identifier') {\n const name = (superClass as IdentifierNode).name;\n return bases.named.has(name) || detected.has(name);\n }\n if (superClass.type === 'MemberExpression') {\n const member = superClass as MemberExpressionNode;\n return (\n member.object?.type === 'Identifier' &&\n !!member.object.name &&\n bases.namespaces.has(member.object.name) &&\n member.property?.name === 'WorkerEntrypoint'\n );\n }\n return false;\n}\n"],"names":[],"mappings":"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"}
|