@sentry/cloudflare 10.67.0 → 10.69.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 +5 -0
- 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 +131 -96
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/index.js +6 -0
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/instrumentations/agents/index.js +14 -0
- package/build/cjs/instrumentations/agents/index.js.map +1 -0
- package/build/cjs/instrumentations/agents/instrumentAgentCallableRpc.js +52 -0
- package/build/cjs/instrumentations/agents/instrumentAgentCallableRpc.js.map +1 -0
- package/build/cjs/instrumentations/agents/instrumentChatAgentConversation.js +31 -0
- package/build/cjs/instrumentations/agents/instrumentChatAgentConversation.js.map +1 -0
- package/build/cjs/instrumentations/agents/types.js +32 -0
- package/build/cjs/instrumentations/agents/types.js.map +1 -0
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js +6 -0
- package/build/cjs/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/cjs/instrumentations/instrumentSqlStorage.js +1 -1
- package/build/cjs/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/cjs/integrations/spotlight.js +64 -0
- package/build/cjs/integrations/spotlight.js.map +1 -0
- package/build/cjs/integrations/tracing/vercelai.js.map +1 -1
- package/build/cjs/nodejs_compat/index.js +10 -4
- 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/options.js +14 -1
- package/build/cjs/options.js.map +1 -1
- package/build/cjs/sdk.js +20 -1
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/utils/internalSqlQuery.js +13 -7
- package/build/cjs/utils/internalSqlQuery.js.map +1 -1
- package/build/cjs/utils/internalStorageKey.js +44 -0
- package/build/cjs/utils/internalStorageKey.js.map +1 -0
- package/build/cjs/vite/agentClass.js +114 -0
- package/build/cjs/vite/agentClass.js.map +1 -0
- package/build/cjs/vite/autoInstrument.js +94 -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/moduleShape.js +231 -0
- package/build/cjs/vite/moduleShape.js.map +1 -0
- package/build/cjs/vite/transform.js +149 -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/esm/client.js +6 -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 +129 -97
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/index.js +4 -2
- package/build/esm/index.js.map +1 -1
- package/build/esm/instrumentations/agents/index.js +12 -0
- package/build/esm/instrumentations/agents/index.js.map +1 -0
- package/build/esm/instrumentations/agents/instrumentAgentCallableRpc.js +50 -0
- package/build/esm/instrumentations/agents/instrumentAgentCallableRpc.js.map +1 -0
- package/build/esm/instrumentations/agents/instrumentChatAgentConversation.js +29 -0
- package/build/esm/instrumentations/agents/instrumentChatAgentConversation.js.map +1 -0
- package/build/esm/instrumentations/agents/types.js +26 -0
- package/build/esm/instrumentations/agents/types.js.map +1 -0
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js +7 -1
- package/build/esm/instrumentations/instrumentDurableObjectStorage.js.map +1 -1
- package/build/esm/instrumentations/instrumentSqlStorage.js +1 -1
- package/build/esm/instrumentations/instrumentSqlStorage.js.map +1 -1
- package/build/esm/integrations/spotlight.js +61 -0
- package/build/esm/integrations/spotlight.js.map +1 -0
- package/build/esm/integrations/tracing/vercelai.js.map +1 -1
- package/build/esm/nodejs_compat/index.js +5 -3
- 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/options.js +14 -1
- package/build/esm/options.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/sdk.js +21 -2
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/utils/internalSqlQuery.js +13 -7
- package/build/esm/utils/internalSqlQuery.js.map +1 -1
- package/build/esm/utils/internalStorageKey.js +41 -0
- package/build/esm/utils/internalStorageKey.js.map +1 -0
- package/build/esm/utils/traceLinks.js +1 -1
- package/build/esm/vite/agentClass.js +111 -0
- package/build/esm/vite/agentClass.js.map +1 -0
- package/build/esm/vite/autoInstrument.js +92 -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/moduleShape.js +227 -0
- package/build/esm/vite/moduleShape.js.map +1 -0
- package/build/esm/vite/transform.js +147 -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/types/client.d.ts +37 -0
- 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 +81 -0
- 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/instrumentations/agents/index.d.ts +24 -0
- package/build/types/instrumentations/agents/index.d.ts.map +1 -0
- package/build/types/instrumentations/agents/instrumentAgentCallableRpc.d.ts +11 -0
- package/build/types/instrumentations/agents/instrumentAgentCallableRpc.d.ts.map +1 -0
- package/build/types/instrumentations/agents/instrumentChatAgentConversation.d.ts +22 -0
- package/build/types/instrumentations/agents/instrumentChatAgentConversation.d.ts.map +1 -0
- package/build/types/instrumentations/agents/types.d.ts +49 -0
- package/build/types/instrumentations/agents/types.d.ts.map +1 -0
- package/build/types/instrumentations/instrumentDurableObjectStorage.d.ts.map +1 -1
- package/build/types/integrations/spotlight.d.ts +22 -0
- package/build/types/integrations/spotlight.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/options.d.ts.map +1 -1
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types/utils/internalSqlQuery.d.ts +4 -2
- package/build/types/utils/internalSqlQuery.d.ts.map +1 -1
- package/build/types/utils/internalStorageKey.d.ts +22 -0
- package/build/types/utils/internalStorageKey.d.ts.map +1 -0
- package/build/types/vite/agentClass.d.ts +41 -0
- package/build/types/vite/agentClass.d.ts.map +1 -0
- package/build/types/vite/autoInstrument.d.ts +22 -0
- package/build/types/vite/autoInstrument.d.ts.map +1 -0
- package/build/types/vite/index.d.ts +98 -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/moduleShape.d.ts +52 -0
- package/build/types/vite/moduleShape.d.ts.map +1 -0
- package/build/types/vite/transform.d.ts +65 -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-ts3.8/client.d.ts +37 -0
- package/build/types-ts3.8/defineCloudflareOptions.d.ts +38 -0
- package/build/types-ts3.8/durableobject.d.ts +81 -0
- package/build/types-ts3.8/index.d.ts +4 -2
- package/build/types-ts3.8/instrumentations/agents/index.d.ts +24 -0
- package/build/types-ts3.8/instrumentations/agents/instrumentAgentCallableRpc.d.ts +11 -0
- package/build/types-ts3.8/instrumentations/agents/instrumentChatAgentConversation.d.ts +22 -0
- package/build/types-ts3.8/instrumentations/agents/types.d.ts +49 -0
- package/build/types-ts3.8/integrations/spotlight.d.ts +22 -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 +4 -2
- package/build/types-ts3.8/utils/internalStorageKey.d.ts +22 -0
- package/build/types-ts3.8/vite/agentClass.d.ts +41 -0
- package/build/types-ts3.8/vite/autoInstrument.d.ts +22 -0
- package/build/types-ts3.8/vite/index.d.ts +98 -0
- package/build/types-ts3.8/vite/instrumentFile.d.ts +22 -0
- package/build/types-ts3.8/vite/moduleShape.d.ts +52 -0
- package/build/types-ts3.8/vite/transform.d.ts +65 -0
- package/build/types-ts3.8/vite/workerEntrypoint.d.ts +12 -0
- package/build/types-ts3.8/vite/wranglerConfig.d.ts +43 -0
- package/package.json +19 -5
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { defineIntegration, debug, serializeEnvelope, suppressTracing } from '@sentry/core';
|
|
2
|
+
import { DEBUG_BUILD } from '../debug-build.js';
|
|
3
|
+
|
|
4
|
+
const INTEGRATION_NAME = "Spotlight";
|
|
5
|
+
const _spotlightIntegration = ((options = {}) => {
|
|
6
|
+
const sidecarUrl = options.sidecarUrl || "http://localhost:8969/stream";
|
|
7
|
+
return {
|
|
8
|
+
name: INTEGRATION_NAME,
|
|
9
|
+
setup(client) {
|
|
10
|
+
DEBUG_BUILD && debug.log("[Spotlight] Using Sidecar URL", sidecarUrl);
|
|
11
|
+
setupSidecarForwarding(client, sidecarUrl);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
const spotlightIntegration = defineIntegration(_spotlightIntegration);
|
|
16
|
+
function setupSidecarForwarding(client, sidecarUrl) {
|
|
17
|
+
const parsedUrl = parseSidecarUrl(sidecarUrl);
|
|
18
|
+
if (!parsedUrl) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
let failCount = 0;
|
|
22
|
+
client.on("beforeEnvelope", (envelope) => {
|
|
23
|
+
if (failCount > 3) {
|
|
24
|
+
DEBUG_BUILD && debug.warn("[Spotlight] Disabled Sentry -> Spotlight forwarding due to too many failed requests");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const body = serializeEnvelope(envelope);
|
|
28
|
+
suppressTracing(() => {
|
|
29
|
+
fetch(parsedUrl.href, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
body,
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/x-sentry-envelope"
|
|
34
|
+
}
|
|
35
|
+
}).then(
|
|
36
|
+
(res) => {
|
|
37
|
+
res.text().catch(() => {
|
|
38
|
+
});
|
|
39
|
+
if (res.status >= 200 && res.status < 400) {
|
|
40
|
+
failCount = 0;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
() => {
|
|
44
|
+
failCount++;
|
|
45
|
+
DEBUG_BUILD && debug.warn("[Spotlight] Failed to send envelope to Spotlight Sidecar");
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function parseSidecarUrl(url) {
|
|
52
|
+
try {
|
|
53
|
+
return new URL(url);
|
|
54
|
+
} catch {
|
|
55
|
+
DEBUG_BUILD && debug.warn(`[Spotlight] Invalid sidecar URL: ${url}`);
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { INTEGRATION_NAME, spotlightIntegration };
|
|
61
|
+
//# sourceMappingURL=spotlight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spotlight.js","sources":["../../../src/integrations/spotlight.ts"],"sourcesContent":["import type { Client, Envelope, IntegrationFn } from '@sentry/core';\nimport { debug, defineIntegration, serializeEnvelope, suppressTracing } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\ntype SpotlightConnectionOptions = {\n /**\n * Set this if the Spotlight Sidecar is not running on localhost:8969.\n * By default, the URL is set to http://localhost:8969/stream\n */\n sidecarUrl?: string;\n};\n\nexport const INTEGRATION_NAME = 'Spotlight' as const;\n\nconst _spotlightIntegration = ((options: Partial<SpotlightConnectionOptions> = {}) => {\n const sidecarUrl = options.sidecarUrl || 'http://localhost:8969/stream';\n\n return {\n name: INTEGRATION_NAME,\n setup(client) {\n DEBUG_BUILD && debug.log('[Spotlight] Using Sidecar URL', sidecarUrl);\n setupSidecarForwarding(client, sidecarUrl);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Use this integration to send errors and transactions to Spotlight.\n *\n * Learn more about spotlight at https://spotlightjs.com\n *\n * Important: This integration is intended for local development only.\n * Each forwarded envelope counts as a Worker subrequest (50 free / 1000 paid\n * per invocation), so it should not be enabled in production.\n */\nexport const spotlightIntegration = defineIntegration(_spotlightIntegration);\n\nfunction setupSidecarForwarding(client: Client, sidecarUrl: string): void {\n const parsedUrl = parseSidecarUrl(sidecarUrl);\n if (!parsedUrl) {\n return;\n }\n\n let failCount = 0;\n\n client.on('beforeEnvelope', (envelope: Envelope) => {\n if (failCount > 3) {\n DEBUG_BUILD && debug.warn('[Spotlight] Disabled Sentry -> Spotlight forwarding due to too many failed requests');\n return;\n }\n\n const body = serializeEnvelope(envelope);\n\n suppressTracing(() => {\n fetch(parsedUrl.href, {\n method: 'POST',\n body,\n headers: {\n 'Content-Type': 'application/x-sentry-envelope',\n },\n }).then(\n res => {\n // Consume the response body to satisfy Cloudflare Workers' requirement\n // that all fetch response bodies are read or cancelled.\n res.text().catch(() => {\n // no-op\n });\n\n if (res.status >= 200 && res.status < 400) {\n failCount = 0;\n }\n },\n () => {\n failCount++;\n DEBUG_BUILD && debug.warn('[Spotlight] Failed to send envelope to Spotlight Sidecar');\n },\n );\n });\n });\n}\n\nfunction parseSidecarUrl(url: string): URL | undefined {\n try {\n return new URL(url);\n } catch {\n DEBUG_BUILD && debug.warn(`[Spotlight] Invalid sidecar URL: ${url}`);\n return undefined;\n }\n}\n"],"names":[],"mappings":";;;AAYO,MAAM,gBAAA,GAAmB;AAEhC,MAAM,qBAAA,IAAyB,CAAC,OAAA,GAA+C,EAAC,KAAM;AACpF,EAAA,MAAM,UAAA,GAAa,QAAQ,UAAA,IAAc,8BAAA;AAEzC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,MAAM,MAAA,EAAQ;AACZ,MAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,+BAAA,EAAiC,UAAU,CAAA;AACpE,MAAA,sBAAA,CAAuB,QAAQ,UAAU,CAAA;AAAA,IAC3C;AAAA,GACF;AACF,CAAA,CAAA;AAWO,MAAM,oBAAA,GAAuB,kBAAkB,qBAAqB;AAE3E,SAAS,sBAAA,CAAuB,QAAgB,UAAA,EAA0B;AACxE,EAAA,MAAM,SAAA,GAAY,gBAAgB,UAAU,CAAA;AAC5C,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,SAAA,GAAY,CAAA;AAEhB,EAAA,MAAA,CAAO,EAAA,CAAG,gBAAA,EAAkB,CAAC,QAAA,KAAuB;AAClD,IAAA,IAAI,YAAY,CAAA,EAAG;AACjB,MAAA,WAAA,IAAe,KAAA,CAAM,KAAK,qFAAqF,CAAA;AAC/G,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,kBAAkB,QAAQ,CAAA;AAEvC,IAAA,eAAA,CAAgB,MAAM;AACpB,MAAA,KAAA,CAAM,UAAU,IAAA,EAAM;AAAA,QACpB,MAAA,EAAQ,MAAA;AAAA,QACR,IAAA;AAAA,QACA,OAAA,EAAS;AAAA,UACP,cAAA,EAAgB;AAAA;AAClB,OACD,CAAA,CAAE,IAAA;AAAA,QACD,CAAA,GAAA,KAAO;AAGL,UAAA,GAAA,CAAI,IAAA,EAAK,CAAE,KAAA,CAAM,MAAM;AAAA,UAEvB,CAAC,CAAA;AAED,UAAA,IAAI,GAAA,CAAI,MAAA,IAAU,GAAA,IAAO,GAAA,CAAI,SAAS,GAAA,EAAK;AACzC,YAAA,SAAA,GAAY,CAAA;AAAA,UACd;AAAA,QACF,CAAA;AAAA,QACA,MAAM;AACJ,UAAA,SAAA,EAAA;AACA,UAAA,WAAA,IAAe,KAAA,CAAM,KAAK,0DAA0D,CAAA;AAAA,QACtF;AAAA,OACF;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAEA,SAAS,gBAAgB,GAAA,EAA8B;AACrD,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,IAAI,GAAG,CAAA;AAAA,EACpB,CAAA,CAAA,MAAQ;AACN,IAAA,WAAA,IAAe,KAAA,CAAM,IAAA,CAAK,CAAA,iCAAA,EAAoC,GAAG,CAAA,CAAE,CAAA;AACnE,IAAA,OAAO,MAAA;AAAA,EACT;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercelai.js","sources":["../../../../src/integrations/tracing/vercelai.ts"],"sourcesContent":["/**\n * This is a copy of the Vercel AI integration from the node SDK.\n *\n * The only difference is that it does not use `@opentelemetry/instrumentation`\n * because Cloudflare Workers do not support it.\n *\n * Therefore, we cannot automatically patch setting `experimental_telemetry: { isEnabled: true }`\n * and users have to manually set this to get spans.\n */\n\nimport type { IntegrationFn } from '@sentry/core';\nimport { addVercelAiProcessors, defineIntegration } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'VercelAI';\n\ninterface VercelAiOptions {\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n}\n\nconst _vercelAIIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n options,\n setup(client) {\n addVercelAiProcessors(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.\n * This integration is not enabled by default, you need to manually add it.\n *\n * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).\n *\n * You need to enable collecting spans for a specific call by setting\n * `experimental_telemetry.isEnabled` to `true` in the first argument of the function call.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true },\n * });\n * ```\n *\n * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each\n * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs`\n * to `true`.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },\n * });\n */\nexport const vercelAIIntegration = defineIntegration(_vercelAIIntegration);\n"],"names":[],"mappings":";;AAaA,MAAM,gBAAA,GAAmB,UAAA;
|
|
1
|
+
{"version":3,"file":"vercelai.js","sources":["../../../../src/integrations/tracing/vercelai.ts"],"sourcesContent":["/**\n * This is a copy of the Vercel AI integration from the node SDK.\n *\n * The only difference is that it does not use `@opentelemetry/instrumentation`\n * because Cloudflare Workers do not support it.\n *\n * Therefore, we cannot automatically patch setting `experimental_telemetry: { isEnabled: true }`\n * and users have to manually set this to get spans.\n */\n\nimport type { IntegrationFn } from '@sentry/core';\nimport { addVercelAiProcessors, defineIntegration } from '@sentry/core';\n\nconst INTEGRATION_NAME = 'VercelAI';\n\ninterface VercelAiOptions {\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n\n // `recordInputs`/`recordOutputs` are intentionally omitted: this entrypoint only post-processes\n // spans the AI SDK already emitted, so it cannot decide whether inputs/outputs are recorded.\n // Control this per call via `experimental_telemetry.recordInputs`/`recordOutputs`, or use the\n // `@sentry/cloudflare/nodejs_compat` entrypoint for integration-level control on ai >= 7.\n}\n\nconst _vercelAIIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n options,\n setup(client) {\n addVercelAiProcessors(client);\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for the [ai](https://www.npmjs.com/package/ai) library.\n * This integration is not enabled by default, you need to manually add it.\n *\n * For more information, see the [`ai` documentation](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry).\n *\n * You need to enable collecting spans for a specific call by setting\n * `experimental_telemetry.isEnabled` to `true` in the first argument of the function call.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true },\n * });\n * ```\n *\n * If you want to collect inputs and outputs for a specific call, you must specifically opt-in to each\n * function call by setting `experimental_telemetry.recordInputs` and `experimental_telemetry.recordOutputs`\n * to `true`.\n *\n * ```javascript\n * const result = await generateText({\n * model: openai('gpt-4-turbo'),\n * experimental_telemetry: { isEnabled: true, recordInputs: true, recordOutputs: true },\n * });\n */\nexport const vercelAIIntegration = defineIntegration(_vercelAIIntegration);\n"],"names":[],"mappings":";;AAaA,MAAM,gBAAA,GAAmB,UAAA;AAezB,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,OAAA;AAAA,IACA,MAAM,MAAA,EAAQ;AACZ,MAAA,qBAAA,CAAsB,MAAM,CAAA;AAAA,IAC9B;AAAA,GACF;AACF,CAAA,CAAA;AA4BO,MAAM,mBAAA,GAAsB,kBAAkB,oBAAoB;;;;"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
export { prismaIntegration } from '@sentry/
|
|
1
|
+
export { prismaIntegration } from '@sentry/server-utils';
|
|
2
2
|
export { vercelAIIntegration } from './integrations/tracing/vercelai.js';
|
|
3
3
|
export { CloudflareClient } from '../client.js';
|
|
4
|
-
export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, bindScopeToEmitter, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createLangChainCallbackHandler, createTransport, dedupeIntegration, eventFiltersIntegration, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, growthbookIntegration, inboundFiltersIntegration, instrumentAnthropicAiClient, instrumentCreateReactAgent, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentLangGraph, instrumentOpenAiClient, instrumentPostgresJsSql, 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, spanToTraceHeader, startInactiveSpan, startNewTrace, startSpan, startSpanManual, supabaseIntegration, suppressTracing, trpcMiddleware, updateSpanName, withActiveSpan, withIsolationScope, withMonitor, withScope, withStreamedSpan, wrapMcpServerWithSentry, zodErrorsIntegration } from '@sentry/core';
|
|
4
|
+
export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, Scope, addBreadcrumb, addEventProcessor, addIntegration, bindScopeToEmitter, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createLangChainCallbackHandler, createTransport, dedupeIntegration, eventFiltersIntegration, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, growthbookIntegration, inboundFiltersIntegration, instrumentAnthropicAiClient, instrumentCreateReactAgent, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentLangGraph, instrumentOpenAiClient, instrumentPostgresJsSql, instrumentStateGraph, 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, spanToTraceHeader, startInactiveSpan, startNewTrace, startSpan, startSpanManual, supabaseIntegration, suppressTracing, trpcMiddleware, updateSpanName, withActiveSpan, withIsolationScope, withMonitor, withScope, withStreamedSpan, wrapMcpServerWithSentry, zodErrorsIntegration } from '@sentry/core';
|
|
5
|
+
export { defineCloudflareOptions } from '../defineCloudflareOptions.js';
|
|
5
6
|
export { fetchIntegration } from '../integrations/fetch.js';
|
|
6
7
|
export { getDefaultIntegrations } from '../sdk.js';
|
|
7
8
|
export { honoIntegration } from '../integrations/hono.js';
|
|
8
9
|
export { httpServerIntegration } from '../integrations/httpServer.js';
|
|
10
|
+
export { instrumentAgentWithSentry, instrumentDurableObjectWithSentry } from '../durableobject.js';
|
|
9
11
|
export { instrumentD1WithSentry } from '../instrumentations/worker/instrumentD1.js';
|
|
10
|
-
export { instrumentDurableObjectWithSentry } from '../durableobject.js';
|
|
11
12
|
export { instrumentWorkflowWithSentry } from '../workflows.js';
|
|
12
13
|
export { sentryPagesPlugin } from '../pages-plugin.js';
|
|
13
14
|
export { setAsyncLocalStorageAsyncContextStrategy } from '../async.js';
|
|
15
|
+
export { spotlightIntegration } from '../integrations/spotlight.js';
|
|
14
16
|
export { withSentry } from '../withSentry.js';
|
|
15
17
|
export { wrapRequestHandler } from '../request.js';
|
|
16
18
|
//# 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":";;;;;;;;;;;;;;;;"}
|
|
@@ -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"],"mappings":";;;;AAYA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,MAAM,KAAA,GAAQA,oBAA+B,OAAO,CAAA;AACpD,EAAA,MAAM,eAAA,GAAkBC,sBAA8B,OAAO,CAAA;AAE7D,EAAA,OAAO;AAAA,IACL,GAAG,KAAA;AAAA,IACH,GAAG;AAAA,GACL;AACF,CAAA,CAAA;AA4BO,MAAM,mBAAA,GAAsB,kBAAkB,oBAAoB;;;;"}
|
package/build/esm/options.js
CHANGED
|
@@ -12,6 +12,7 @@ function getFinalOptions(userOptions = {}, env) {
|
|
|
12
12
|
}
|
|
13
13
|
const release = "SENTRY_RELEASE" in env && typeof env.SENTRY_RELEASE === "string" ? env.SENTRY_RELEASE : "CF_VERSION_METADATA" in env && isVersionMetadata(env.CF_VERSION_METADATA) ? env.CF_VERSION_METADATA.id : void 0;
|
|
14
14
|
const tracesSampleRate = userOptions.tracesSampleRate ?? parseFloat(getEnvVar(env, "SENTRY_TRACES_SAMPLE_RATE") ?? "");
|
|
15
|
+
const spotlight = getSpotlightFromEnv(userOptions.spotlight, getEnvVar(env, "SENTRY_SPOTLIGHT"));
|
|
15
16
|
return {
|
|
16
17
|
release,
|
|
17
18
|
...userOptions,
|
|
@@ -19,9 +20,21 @@ function getFinalOptions(userOptions = {}, env) {
|
|
|
19
20
|
environment: userOptions.environment ?? getEnvVar(env, "SENTRY_ENVIRONMENT"),
|
|
20
21
|
tracesSampleRate: isFinite(tracesSampleRate) ? tracesSampleRate : void 0,
|
|
21
22
|
debug: userOptions.debug ?? envToBool(getEnvVar(env, "SENTRY_DEBUG")),
|
|
22
|
-
tunnel: userOptions.tunnel ?? getEnvVar(env, "SENTRY_TUNNEL")
|
|
23
|
+
tunnel: userOptions.tunnel ?? getEnvVar(env, "SENTRY_TUNNEL"),
|
|
24
|
+
spotlight
|
|
23
25
|
};
|
|
24
26
|
}
|
|
27
|
+
function getSpotlightFromEnv(optionsSpotlight, envVar) {
|
|
28
|
+
if (optionsSpotlight === false) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (typeof optionsSpotlight === "string") {
|
|
32
|
+
return optionsSpotlight;
|
|
33
|
+
}
|
|
34
|
+
const envBool = envToBool(envVar, { strict: true });
|
|
35
|
+
const envUrl = envBool === null && envVar ? envVar : void 0;
|
|
36
|
+
return optionsSpotlight === true ? envUrl ?? true : envBool ?? envUrl;
|
|
37
|
+
}
|
|
25
38
|
|
|
26
39
|
export { getFinalOptions };
|
|
27
40
|
//# sourceMappingURL=options.js.map
|
package/build/esm/options.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.js","sources":["../../src/options.ts"],"sourcesContent":["import { isObjectLike, envToBool } from '@sentry/core';\nimport type { CloudflareOptions } from './client';\n\n/**\n * Cloudflare's version metadata binding structure.\n * @see https://developers.cloudflare.com/workers/runtime-apis/bindings/version-metadata/\n */\ninterface CfVersionMetadata {\n id: string;\n tag?: string;\n timestamp?: string;\n}\n\n/**\n * Checks if the value is a valid CF_VERSION_METADATA binding.\n */\nfunction isVersionMetadata(value: unknown): value is CfVersionMetadata {\n return isObjectLike(value) && 'id' in value && typeof value.id === 'string';\n}\n\nfunction getEnvVar<T extends Record<string, unknown>>(env: unknown, varName: keyof T): string | undefined {\n return isObjectLike(env) && varName in env && typeof (env as T)[varName] === 'string'\n ? ((env as T)[varName] as string)\n : undefined;\n}\n\n/**\n * Merges the options passed in from the user with the options we read from\n * the Cloudflare `env` environment variable object.\n *\n * Release is determined with the following priority (highest to lowest):\n * 1. User-provided release option\n * 2. SENTRY_RELEASE environment variable\n * 3. CF_VERSION_METADATA.id binding (if configured in the wrangler config)\n *\n * @param userOptions - The options passed in from the user.\n * @param env - The environment variables.\n *\n * @returns The final options.\n */\nexport function getFinalOptions(userOptions: CloudflareOptions = {}, env: unknown): CloudflareOptions {\n if (typeof env !== 'object' || env === null) {\n return userOptions;\n }\n\n // Priority: userOptions.release > SENTRY_RELEASE > CF_VERSION_METADATA.id\n const release =\n 'SENTRY_RELEASE' in env && typeof env.SENTRY_RELEASE === 'string'\n ? env.SENTRY_RELEASE\n : 'CF_VERSION_METADATA' in env && isVersionMetadata(env.CF_VERSION_METADATA)\n ? env.CF_VERSION_METADATA.id\n : undefined;\n\n const tracesSampleRate =\n userOptions.tracesSampleRate ?? parseFloat(getEnvVar(env, 'SENTRY_TRACES_SAMPLE_RATE') ?? '');\n\n return {\n release,\n ...userOptions,\n dsn: userOptions.dsn ?? getEnvVar(env, 'SENTRY_DSN'),\n environment: userOptions.environment ?? getEnvVar(env, 'SENTRY_ENVIRONMENT'),\n tracesSampleRate: isFinite(tracesSampleRate) ? tracesSampleRate : undefined,\n debug: userOptions.debug ?? envToBool(getEnvVar(env, 'SENTRY_DEBUG')),\n tunnel: userOptions.tunnel ?? getEnvVar(env, 'SENTRY_TUNNEL'),\n };\n}\n"],"names":[],"mappings":";;AAgBA,SAAS,kBAAkB,KAAA,EAA4C;AACrE,EAAA,OAAO,aAAa,KAAK,CAAA,IAAK,QAAQ,KAAA,IAAS,OAAO,MAAM,EAAA,KAAO,QAAA;AACrE;AAEA,SAAS,SAAA,CAA6C,KAAc,OAAA,EAAsC;AACxG,EAAA,OAAO,YAAA,CAAa,GAAG,CAAA,IAAK,OAAA,IAAW,GAAA,IAAO,OAAQ,GAAA,CAAU,OAAO,CAAA,KAAM,QAAA,GACvE,GAAA,CAAU,OAAO,CAAA,GACnB,MAAA;AACN;AAgBO,SAAS,eAAA,CAAgB,WAAA,GAAiC,EAAC,EAAG,GAAA,EAAiC;AACpG,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,IAAA,EAAM;AAC3C,IAAA,OAAO,WAAA;AAAA,EACT;AAGA,EAAA,MAAM,UACJ,gBAAA,IAAoB,GAAA,IAAO,OAAO,GAAA,CAAI,mBAAmB,QAAA,GACrD,GAAA,CAAI,cAAA,GACJ,qBAAA,IAAyB,OAAO,iBAAA,CAAkB,GAAA,CAAI,mBAAmB,CAAA,GACvE,GAAA,CAAI,oBAAoB,EAAA,GACxB,MAAA;AAER,EAAA,MAAM,gBAAA,GACJ,YAAY,gBAAA,IAAoB,UAAA,CAAW,UAAU,GAAA,EAAK,2BAA2B,KAAK,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"options.js","sources":["../../src/options.ts"],"sourcesContent":["import { isObjectLike, envToBool } from '@sentry/core';\nimport type { CloudflareOptions } from './client';\n\n/**\n * Cloudflare's version metadata binding structure.\n * @see https://developers.cloudflare.com/workers/runtime-apis/bindings/version-metadata/\n */\ninterface CfVersionMetadata {\n id: string;\n tag?: string;\n timestamp?: string;\n}\n\n/**\n * Checks if the value is a valid CF_VERSION_METADATA binding.\n */\nfunction isVersionMetadata(value: unknown): value is CfVersionMetadata {\n return isObjectLike(value) && 'id' in value && typeof value.id === 'string';\n}\n\nfunction getEnvVar<T extends Record<string, unknown>>(env: unknown, varName: keyof T): string | undefined {\n return isObjectLike(env) && varName in env && typeof (env as T)[varName] === 'string'\n ? ((env as T)[varName] as string)\n : undefined;\n}\n\n/**\n * Merges the options passed in from the user with the options we read from\n * the Cloudflare `env` environment variable object.\n *\n * Release is determined with the following priority (highest to lowest):\n * 1. User-provided release option\n * 2. SENTRY_RELEASE environment variable\n * 3. CF_VERSION_METADATA.id binding (if configured in the wrangler config)\n *\n * @param userOptions - The options passed in from the user.\n * @param env - The environment variables.\n *\n * @returns The final options.\n */\nexport function getFinalOptions(userOptions: CloudflareOptions = {}, env: unknown): CloudflareOptions {\n if (typeof env !== 'object' || env === null) {\n return userOptions;\n }\n\n // Priority: userOptions.release > SENTRY_RELEASE > CF_VERSION_METADATA.id\n const release =\n 'SENTRY_RELEASE' in env && typeof env.SENTRY_RELEASE === 'string'\n ? env.SENTRY_RELEASE\n : 'CF_VERSION_METADATA' in env && isVersionMetadata(env.CF_VERSION_METADATA)\n ? env.CF_VERSION_METADATA.id\n : undefined;\n\n const tracesSampleRate =\n userOptions.tracesSampleRate ?? parseFloat(getEnvVar(env, 'SENTRY_TRACES_SAMPLE_RATE') ?? '');\n\n // Spotlight precedence (mirrors node-core's getSpotlightConfig):\n // - false or explicit string from options: use as-is\n // - true: enable, but prefer a custom URL from the env var if set\n // - undefined: defer entirely to the env var (bool or URL)\n const spotlight = getSpotlightFromEnv(userOptions.spotlight, getEnvVar(env, 'SENTRY_SPOTLIGHT'));\n\n return {\n release,\n ...userOptions,\n dsn: userOptions.dsn ?? getEnvVar(env, 'SENTRY_DSN'),\n environment: userOptions.environment ?? getEnvVar(env, 'SENTRY_ENVIRONMENT'),\n tracesSampleRate: isFinite(tracesSampleRate) ? tracesSampleRate : undefined,\n debug: userOptions.debug ?? envToBool(getEnvVar(env, 'SENTRY_DEBUG')),\n tunnel: userOptions.tunnel ?? getEnvVar(env, 'SENTRY_TUNNEL'),\n spotlight,\n };\n}\n\n/**\n * Resolve the spotlight option from a user-supplied value and an env binding string.\n * Mirrors node-core's `getSpotlightConfig` precedence:\n * - `false` or explicit string from options → use as-is\n * - `true` → enable, but prefer a custom URL from the env var if set\n * - `undefined` → defer entirely to the env var (bool or URL)\n */\nfunction getSpotlightFromEnv(\n optionsSpotlight: boolean | string | undefined,\n envVar: string | undefined,\n): boolean | string | undefined {\n if (optionsSpotlight === false) {\n return false;\n }\n if (typeof optionsSpotlight === 'string') {\n return optionsSpotlight;\n }\n\n // optionsSpotlight is true or undefined\n const envBool = envToBool(envVar, { strict: true });\n const envUrl = envBool === null && envVar ? envVar : undefined;\n\n return optionsSpotlight === true\n ? (envUrl ?? true) // true: use env URL if present, otherwise true\n : (envBool ?? envUrl); // undefined: use env var (bool or URL)\n}\n"],"names":[],"mappings":";;AAgBA,SAAS,kBAAkB,KAAA,EAA4C;AACrE,EAAA,OAAO,aAAa,KAAK,CAAA,IAAK,QAAQ,KAAA,IAAS,OAAO,MAAM,EAAA,KAAO,QAAA;AACrE;AAEA,SAAS,SAAA,CAA6C,KAAc,OAAA,EAAsC;AACxG,EAAA,OAAO,YAAA,CAAa,GAAG,CAAA,IAAK,OAAA,IAAW,GAAA,IAAO,OAAQ,GAAA,CAAU,OAAO,CAAA,KAAM,QAAA,GACvE,GAAA,CAAU,OAAO,CAAA,GACnB,MAAA;AACN;AAgBO,SAAS,eAAA,CAAgB,WAAA,GAAiC,EAAC,EAAG,GAAA,EAAiC;AACpG,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,KAAQ,IAAA,EAAM;AAC3C,IAAA,OAAO,WAAA;AAAA,EACT;AAGA,EAAA,MAAM,UACJ,gBAAA,IAAoB,GAAA,IAAO,OAAO,GAAA,CAAI,mBAAmB,QAAA,GACrD,GAAA,CAAI,cAAA,GACJ,qBAAA,IAAyB,OAAO,iBAAA,CAAkB,GAAA,CAAI,mBAAmB,CAAA,GACvE,GAAA,CAAI,oBAAoB,EAAA,GACxB,MAAA;AAER,EAAA,MAAM,gBAAA,GACJ,YAAY,gBAAA,IAAoB,UAAA,CAAW,UAAU,GAAA,EAAK,2BAA2B,KAAK,EAAE,CAAA;AAM9F,EAAA,MAAM,YAAY,mBAAA,CAAoB,WAAA,CAAY,WAAW,SAAA,CAAU,GAAA,EAAK,kBAAkB,CAAC,CAAA;AAE/F,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,GAAG,WAAA;AAAA,IACH,GAAA,EAAK,WAAA,CAAY,GAAA,IAAO,SAAA,CAAU,KAAK,YAAY,CAAA;AAAA,IACnD,WAAA,EAAa,WAAA,CAAY,WAAA,IAAe,SAAA,CAAU,KAAK,oBAAoB,CAAA;AAAA,IAC3E,gBAAA,EAAkB,QAAA,CAAS,gBAAgB,CAAA,GAAI,gBAAA,GAAmB,MAAA;AAAA,IAClE,OAAO,WAAA,CAAY,KAAA,IAAS,UAAU,SAAA,CAAU,GAAA,EAAK,cAAc,CAAC,CAAA;AAAA,IACpE,MAAA,EAAQ,WAAA,CAAY,MAAA,IAAU,SAAA,CAAU,KAAK,eAAe,CAAA;AAAA,IAC5D;AAAA,GACF;AACF;AASA,SAAS,mBAAA,CACP,kBACA,MAAA,EAC8B;AAC9B,EAAA,IAAI,qBAAqB,KAAA,EAAO;AAC9B,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,qBAAqB,QAAA,EAAU;AACxC,IAAA,OAAO,gBAAA;AAAA,EACT;AAGA,EAAA,MAAM,UAAU,SAAA,CAAU,MAAA,EAAQ,EAAE,MAAA,EAAQ,MAAM,CAAA;AAClD,EAAA,MAAM,MAAA,GAAS,OAAA,KAAY,IAAA,IAAQ,MAAA,GAAS,MAAA,GAAS,MAAA;AAErD,EAAA,OAAO,gBAAA,KAAqB,IAAA,GACvB,MAAA,IAAU,IAAA,GACV,OAAA,IAAW,MAAA;AAClB;;;;"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.69.0","sideEffects":false}
|
package/build/esm/sdk.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { dedupeIntegration, inboundFiltersIntegration, functionToStringIntegration, conversationIdIntegration, linkedErrorsIntegration, requestDataIntegration, consoleIntegration, getIntegrationsToSetup, stackParserFromStackParserOptions, initAndBind } from '@sentry/core';
|
|
1
|
+
import { dedupeIntegration, inboundFiltersIntegration, functionToStringIntegration, conversationIdIntegration, linkedErrorsIntegration, requestDataIntegration, consoleIntegration, GLOBAL_OBJ, getIntegrationsToSetup, stackParserFromStackParserOptions, initAndBind } from '@sentry/core';
|
|
2
2
|
import { CloudflareClient } from './client.js';
|
|
3
3
|
import { makeFlushLock } from './flush.js';
|
|
4
4
|
import { httpServerIntegration } from './integrations/httpServer.js';
|
|
5
5
|
import { fetchIntegration } from './integrations/fetch.js';
|
|
6
6
|
import { honoIntegration } from './integrations/hono.js';
|
|
7
|
+
import { INTEGRATION_NAME, spotlightIntegration } from './integrations/spotlight.js';
|
|
7
8
|
import { setupOpenTelemetryTracer } from './opentelemetry/tracer.js';
|
|
8
9
|
import { makeCloudflareTransport } from './transport.js';
|
|
9
10
|
import { defaultStackParser } from './vendor/stacktrace.js';
|
|
10
11
|
|
|
12
|
+
function getRegisteredChannelIntegrations() {
|
|
13
|
+
const registered = GLOBAL_OBJ.__SENTRY_ORCHESTRION__?.integrations;
|
|
14
|
+
return registered ? [...registered.values()].map((factory) => factory()) : [];
|
|
15
|
+
}
|
|
11
16
|
function getDefaultIntegrations(options) {
|
|
12
17
|
const cookiesEnabled = options.sendDefaultPii || options.dataCollection?.cookies != null;
|
|
13
18
|
return [
|
|
@@ -25,7 +30,14 @@ function getDefaultIntegrations(options) {
|
|
|
25
30
|
honoIntegration(),
|
|
26
31
|
httpServerIntegration(),
|
|
27
32
|
requestDataIntegration(cookiesEnabled ? void 0 : { include: { cookies: false } }),
|
|
28
|
-
consoleIntegration()
|
|
33
|
+
consoleIntegration(),
|
|
34
|
+
// The orchestrion diagnostics-channel subscribers (mysql, pg, …). The
|
|
35
|
+
// `@sentry/cloudflare/vite` plugin injects the channels at build time and,
|
|
36
|
+
// next to each, a snippet that registers the matching subscriber factory on
|
|
37
|
+
// the global marker. Read from there instead of importing them so bundles
|
|
38
|
+
// built without the plugin — where the channels would never fire — don't
|
|
39
|
+
// ship the code.
|
|
40
|
+
...getRegisteredChannelIntegrations()
|
|
29
41
|
];
|
|
30
42
|
}
|
|
31
43
|
function init(options) {
|
|
@@ -41,6 +53,13 @@ function init(options) {
|
|
|
41
53
|
transport: options.transport || makeCloudflareTransport,
|
|
42
54
|
flushLock
|
|
43
55
|
};
|
|
56
|
+
if (options.spotlight && !clientOptions.integrations.some(({ name }) => name === INTEGRATION_NAME)) {
|
|
57
|
+
clientOptions.integrations.push(
|
|
58
|
+
spotlightIntegration({
|
|
59
|
+
sidecarUrl: typeof options.spotlight === "string" ? options.spotlight : void 0
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
}
|
|
44
63
|
if (!options.skipOpenTelemetrySetup) {
|
|
45
64
|
setupOpenTelemetryTracer();
|
|
46
65
|
}
|
package/build/esm/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":[],"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 { INTEGRATION_NAME as SPOTLIGHT_INTEGRATION_NAME, spotlightIntegration } from './integrations/spotlight';\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 if (options.spotlight && !clientOptions.integrations.some(({ name }) => name === SPOTLIGHT_INTEGRATION_NAME)) {\n clientOptions.integrations.push(\n spotlightIntegration({\n sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,\n }),\n );\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":["SPOTLIGHT_INTEGRATION_NAME"],"mappings":";;;;;;;;;;;AAoCA,SAAS,gCAAA,GAAkD;AACzD,EAAA,MAAM,UAAA,GAAa,WAAW,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,CAAC,mBAAmB,CAAA;AAAA;AAAA;AAAA,IAG9D,yBAAA,EAA0B;AAAA,IAC1B,2BAAA,EAA4B;AAAA,IAC5B,yBAAA,EAA0B;AAAA,IAC1B,uBAAA,EAAwB;AAAA,IACxB,gBAAA,EAAiB;AAAA;AAAA,IAEjB,eAAA,EAAgB;AAAA,IAChB,qBAAA,EAAsB;AAAA,IACtB,sBAAA,CAAuB,iBAAiB,MAAA,GAAY,EAAE,SAAS,EAAE,OAAA,EAAS,KAAA,EAAM,EAAG,CAAA;AAAA,IACnF,kBAAA,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,GAAM,aAAA,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,EAAa,iCAAA,CAAkC,OAAA,CAAQ,WAAA,IAAe,kBAAkB,CAAA;AAAA,IACxF,YAAA,EAAc,uBAAuB,OAAO,CAAA;AAAA,IAC5C,SAAA,EAAW,QAAQ,SAAA,IAAa,uBAAA;AAAA,IAChC;AAAA,GACF;AAEA,EAAA,IAAI,OAAA,CAAQ,SAAA,IAAa,CAAC,aAAA,CAAc,YAAA,CAAa,IAAA,CAAK,CAAC,EAAE,IAAA,EAAK,KAAM,IAAA,KAASA,gBAA0B,CAAA,EAAG;AAC5G,IAAA,aAAA,CAAc,YAAA,CAAa,IAAA;AAAA,MACzB,oBAAA,CAAqB;AAAA,QACnB,YAAY,OAAO,OAAA,CAAQ,SAAA,KAAc,QAAA,GAAW,QAAQ,SAAA,GAAY;AAAA,OACzE;AAAA,KACH;AAAA,EACF;AASA,EAAA,IAAI,CAAC,QAAQ,sBAAA,EAAwB;AACnC,IAAA,wBAAA,EAAyB;AAAA,EAC3B;AAEA,EAAA,OAAO,WAAA,CAAY,kBAAkB,aAAa,CAAA;AACpD;;;;"}
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import { stringMatchesSomePattern } from '@sentry/core';
|
|
2
2
|
|
|
3
|
-
function targetsCloudflareInternalTable(querySummary, allowlist) {
|
|
3
|
+
function targetsCloudflareInternalTable(querySummary, allowlist, queryText) {
|
|
4
4
|
if (!querySummary) {
|
|
5
5
|
return false;
|
|
6
6
|
}
|
|
7
|
+
const indexedTable = queryText ? CREATE_INDEX_TABLE_RE.exec(queryText)?.groups?.["table"] : void 0;
|
|
8
|
+
if (indexedTable) {
|
|
9
|
+
return isCloudflareInternalTable(indexedTable, allowlist);
|
|
10
|
+
}
|
|
7
11
|
const [, ...tables] = querySummary.split(" ");
|
|
8
|
-
return tables.some((table) =>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
return tables.some((table) => isCloudflareInternalTable(table, allowlist));
|
|
13
|
+
}
|
|
14
|
+
const CREATE_INDEX_TABLE_RE = /^\s*CREATE\s+(?:UNIQUE\s+)?INDEX(?:\s+IF\s+(?:NOT\s+)?EXISTS)?\s+[^\s(,;)]+\s+ON\s+(?<table>[^\s(,;)]+)/i;
|
|
15
|
+
function isCloudflareInternalTable(table, allowlist) {
|
|
16
|
+
if (!table.toLowerCase().startsWith("cf_")) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return !allowlist?.length || !stringMatchesSomePattern(table, allowlist, true);
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
export { targetsCloudflareInternalTable };
|
|
@@ -1 +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
|
|
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. The one exception is `CREATE INDEX`: its summary carries the index name, not the indexed\n * table (upstream OTel convention), so the `cf_` target only appears in the ON clause of the full\n * statement, which `queryText` is needed for.\n */\nexport function targetsCloudflareInternalTable(\n querySummary: string | undefined,\n allowlist?: Array<string | RegExp>,\n queryText?: string,\n): boolean {\n if (!querySummary) {\n return false;\n }\n\n const indexedTable = queryText ? CREATE_INDEX_TABLE_RE.exec(queryText)?.groups?.['table'] : undefined;\n if (indexedTable) {\n return isCloudflareInternalTable(indexedTable, allowlist);\n }\n\n const [, ...tables] = querySummary.split(' ');\n\n return tables.some(table => isCloudflareInternalTable(table, allowlist));\n}\n\n// `CREATE [UNIQUE] INDEX [IF NOT EXISTS] <name> ON <table>` — the IF EXISTS shape mirrors DDL_RE\n// in @sentry/core.\nconst CREATE_INDEX_TABLE_RE =\n /^\\s*CREATE\\s+(?:UNIQUE\\s+)?INDEX(?:\\s+IF\\s+(?:NOT\\s+)?EXISTS)?\\s+[^\\s(,;)]+\\s+ON\\s+(?<table>[^\\s(,;)]+)/i;\n\nfunction isCloudflareInternalTable(table: string, allowlist?: Array<string | RegExp>): boolean {\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"],"names":[],"mappings":";;AAoBO,SAAS,8BAAA,CACd,YAAA,EACA,SAAA,EACA,SAAA,EACS;AACT,EAAA,IAAI,CAAC,YAAA,EAAc;AACjB,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,YAAY,qBAAA,CAAsB,IAAA,CAAK,SAAS,CAAA,EAAG,MAAA,GAAS,OAAO,CAAA,GAAI,MAAA;AAC5F,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,OAAO,yBAAA,CAA0B,cAAc,SAAS,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,GAAG,GAAG,MAAM,CAAA,GAAI,YAAA,CAAa,MAAM,GAAG,CAAA;AAE5C,EAAA,OAAO,OAAO,IAAA,CAAK,CAAA,KAAA,KAAS,yBAAA,CAA0B,KAAA,EAAO,SAAS,CAAC,CAAA;AACzE;AAIA,MAAM,qBAAA,GACJ,0GAAA;AAEF,SAAS,yBAAA,CAA0B,OAAe,SAAA,EAA6C;AAC7F,EAAA,IAAI,CAAC,KAAA,CAAM,WAAA,EAAY,CAAE,UAAA,CAAW,KAAK,CAAA,EAAG;AAC1C,IAAA,OAAO,KAAA;AAAA,EACT;AAIA,EAAA,OAAO,CAAC,SAAA,EAAW,MAAA,IAAU,CAAC,wBAAA,CAAyB,KAAA,EAAO,WAAW,IAAI,CAAA;AAC/E;;;;"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { stringMatchesSomePattern } from '@sentry/core';
|
|
2
|
+
|
|
3
|
+
function targetsCloudflareInternalKey(key, allowlist) {
|
|
4
|
+
if (!key) {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const isFrameworkKey = key.startsWith("cf_") || key.startsWith("cf:") || key.startsWith("__ps_") || key.startsWith("/");
|
|
8
|
+
if (!isFrameworkKey) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return !allowlist?.length || !stringMatchesSomePattern(key, allowlist, true);
|
|
12
|
+
}
|
|
13
|
+
function getStorageKeys(methodName, args) {
|
|
14
|
+
const [first] = args;
|
|
15
|
+
if (methodName === "get" || methodName === "delete") {
|
|
16
|
+
if (typeof first === "string") {
|
|
17
|
+
return [first];
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(first)) {
|
|
20
|
+
return first.filter((k) => typeof k === "string");
|
|
21
|
+
}
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
if (methodName === "put") {
|
|
25
|
+
if (typeof first === "string") {
|
|
26
|
+
return [first];
|
|
27
|
+
}
|
|
28
|
+
if (first && typeof first === "object" && !Array.isArray(first)) {
|
|
29
|
+
return Object.keys(first);
|
|
30
|
+
}
|
|
31
|
+
return void 0;
|
|
32
|
+
}
|
|
33
|
+
if (methodName === "list") {
|
|
34
|
+
const prefix = first && typeof first === "object" ? first.prefix : void 0;
|
|
35
|
+
return typeof prefix === "string" ? [prefix] : void 0;
|
|
36
|
+
}
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { getStorageKeys, targetsCloudflareInternalKey };
|
|
41
|
+
//# sourceMappingURL=internalStorageKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internalStorageKey.js","sources":["../../../src/utils/internalStorageKey.ts"],"sourcesContent":["import { stringMatchesSomePattern } from '@sentry/core';\n\n/**\n * Cloudflare frameworks that build on Durable Objects (`agents`, `partyserver`, ...) also manage\n * their own internal KV entries alongside their internal SQLite tables, namespaced with a reserved\n * prefix — e.g. `cf_agents_state`, `cf_agents_mcp_servers`, `__ps_name`. Reads/writes of these\n * (message persistence, MCP connection bookkeeping, name hydration) are framework implementation\n * details that otherwise flood traces with dozens of zero-signal `durable_object_storage_*` spans\n * per request, so we match the reserved prefixes rather than an enumerated list. This mirrors the\n * `cf_` convention used for internal SQL tables (see `targetsCloudflareInternalTable`).\n *\n * The prefixes are a reserved convention for framework-managed entries, so user keys should not use\n * them. In case a user key does collide, the `durableObjectStorageSpanAllowlist` option lets them\n * opt those keys back into instrumentation.\n */\nexport function targetsCloudflareInternalKey(key: string | undefined, allowlist?: Array<string | RegExp>): boolean {\n if (!key) {\n return false;\n }\n\n // Framework-managed KV namespaces:\n // - `cf_` — agents / ai-chat internal state (mirrors the internal SQL table convention)\n // - `cf:` — agents chat-recovery entries (`cf:chat-recovery:*`, `cf:chat:*`); the same reserved\n // `cf` namespace, but colon-separated instead of underscore-separated\n // - `__ps_` — partyserver internals (e.g. `__ps_name`)\n // - `/` — MCP OAuth client state (`/<clientName>/<serverId>/{token,client_info,state,...}`),\n // read on every MCP tool call. User keys on an Agent rarely use a leading slash; if one does,\n // the allowlist opts it back in.\n const isFrameworkKey =\n key.startsWith('cf_') || key.startsWith('cf:') || key.startsWith('__ps_') || key.startsWith('/');\n if (!isFrameworkKey) {\n return false;\n }\n\n // A key on the allowlist is treated as a user key and stays instrumented, even though it matches\n // a reserved prefix.\n return !allowlist?.length || !stringMatchesSomePattern(key, allowlist, true);\n}\n\n/**\n * Extracts the KV keys a Durable Object storage call targets, so the caller can decide whether the\n * operation only touches framework-internal entries. Returns `undefined` when the keys can't be\n * determined from the arguments (e.g. `list()` without a prefix), in which case the call is treated\n * as user work and stays instrumented.\n */\nexport function getStorageKeys(methodName: string, args: unknown[]): string[] | undefined {\n const [first] = args;\n\n if (methodName === 'get' || methodName === 'delete') {\n // get(key) / get(keys[]) / delete(key) / delete(keys[])\n if (typeof first === 'string') {\n return [first];\n }\n if (Array.isArray(first)) {\n return first.filter((k): k is string => typeof k === 'string');\n }\n return undefined;\n }\n\n if (methodName === 'put') {\n // put(key, value) or put({ key: value, ... })\n if (typeof first === 'string') {\n return [first];\n }\n if (first && typeof first === 'object' && !Array.isArray(first)) {\n return Object.keys(first);\n }\n return undefined;\n }\n\n if (methodName === 'list') {\n // list({ prefix })\n const prefix = first && typeof first === 'object' ? (first as { prefix?: unknown }).prefix : undefined;\n return typeof prefix === 'string' ? [prefix] : undefined;\n }\n\n return undefined;\n}\n"],"names":[],"mappings":";;AAeO,SAAS,4BAAA,CAA6B,KAAyB,SAAA,EAA6C;AACjH,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,OAAO,KAAA;AAAA,EACT;AAUA,EAAA,MAAM,cAAA,GACJ,GAAA,CAAI,UAAA,CAAW,KAAK,KAAK,GAAA,CAAI,UAAA,CAAW,KAAK,CAAA,IAAK,IAAI,UAAA,CAAW,OAAO,CAAA,IAAK,GAAA,CAAI,WAAW,GAAG,CAAA;AACjG,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,OAAO,KAAA;AAAA,EACT;AAIA,EAAA,OAAO,CAAC,SAAA,EAAW,MAAA,IAAU,CAAC,wBAAA,CAAyB,GAAA,EAAK,WAAW,IAAI,CAAA;AAC7E;AAQO,SAAS,cAAA,CAAe,YAAoB,IAAA,EAAuC;AACxF,EAAA,MAAM,CAAC,KAAK,CAAA,GAAI,IAAA;AAEhB,EAAA,IAAI,UAAA,KAAe,KAAA,IAAS,UAAA,KAAe,QAAA,EAAU;AAEnD,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,OAAO,CAAC,KAAK,CAAA;AAAA,IACf;AACA,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,MAAA,OAAO,MAAM,MAAA,CAAO,CAAC,CAAA,KAAmB,OAAO,MAAM,QAAQ,CAAA;AAAA,IAC/D;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,eAAe,KAAA,EAAO;AAExB,IAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,MAAA,OAAO,CAAC,KAAK,CAAA;AAAA,IACf;AACA,IAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAC/D,MAAA,OAAO,MAAA,CAAO,KAAK,KAAK,CAAA;AAAA,IAC1B;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,eAAe,MAAA,EAAQ;AAEzB,IAAA,MAAM,SAAS,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,GAAY,MAA+B,MAAA,GAAS,MAAA;AAC7F,IAAA,OAAO,OAAO,MAAA,KAAW,QAAA,GAAW,CAAC,MAAM,CAAA,GAAI,MAAA;AAAA,EACjD;AAEA,EAAA,OAAO,MAAA;AACT;;;;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { TraceFlags } from '@opentelemetry/api';
|
|
2
|
-
import {
|
|
2
|
+
import { getActiveSpan, spanIsSampled, debug, SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE } from '@sentry/core';
|
|
3
3
|
import { DEBUG_BUILD } from '../debug-build.js';
|
|
4
4
|
|
|
5
5
|
const SENTRY_TRACE_LINK_KEY_PREFIX = "__SENTRY_TRACE_LINK__";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { shapeFromAst, DEFAULT_EXPORT, shapeFromSource } from './moduleShape.js';
|
|
3
|
+
|
|
4
|
+
const AGENT_BASE_CLASSES = {
|
|
5
|
+
agents: /* @__PURE__ */ new Set(["Agent"]),
|
|
6
|
+
"agents/mcp": /* @__PURE__ */ new Set(["McpAgent"]),
|
|
7
|
+
"@cloudflare/ai-chat": /* @__PURE__ */ new Set(["AIChatAgent"]),
|
|
8
|
+
"@cloudflare/think": /* @__PURE__ */ new Set(["Think"])
|
|
9
|
+
};
|
|
10
|
+
const MAX_DEPTH = 8;
|
|
11
|
+
async function detectAgentClasses(ast, entryId, candidates, resolver) {
|
|
12
|
+
const ctx = { resolver, modules: /* @__PURE__ */ new Map([[entryId, shapeFromAst(ast)]]) };
|
|
13
|
+
const detected = /* @__PURE__ */ new Set();
|
|
14
|
+
for (const name of candidates) {
|
|
15
|
+
if (await isAgentBinding(ctx, entryId, name, 0, /* @__PURE__ */ new Set())) {
|
|
16
|
+
detected.add(name);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return detected;
|
|
20
|
+
}
|
|
21
|
+
function collectAgentCandidates(ast, configuredNames) {
|
|
22
|
+
const shape = shapeFromAst(ast);
|
|
23
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
24
|
+
for (const configured of configuredNames) {
|
|
25
|
+
if (shape.classes.has(configured)) {
|
|
26
|
+
candidates.add(configured);
|
|
27
|
+
}
|
|
28
|
+
const local = shape.localExports.get(configured);
|
|
29
|
+
if (local && shape.classes.has(local)) {
|
|
30
|
+
candidates.add(local);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return candidates;
|
|
34
|
+
}
|
|
35
|
+
async function isAgentBinding(ctx, moduleId, name, depth, visited) {
|
|
36
|
+
if (depth > MAX_DEPTH) return false;
|
|
37
|
+
const key = `${moduleId} ${name}`;
|
|
38
|
+
if (visited.has(key)) return false;
|
|
39
|
+
visited.add(key);
|
|
40
|
+
const shape = await getModuleShape(ctx, moduleId);
|
|
41
|
+
if (!shape) return false;
|
|
42
|
+
if (shape.classes.has(name)) {
|
|
43
|
+
return extendsAgent(ctx, shape, moduleId, shape.classes.get(name), depth, visited);
|
|
44
|
+
}
|
|
45
|
+
const imported = shape.imports.get(name);
|
|
46
|
+
if (imported) {
|
|
47
|
+
return followImport(ctx, moduleId, imported.source, imported.imported, depth, visited);
|
|
48
|
+
}
|
|
49
|
+
if (name === DEFAULT_EXPORT) {
|
|
50
|
+
if (shape.defaultExportIsClass) {
|
|
51
|
+
return extendsAgent(ctx, shape, moduleId, shape.defaultExportSuper, depth, visited);
|
|
52
|
+
}
|
|
53
|
+
if (shape.defaultExportName) {
|
|
54
|
+
return isAgentBinding(ctx, moduleId, shape.defaultExportName, depth + 1, visited);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const localName = shape.localExports.get(name);
|
|
58
|
+
if (localName) {
|
|
59
|
+
return isAgentBinding(ctx, moduleId, localName, depth + 1, visited);
|
|
60
|
+
}
|
|
61
|
+
const reexport = shape.reexports.get(name);
|
|
62
|
+
if (reexport) {
|
|
63
|
+
return followImport(ctx, moduleId, reexport.source, reexport.imported, depth, visited);
|
|
64
|
+
}
|
|
65
|
+
for (const source of shape.starExports) {
|
|
66
|
+
if (await followImport(ctx, moduleId, source, name, depth, visited)) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
async function extendsAgent(ctx, shape, moduleId, superClass, depth, visited) {
|
|
73
|
+
if (!superClass) return false;
|
|
74
|
+
if (superClass.kind === "identifier") {
|
|
75
|
+
return isAgentBinding(ctx, moduleId, superClass.name, depth + 1, visited);
|
|
76
|
+
}
|
|
77
|
+
const source = shape.namespaces.get(superClass.object);
|
|
78
|
+
if (source) {
|
|
79
|
+
return followImport(ctx, moduleId, source, superClass.property, depth, visited);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
async function followImport(ctx, importerId, source, importedName, depth, visited) {
|
|
84
|
+
if (AGENT_BASE_CLASSES[source]?.has(importedName)) return true;
|
|
85
|
+
if (!ctx.resolver.resolve) return false;
|
|
86
|
+
let resolved;
|
|
87
|
+
try {
|
|
88
|
+
resolved = await ctx.resolver.resolve(source, importerId);
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (!resolved?.id) return false;
|
|
93
|
+
if (resolved.id.includes("/node_modules/") || resolved.id.includes("\\node_modules\\")) return false;
|
|
94
|
+
return isAgentBinding(ctx, resolved.id, importedName, depth + 1, visited);
|
|
95
|
+
}
|
|
96
|
+
async function getModuleShape(ctx, moduleId) {
|
|
97
|
+
if (ctx.modules.has(moduleId)) return ctx.modules.get(moduleId);
|
|
98
|
+
let shape;
|
|
99
|
+
try {
|
|
100
|
+
const code = ctx.resolver.readFile ? ctx.resolver.readFile(moduleId) : readFileSync(moduleId.replace(/[?#].*$/, ""), "utf8");
|
|
101
|
+
if (typeof code === "string") {
|
|
102
|
+
shape = shapeFromSource(code);
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
ctx.modules.set(moduleId, shape);
|
|
107
|
+
return shape;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { collectAgentCandidates, detectAgentClasses };
|
|
111
|
+
//# sourceMappingURL=agentClass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentClass.js","sources":["../../../src/vite/agentClass.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { DEFAULT_EXPORT, type ModuleShape, shapeFromAst, shapeFromSource, type SuperRef } from './moduleShape';\nimport type { ProgramBody } from './transform';\n\n/**\n * Agent base classes, keyed by the module specifier they are imported from. A class extending any\n * of these — directly or through a chain of local/imported subclasses — is an `agents` Agent rather\n * than a plain Durable Object.\n *\n * `McpAgent`, `AIChatAgent` and `Think` all extend `Agent` themselves, but they live in packages\n * whose sources we never walk into (see {@link followImport}), so each needs its own entry.\n */\nconst AGENT_BASE_CLASSES: Record<string, ReadonlySet<string>> = {\n agents: new Set(['Agent']),\n 'agents/mcp': new Set(['McpAgent']),\n '@cloudflare/ai-chat': new Set(['AIChatAgent']),\n '@cloudflare/think': new Set(['Think']),\n};\n\n/**\n * How many modules deep the base-class chain is followed. Guards against pathological module graphs;\n * real Agent hierarchies are only a few levels deep.\n */\nconst MAX_DEPTH = 8;\n\n/**\n * The subset of the Vite/Rollup plugin context needed to walk the module graph.\n *\n * `resolve` is optional: without it detection still works, but only for base-class chains declared\n * inside the entry module itself. `readFile` is injectable for tests and defaults to reading disk.\n *\n * Deliberately **no `load`**: awaiting the plugin context's `load()` from inside a `transform` hook\n * deadlocks the build — the module cannot finish loading while its own transform is still pending\n * (Rollup documents this hazard, and Vite's Rolldown pipeline is stricter still). Sibling modules\n * are therefore read straight off disk; see {@link getModuleShape}.\n */\nexport interface ModuleResolver {\n parse(code: string): ProgramBody;\n resolve?(source: string, importer: string): Promise<{ id: string } | null | undefined>;\n readFile?(id: string): string | undefined;\n}\n\ninterface DetectContext {\n resolver: ModuleResolver;\n modules: Map<string, ModuleShape | undefined>;\n}\n\n/**\n * Find which of `candidates` (top-level class names in the entry module) are Cloudflare\n * [`agents`](https://www.npmjs.com/package/agents) Agents.\n *\n * An Agent is a Durable Object under the hood, so wrangler configures it as one and the transform\n * would otherwise reach for `instrumentDurableObjectWithSentry`. Detecting the Agent base chain lets\n * it pick `instrumentAgentWithSentry` instead, which adds the Agent-specific telemetry on top.\n *\n * Unlike `WorkerEntrypoint` detection, the chain is followed *across* modules: base classes commonly\n * live in their own file (`import { MyBase } from './base'`), and there is no runtime fallback that\n * would catch a missed one. Resolution stops at package boundaries — a base class imported from\n * `node_modules` is only recognized when it is one of {@link AGENT_BASE_CLASSES}.\n */\nexport async function detectAgentClasses(\n ast: ProgramBody,\n entryId: string,\n candidates: Iterable<string>,\n resolver: ModuleResolver,\n): Promise<Set<string>> {\n // The entry's shape comes from the AST Vite already handed us (TypeScript stripped, full\n // fidelity); only sibling modules fall back to source scanning.\n const ctx: DetectContext = { resolver, modules: new Map([[entryId, shapeFromAst(ast)]]) };\n\n const detected = new Set<string>();\n for (const name of candidates) {\n // A fresh cycle guard per candidate: a shared one would record \"not an Agent\" for bindings\n // visited while resolving an earlier candidate that turned out to be unrelated.\n if (await isAgentBinding(ctx, entryId, name, 0, new Set())) {\n detected.add(name);\n }\n }\n return detected;\n}\n\n/**\n * The local class names in the entry that a configured class name could refer to — either declared\n * under that name directly, or aliased to it by an `export { Local as Configured }` specifier.\n *\n * Keeps detection (which reads and scans other modules) off classes that no binding points at.\n */\nexport function collectAgentCandidates(ast: ProgramBody, configuredNames: Iterable<string>): Set<string> {\n const shape = shapeFromAst(ast);\n const candidates = new Set<string>();\n\n for (const configured of configuredNames) {\n if (shape.classes.has(configured)) {\n candidates.add(configured);\n }\n const local = shape.localExports.get(configured);\n if (local && shape.classes.has(local)) {\n candidates.add(local);\n }\n }\n\n return candidates;\n}\n\nasync function isAgentBinding(\n ctx: DetectContext,\n moduleId: string,\n name: string,\n depth: number,\n visited: Set<string>,\n): Promise<boolean> {\n if (depth > MAX_DEPTH) return false;\n\n const key = `${moduleId} ${name}`;\n if (visited.has(key)) return false;\n visited.add(key);\n\n const shape = await getModuleShape(ctx, moduleId);\n if (!shape) return false;\n\n if (shape.classes.has(name)) {\n return extendsAgent(ctx, shape, moduleId, shape.classes.get(name), depth, visited);\n }\n\n const imported = shape.imports.get(name);\n if (imported) {\n return followImport(ctx, moduleId, imported.source, imported.imported, depth, visited);\n }\n\n if (name === DEFAULT_EXPORT) {\n if (shape.defaultExportIsClass) {\n return extendsAgent(ctx, shape, moduleId, shape.defaultExportSuper, depth, visited);\n }\n if (shape.defaultExportName) {\n return isAgentBinding(ctx, moduleId, shape.defaultExportName, depth + 1, visited);\n }\n }\n\n // `export { Local as Requested }` — the caller asked by exported name.\n const localName = shape.localExports.get(name);\n if (localName) {\n return isAgentBinding(ctx, moduleId, localName, depth + 1, visited);\n }\n\n const reexport = shape.reexports.get(name);\n if (reexport) {\n return followImport(ctx, moduleId, reexport.source, reexport.imported, depth, visited);\n }\n\n // Barrel modules (`export * from './base'`) don't name the binding, so every star source is a\n // candidate home for it.\n for (const source of shape.starExports) {\n if (await followImport(ctx, moduleId, source, name, depth, visited)) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Whether a superclass reference resolves to an Agent base — a bare identifier (imported, or a\n * subclass declared in the same module) or `ns.Agent` off a namespace import.\n */\nasync function extendsAgent(\n ctx: DetectContext,\n shape: ModuleShape,\n moduleId: string,\n superClass: SuperRef | undefined,\n depth: number,\n visited: Set<string>,\n): Promise<boolean> {\n if (!superClass) return false;\n\n if (superClass.kind === 'identifier') {\n return isAgentBinding(ctx, moduleId, superClass.name, depth + 1, visited);\n }\n\n const source = shape.namespaces.get(superClass.object);\n if (source) {\n return followImport(ctx, moduleId, source, superClass.property, depth, visited);\n }\n\n return false;\n}\n\n/** Resolve an import to its module and continue the search there, stopping at package boundaries. */\nasync function followImport(\n ctx: DetectContext,\n importerId: string,\n source: string,\n importedName: string,\n depth: number,\n visited: Set<string>,\n): Promise<boolean> {\n if (AGENT_BASE_CLASSES[source]?.has(importedName)) return true;\n\n if (!ctx.resolver.resolve) return false;\n\n let resolved: { id: string } | null | undefined;\n try {\n resolved = await ctx.resolver.resolve(source, importerId);\n } catch {\n return false;\n }\n if (!resolved?.id) return false;\n\n // Third-party sources are not walked: they are large, may not be plain JS by the time we see\n // them, and any Agent base worth knowing about is listed in AGENT_BASE_CLASSES.\n if (resolved.id.includes('/node_modules/') || resolved.id.includes('\\\\node_modules\\\\')) return false;\n\n return isAgentBinding(ctx, resolved.id, importedName, depth + 1, visited);\n}\n\nasync function getModuleShape(ctx: DetectContext, moduleId: string): Promise<ModuleShape | undefined> {\n if (ctx.modules.has(moduleId)) return ctx.modules.get(moduleId);\n\n let shape: ModuleShape | undefined;\n try {\n const code = ctx.resolver.readFile\n ? ctx.resolver.readFile(moduleId)\n : readFileSync(moduleId.replace(/[?#].*$/, ''), 'utf8');\n if (typeof code === 'string') {\n shape = shapeFromSource(code);\n }\n } catch {\n // Unreadable or not a source file — treat as \"not an Agent\" rather than failing the build.\n }\n\n ctx.modules.set(moduleId, shape);\n return shape;\n}\n"],"names":[],"mappings":"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"}
|