@sentry/cloudflare 10.71.0 → 10.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/client.js.map +1 -1
- package/build/cjs/durableobject.js.map +1 -1
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js +4 -4
- package/build/cjs/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/cjs/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/cjs/instrumentations/worker/instrumentEnv.js +5 -7
- package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/cjs/utils/rpcPropagation.js +20 -0
- package/build/cjs/utils/rpcPropagation.js.map +1 -0
- package/build/cjs/vite/autoInstrument.js +2 -1
- package/build/cjs/vite/autoInstrument.js.map +1 -1
- package/build/cjs/vite/bindings.js +6 -0
- package/build/cjs/vite/bindings.js.map +1 -0
- package/build/cjs/vite/index.js.map +1 -1
- package/build/cjs/vite/transform.js +30 -5
- package/build/cjs/vite/transform.js.map +1 -1
- package/build/cjs/vite/wranglerConfig.js +21 -1
- package/build/cjs/vite/wranglerConfig.js.map +1 -1
- package/build/esm/client.js.map +1 -1
- package/build/esm/durableobject.js.map +1 -1
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js +4 -4
- package/build/esm/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/esm/instrumentations/instrumentWorkerEntrypoint.js.map +1 -1
- package/build/esm/instrumentations/worker/instrumentEnv.js +5 -7
- package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/utils/rpcPropagation.js +18 -0
- package/build/esm/utils/rpcPropagation.js.map +1 -0
- package/build/esm/vite/autoInstrument.js +2 -1
- package/build/esm/vite/autoInstrument.js.map +1 -1
- package/build/esm/vite/bindings.js +4 -0
- package/build/esm/vite/bindings.js.map +1 -0
- package/build/esm/vite/index.js.map +1 -1
- package/build/esm/vite/transform.js +30 -5
- package/build/esm/vite/transform.js.map +1 -1
- package/build/esm/vite/wranglerConfig.js +21 -2
- package/build/esm/vite/wranglerConfig.js.map +1 -1
- package/build/types/client.d.ts +39 -29
- package/build/types/client.d.ts.map +1 -1
- package/build/types/durableobject.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentDurableObjectNamespace.d.ts +2 -1
- package/build/types/instrumentations/instrumentDurableObjectNamespace.d.ts.map +1 -1
- package/build/types/instrumentations/instrumentWorkerEntrypoint.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEnv.d.ts.map +1 -1
- package/build/types/utils/rpcPropagation.d.ts +15 -0
- package/build/types/utils/rpcPropagation.d.ts.map +1 -0
- package/build/types/vite/autoInstrument.d.ts.map +1 -1
- package/build/types/vite/bindings.d.ts +15 -0
- package/build/types/vite/bindings.d.ts.map +1 -0
- package/build/types/vite/index.d.ts +4 -0
- package/build/types/vite/index.d.ts.map +1 -1
- package/build/types/vite/transform.d.ts +3 -0
- package/build/types/vite/transform.d.ts.map +1 -1
- package/build/types/vite/wranglerConfig.d.ts +7 -0
- package/build/types/vite/wranglerConfig.d.ts.map +1 -1
- package/build/types-ts3.8/client.d.ts +39 -29
- package/build/types-ts3.8/instrumentations/instrumentDurableObjectNamespace.d.ts +2 -1
- package/build/types-ts3.8/utils/rpcPropagation.d.ts +15 -0
- package/build/types-ts3.8/vite/bindings.d.ts +15 -0
- package/build/types-ts3.8/vite/index.d.ts +4 -0
- package/build/types-ts3.8/vite/transform.d.ts +3 -0
- package/build/types-ts3.8/vite/wranglerConfig.d.ts +7 -0
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentWorkerEntrypoint.js","sources":["../../../src/instrumentations/instrumentWorkerEntrypoint.ts"],"sourcesContent":["import type { RpcStub, WorkerEntrypoint } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '../async';\nimport type { CloudflareOptions } from '../client';\nimport { getFinalOptions } from '../options';\nimport { instrumentContext } from '../utils/instrumentContext';\nimport { extractRpcMeta } from '../utils/rpcMeta';\nimport { type UncheckedMethod, wrapMethodWithSentry } from '../wrapMethodWithSentry';\nimport { instrumentEnv } from './worker/instrumentEnv';\nimport { instrumentWorkerEntrypointFetch } from './worker/instrumentFetch';\nimport { instrumentWorkerEntrypointQueue } from './worker/instrumentQueue';\nimport { instrumentWorkerEntrypointScheduled } from './worker/instrumentScheduled';\nimport { instrumentWorkerEntrypointTail } from './worker/instrumentTail';\n\nconst WORKER_ENTRYPOINT_ORIGIN = 'auto.faas.cloudflare.worker_entrypoint';\n\ntype ReservedMethod =\n | Exclude<Extract<keyof WorkerEntrypoint, string>, '__WORKER_ENTRYPOINT_BRAND'>\n | Extract<keyof ExportedHandler, string>\n | Exclude<Extract<keyof RpcStub<(...args: unknown[]) => unknown>, string>, '__RPC_STUB_BRAND'>\n | 'constructor';\n\nconst RESERVED_METHODS = new Set<string>([\n 'connect',\n 'constructor',\n 'dup',\n 'email',\n 'fetch',\n 'queue',\n 'scheduled',\n 'tail',\n 'tailStream',\n 'test',\n 'trace',\n] satisfies ReservedMethod[]);\n\ninterface CachedMethod {\n source: UncheckedMethod;\n wrapped: UncheckedMethod;\n}\n\nexport type WorkerEntrypointConstructor<Env = unknown, Props = {}> = new (\n ctx: ExecutionContext,\n // WorkerEntrypoint subclasses can define different `env` shapes, so this constructor must accept all of them.\n // oxlint-disable-next-line typescript/no-explicit-any\n env: any,\n) => InstanceType<typeof WorkerEntrypoint<Env, Props>>;\n\nfunction isPrototypeMethod(instance: object, prop: string, method: UncheckedMethod): boolean {\n let prototype = Object.getPrototypeOf(instance);\n\n while (prototype && prototype !== Object.prototype) {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, prop);\n if (descriptor) {\n return descriptor.value === method;\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n\n return false;\n}\n\nfunction bindToInstance(instance: object, proxy: object, method: UncheckedMethod): UncheckedMethod {\n return new Proxy(method, {\n apply(target, thisArg, args) {\n return Reflect.apply(target, thisArg === proxy ? instance : thisArg, args);\n },\n });\n}\n\nfunction instrumentMethod(\n instance: object,\n proxy: object,\n prop: PropertyKey,\n method: UncheckedMethod,\n options: CloudflareOptions,\n context: ExecutionContext,\n): UncheckedMethod {\n const ownDescriptor = Object.getOwnPropertyDescriptor(instance, prop);\n if (ownDescriptor && 'value' in ownDescriptor && !ownDescriptor.configurable && !ownDescriptor.writable) {\n return method;\n }\n\n const boundMethod = bindToInstance(instance, proxy, method);\n\n if (typeof prop !== 'string' || RESERVED_METHODS.has(prop) || !isPrototypeMethod(instance, prop, method)) {\n return boundMethod;\n }\n\n const captureMethod = wrapMethodWithSentry(\n { options, context, spanOp: 'rpc', origin: WORKER_ENTRYPOINT_ORIGIN },\n boundMethod,\n undefined,\n true,\n );\n\n if (!options.enableRpcTracePropagation) {\n return captureMethod;\n }\n\n const tracedMethod = wrapMethodWithSentry(\n { options, context, spanName: prop, spanOp: 'rpc', origin: WORKER_ENTRYPOINT_ORIGIN },\n boundMethod,\n undefined,\n true,\n );\n\n return (...args: unknown[]) => {\n const { rpcMeta } = extractRpcMeta(args);\n return rpcMeta ? tracedMethod.call(proxy, ...args) : captureMethod.call(proxy, ...args);\n };\n}\n\n/**\n * Instruments a WorkerEntrypoint class to capture errors and performance data.\n *\n * Instruments the following methods (same as `withSentry` for ExportedHandler):\n * - fetch (HTTP requests)\n * - scheduled (cron triggers)\n * - queue (queue consumers)\n * - email (email handlers)\n * - tail (tail workers)\n *\n * as well as any other public RPC methods on the WorkerEntrypoint instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param WorkerEntrypointClass The WorkerEntrypoint class to instrument.\n * @returns The instrumented WorkerEntrypoint class.\n *\n * @example\n * ```ts\n * class MyWorkerBase extends WorkerEntrypoint<Env> {\n * async fetch(request: Request): Promise<Response> {\n * return new Response('Hello World!');\n * }\n *\n * async myRpcMethod(arg: string): Promise<string> {\n * return `Hello ${arg}!`;\n * }\n * }\n *\n * export default instrumentWorkerEntrypoint(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyWorkerBase,\n * );\n * ```\n */\nexport function instrumentWorkerEntrypoint<\n Env,\n Props,\n T extends InstanceType<typeof WorkerEntrypoint<Env, Props>>,\n C extends new (ctx: ExecutionContext, env: Env) => T,\n>(optionsCallback: (env: Env) => CloudflareOptions | undefined, WorkerEntrypointClass: C): C {\n // Set up AsyncLocalStorage strategy ONCE at instrumentation time, not per-request\n // This is critical - calling this per-request would create a new AsyncLocalStorage\n // each time, breaking scope isolation for concurrent requests\n setAsyncLocalStorageAsyncContextStrategy();\n\n return new Proxy(WorkerEntrypointClass, {\n construct(target, [ctx, env]) {\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n const obj = new target(context, instrumentedEnv);\n\n // Override this.ctx to ensure the instrumented context is used\n // This is necessary because the base WorkerEntrypoint class sets this.ctx\n // from the constructor parameter, but we want users accessing this.ctx\n // to get the instrumented version\n if ('ctx' in obj) {\n Object.defineProperty(obj, 'ctx', {\n value: context,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n if ('env' in obj) {\n Object.defineProperty(obj, 'env', {\n value: instrumentedEnv,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n const entrypoint = obj as WorkerEntrypoint;\n instrumentWorkerEntrypointFetch(entrypoint, options, context);\n instrumentWorkerEntrypointScheduled(entrypoint, options, context);\n instrumentWorkerEntrypointQueue(entrypoint, options, context);\n instrumentWorkerEntrypointTail(entrypoint, options, context);\n\n // workerd resolves RPC methods through property access.\n const methodCache = new Map<PropertyKey, CachedMethod>();\n\n const proxy: typeof obj = new Proxy(obj, {\n get(instance, prop) {\n const value = Reflect.get(instance, prop, instance);\n\n if (typeof value !== 'function') {\n return value;\n }\n\n const method = value as UncheckedMethod;\n\n const cached = methodCache.get(prop);\n if (cached?.source === method) {\n return cached.wrapped;\n }\n\n const wrapped = instrumentMethod(instance, proxy, prop, method, options, context);\n methodCache.set(prop, { source: method, wrapped });\n return wrapped;\n },\n });\n\n return proxy;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"instrumentWorkerEntrypoint.js","sources":["../../../src/instrumentations/instrumentWorkerEntrypoint.ts"],"sourcesContent":["import type { RpcStub, WorkerEntrypoint } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '../async';\nimport type { CloudflareOptions } from '../client';\nimport { getFinalOptions } from '../options';\nimport { instrumentContext } from '../utils/instrumentContext';\nimport { extractRpcMeta } from '../utils/rpcMeta';\nimport { type UncheckedMethod, wrapMethodWithSentry } from '../wrapMethodWithSentry';\nimport { instrumentEnv } from './worker/instrumentEnv';\nimport { instrumentWorkerEntrypointFetch } from './worker/instrumentFetch';\nimport { instrumentWorkerEntrypointQueue } from './worker/instrumentQueue';\nimport { instrumentWorkerEntrypointScheduled } from './worker/instrumentScheduled';\nimport { instrumentWorkerEntrypointTail } from './worker/instrumentTail';\n\nconst WORKER_ENTRYPOINT_ORIGIN = 'auto.faas.cloudflare.worker_entrypoint';\n\ntype ReservedMethod =\n | Exclude<Extract<keyof WorkerEntrypoint, string>, '__WORKER_ENTRYPOINT_BRAND'>\n | Extract<keyof ExportedHandler, string>\n | Exclude<Extract<keyof RpcStub<(...args: unknown[]) => unknown>, string>, '__RPC_STUB_BRAND'>\n | 'constructor';\n\nconst RESERVED_METHODS = new Set<string>([\n 'connect',\n 'constructor',\n 'dup',\n 'email',\n 'fetch',\n 'queue',\n 'scheduled',\n 'tail',\n 'tailStream',\n 'test',\n 'trace',\n] satisfies ReservedMethod[]);\n\ninterface CachedMethod {\n source: UncheckedMethod;\n wrapped: UncheckedMethod;\n}\n\nexport type WorkerEntrypointConstructor<Env = unknown, Props = {}> = new (\n ctx: ExecutionContext,\n // WorkerEntrypoint subclasses can define different `env` shapes, so this constructor must accept all of them.\n // oxlint-disable-next-line typescript/no-explicit-any\n env: any,\n) => InstanceType<typeof WorkerEntrypoint<Env, Props>>;\n\nfunction isPrototypeMethod(instance: object, prop: string, method: UncheckedMethod): boolean {\n let prototype = Object.getPrototypeOf(instance);\n\n while (prototype && prototype !== Object.prototype) {\n const descriptor = Object.getOwnPropertyDescriptor(prototype, prop);\n if (descriptor) {\n return descriptor.value === method;\n }\n prototype = Object.getPrototypeOf(prototype);\n }\n\n return false;\n}\n\nfunction bindToInstance(instance: object, proxy: object, method: UncheckedMethod): UncheckedMethod {\n return new Proxy(method, {\n apply(target, thisArg, args) {\n return Reflect.apply(target, thisArg === proxy ? instance : thisArg, args);\n },\n });\n}\n\nfunction instrumentMethod(\n instance: object,\n proxy: object,\n prop: PropertyKey,\n method: UncheckedMethod,\n options: CloudflareOptions,\n context: ExecutionContext,\n): UncheckedMethod {\n const ownDescriptor = Object.getOwnPropertyDescriptor(instance, prop);\n if (ownDescriptor && 'value' in ownDescriptor && !ownDescriptor.configurable && !ownDescriptor.writable) {\n return method;\n }\n\n const boundMethod = bindToInstance(instance, proxy, method);\n\n if (typeof prop !== 'string' || RESERVED_METHODS.has(prop) || !isPrototypeMethod(instance, prop, method)) {\n return boundMethod;\n }\n\n const captureMethod = wrapMethodWithSentry(\n { options, context, spanOp: 'rpc', origin: WORKER_ENTRYPOINT_ORIGIN },\n boundMethod,\n undefined,\n true,\n );\n\n // eslint-disable-next-line typescript/no-deprecated\n if (!options.enableRpcTracePropagation) {\n return captureMethod;\n }\n\n const tracedMethod = wrapMethodWithSentry(\n { options, context, spanName: prop, spanOp: 'rpc', origin: WORKER_ENTRYPOINT_ORIGIN },\n boundMethod,\n undefined,\n true,\n );\n\n return (...args: unknown[]) => {\n const { rpcMeta } = extractRpcMeta(args);\n return rpcMeta ? tracedMethod.call(proxy, ...args) : captureMethod.call(proxy, ...args);\n };\n}\n\n/**\n * Instruments a WorkerEntrypoint class to capture errors and performance data.\n *\n * Instruments the following methods (same as `withSentry` for ExportedHandler):\n * - fetch (HTTP requests)\n * - scheduled (cron triggers)\n * - queue (queue consumers)\n * - email (email handlers)\n * - tail (tail workers)\n *\n * as well as any other public RPC methods on the WorkerEntrypoint instance.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param WorkerEntrypointClass The WorkerEntrypoint class to instrument.\n * @returns The instrumented WorkerEntrypoint class.\n *\n * @example\n * ```ts\n * class MyWorkerBase extends WorkerEntrypoint<Env> {\n * async fetch(request: Request): Promise<Response> {\n * return new Response('Hello World!');\n * }\n *\n * async myRpcMethod(arg: string): Promise<string> {\n * return `Hello ${arg}!`;\n * }\n * }\n *\n * export default instrumentWorkerEntrypoint(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyWorkerBase,\n * );\n * ```\n */\nexport function instrumentWorkerEntrypoint<\n Env,\n Props,\n T extends InstanceType<typeof WorkerEntrypoint<Env, Props>>,\n C extends new (ctx: ExecutionContext, env: Env) => T,\n>(optionsCallback: (env: Env) => CloudflareOptions | undefined, WorkerEntrypointClass: C): C {\n // Set up AsyncLocalStorage strategy ONCE at instrumentation time, not per-request\n // This is critical - calling this per-request would create a new AsyncLocalStorage\n // each time, breaking scope isolation for concurrent requests\n setAsyncLocalStorageAsyncContextStrategy();\n\n return new Proxy(WorkerEntrypointClass, {\n construct(target, [ctx, env]) {\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n const obj = new target(context, instrumentedEnv);\n\n // Override this.ctx to ensure the instrumented context is used\n // This is necessary because the base WorkerEntrypoint class sets this.ctx\n // from the constructor parameter, but we want users accessing this.ctx\n // to get the instrumented version\n if ('ctx' in obj) {\n Object.defineProperty(obj, 'ctx', {\n value: context,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n if ('env' in obj) {\n Object.defineProperty(obj, 'env', {\n value: instrumentedEnv,\n writable: true,\n enumerable: true,\n configurable: true,\n });\n }\n\n Object.defineProperty(obj, '__SENTRY_CONTEXT__', {\n value: context,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n Object.defineProperty(obj, '__SENTRY_OPTIONS__', {\n value: options,\n enumerable: false,\n writable: false,\n configurable: false,\n });\n\n const entrypoint = obj as WorkerEntrypoint;\n instrumentWorkerEntrypointFetch(entrypoint, options, context);\n instrumentWorkerEntrypointScheduled(entrypoint, options, context);\n instrumentWorkerEntrypointQueue(entrypoint, options, context);\n instrumentWorkerEntrypointTail(entrypoint, options, context);\n\n // workerd resolves RPC methods through property access.\n const methodCache = new Map<PropertyKey, CachedMethod>();\n\n const proxy: typeof obj = new Proxy(obj, {\n get(instance, prop) {\n const value = Reflect.get(instance, prop, instance);\n\n if (typeof value !== 'function') {\n return value;\n }\n\n const method = value as UncheckedMethod;\n\n const cached = methodCache.get(prop);\n if (cached?.source === method) {\n return cached.wrapped;\n }\n\n const wrapped = instrumentMethod(instance, proxy, prop, method, options, context);\n methodCache.set(prop, { source: method, wrapped });\n return wrapped;\n },\n });\n\n return proxy;\n },\n });\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { instrumentWorkersAiClient, isObjectLike } from '@sentry/core';
|
|
|
2
2
|
import { isD1Database, isQueue, isR2Bucket, isRateLimit, isAiBinding, isDurableObjectNamespace, isJSRPC } from '../../utils/isBinding.js';
|
|
3
3
|
import { instrumentD1 } from './instrumentD1.js';
|
|
4
4
|
import { appendRpcMeta } from '../../utils/rpcMeta.js';
|
|
5
|
-
import {
|
|
5
|
+
import { createRpcPropagationResolver } from '../../utils/rpcPropagation.js';
|
|
6
6
|
import { instrumentDurableObjectNamespace, STUB_NON_RPC_METHODS } from '../instrumentDurableObjectNamespace.js';
|
|
7
7
|
import { instrumentFetcher } from './instrumentFetcher.js';
|
|
8
8
|
import { instrumentQueueProducer } from './instrumentQueueProducer.js';
|
|
@@ -17,7 +17,7 @@ function instrumentEnv(env, options) {
|
|
|
17
17
|
if (!env || typeof env !== "object") {
|
|
18
18
|
return env;
|
|
19
19
|
}
|
|
20
|
-
const
|
|
20
|
+
const shouldPropagateRpcTrace = createRpcPropagationResolver(options);
|
|
21
21
|
return new Proxy(env, {
|
|
22
22
|
get(target, prop, receiver) {
|
|
23
23
|
const item = Reflect.get(target, prop, receiver);
|
|
@@ -56,11 +56,9 @@ function instrumentEnv(env, options) {
|
|
|
56
56
|
instrumentedBindings.set(item, instrumented);
|
|
57
57
|
return instrumented;
|
|
58
58
|
}
|
|
59
|
-
|
|
60
|
-
return item;
|
|
61
|
-
}
|
|
59
|
+
const propagateRpcTrace = shouldPropagateRpcTrace(String(prop));
|
|
62
60
|
if (isDurableObjectNamespace(item)) {
|
|
63
|
-
const instrumented = instrumentDurableObjectNamespace(item);
|
|
61
|
+
const instrumented = instrumentDurableObjectNamespace(item, propagateRpcTrace);
|
|
64
62
|
instrumentedBindings.set(item, instrumented);
|
|
65
63
|
return instrumented;
|
|
66
64
|
}
|
|
@@ -71,7 +69,7 @@ function instrumentEnv(env, options) {
|
|
|
71
69
|
if (p === "fetch" && typeof value === "function") {
|
|
72
70
|
return instrumentFetcher((...args) => Reflect.apply(value, target2, args));
|
|
73
71
|
}
|
|
74
|
-
if (typeof value === "function" && typeof p === "string" && !STUB_NON_RPC_METHODS.has(p)) {
|
|
72
|
+
if (propagateRpcTrace && typeof value === "function" && typeof p === "string" && !STUB_NON_RPC_METHODS.has(p)) {
|
|
75
73
|
return (...args) => Reflect.apply(value, target2, appendRpcMeta(args));
|
|
76
74
|
}
|
|
77
75
|
return value;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentEnv.js","sources":["../../../../src/instrumentations/worker/instrumentEnv.ts"],"sourcesContent":["import { isObjectLike } from '@sentry/core';\nimport { instrumentWorkersAiClient } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport {\n isAiBinding,\n isD1Database,\n isDurableObjectNamespace,\n isJSRPC,\n isQueue,\n isR2Bucket,\n isRateLimit,\n} from '../../utils/isBinding';\nimport { instrumentD1 } from './instrumentD1';\nimport { appendRpcMeta } from '../../utils/rpcMeta';\nimport {
|
|
1
|
+
{"version":3,"file":"instrumentEnv.js","sources":["../../../../src/instrumentations/worker/instrumentEnv.ts"],"sourcesContent":["import { isObjectLike } from '@sentry/core';\nimport { instrumentWorkersAiClient } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport {\n isAiBinding,\n isD1Database,\n isDurableObjectNamespace,\n isJSRPC,\n isQueue,\n isR2Bucket,\n isRateLimit,\n} from '../../utils/isBinding';\nimport { instrumentD1 } from './instrumentD1';\nimport { appendRpcMeta } from '../../utils/rpcMeta';\nimport { createRpcPropagationResolver } from '../../utils/rpcPropagation';\nimport { instrumentDurableObjectNamespace, STUB_NON_RPC_METHODS } from '../instrumentDurableObjectNamespace';\nimport { instrumentFetcher } from './instrumentFetcher';\nimport { instrumentQueueProducer } from './instrumentQueueProducer';\nimport { instrumentR2Bucket } from './instrumentR2';\nimport { instrumentRateLimit } from './instrumentRateLimit';\n\nfunction isProxyable(item: unknown): item is object {\n return isObjectLike(item) || typeof item === 'function';\n}\n\nconst instrumentedBindings = new WeakMap<object, unknown>();\n\n/**\n * Wraps the Cloudflare `env` object in a Proxy that detects binding types\n * on property access and returns instrumented versions.\n *\n * Currently detects:\n * - DurableObjectNamespace (via `idFromName` duck-typing)\n * - Service bindings / JSRPC proxies\n * - Queue producers (via `send` + `sendBatch` duck-typing)\n * - R2 Buckets (via `head` + `put` + `createMultipartUpload` duck-typing)\n * - Rate limiters (via `limit` duck-typing)\n * - Workers AI (via `run` + `gateway` + `toMarkdown` duck-typing)\n *\n * @param env - The Cloudflare env object to instrument\n * @param options - Optional CloudflareOptions to control RPC trace propagation\n */\nexport function instrumentEnv<Env extends Record<string, unknown>>(env: Env, options?: CloudflareOptions): Env {\n if (!env || typeof env !== 'object') {\n return env;\n }\n\n const shouldPropagateRpcTrace = createRpcPropagationResolver(options);\n\n return new Proxy(env, {\n get(target, prop, receiver) {\n const item = Reflect.get(target, prop, receiver);\n\n if (!isProxyable(item)) {\n return item;\n }\n\n const cached = instrumentedBindings.get(item);\n\n if (cached) {\n return cached;\n }\n\n if (isD1Database(item)) {\n const instrumented = instrumentD1(item);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isQueue(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentQueueProducer(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isR2Bucket(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentR2Bucket(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isRateLimit(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentRateLimit(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isAiBinding(item)) {\n const instrumented = instrumentWorkersAiClient(item);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n const propagateRpcTrace = shouldPropagateRpcTrace(String(prop));\n\n if (isDurableObjectNamespace(item)) {\n const instrumented = instrumentDurableObjectNamespace(item, propagateRpcTrace);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isJSRPC(item)) {\n const instrumented = new Proxy(item, {\n get(target, p) {\n const value = Reflect.get(target, p);\n\n if (p === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((...args) => Reflect.apply(value, target, args));\n }\n\n if (\n propagateRpcTrace &&\n typeof value === 'function' &&\n typeof p === 'string' &&\n !STUB_NON_RPC_METHODS.has(p)\n ) {\n return (...args: unknown[]) => Reflect.apply(value, target, appendRpcMeta(args));\n }\n\n return value;\n },\n });\n\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n return item;\n },\n });\n}\n"],"names":["target"],"mappings":"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"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.72.0","sideEffects":false}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { stringMatchesSomePattern } from '@sentry/core';
|
|
2
|
+
import { getEffectiveRpcPropagation } from './rpcOptions.js';
|
|
3
|
+
|
|
4
|
+
const PROPAGATE_TO_NONE = () => false;
|
|
5
|
+
const PROPAGATE_TO_ALL = () => true;
|
|
6
|
+
function createRpcPropagationResolver(options) {
|
|
7
|
+
const bindings = options?.rpcTracePropagationBindings;
|
|
8
|
+
if (bindings === void 0) {
|
|
9
|
+
return options && getEffectiveRpcPropagation(options) ? PROPAGATE_TO_ALL : PROPAGATE_TO_NONE;
|
|
10
|
+
}
|
|
11
|
+
if (!bindings.length) {
|
|
12
|
+
return PROPAGATE_TO_NONE;
|
|
13
|
+
}
|
|
14
|
+
return (bindingName) => stringMatchesSomePattern(bindingName, bindings, true);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { createRpcPropagationResolver };
|
|
18
|
+
//# sourceMappingURL=rpcPropagation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpcPropagation.js","sources":["../../../src/utils/rpcPropagation.ts"],"sourcesContent":["import { stringMatchesSomePattern } from '@sentry/core';\nimport type { CloudflareOptions } from '../client';\nimport { getEffectiveRpcPropagation } from './rpcOptions';\n\nconst PROPAGATE_TO_NONE = (): boolean => false;\nconst PROPAGATE_TO_ALL = (): boolean => true;\n\n/**\n * Builds the per-binding predicate that decides whether a binding takes part in RPC trace\n * propagation.\n *\n * `rpcTracePropagationBindings` wins over `enableRpcTracePropagation` as soon as it is set, an\n * allow list is the more precise statement. An empty list therefore propagates to nothing, even\n * next to `enableRpcTracePropagation: true`, which is how a receiver opts out of being a caller.\n * Only leaving it unset falls back to the boolean.\n *\n * Callers only. Receivers continue an incoming trace whenever `enableRpcTracePropagation` is on,\n * so they have nothing to match against.\n */\nexport function createRpcPropagationResolver(options: CloudflareOptions | undefined): (bindingName: string) => boolean {\n const bindings = options?.rpcTracePropagationBindings;\n\n if (bindings === undefined) {\n return options && getEffectiveRpcPropagation(options) ? PROPAGATE_TO_ALL : PROPAGATE_TO_NONE;\n }\n\n if (!bindings.length) {\n return PROPAGATE_TO_NONE;\n }\n\n // Strings must match a binding name exactly, without this, an entry of `DB` would also enable\n // propagation for a binding named `MY_DB`. Regular expressions still give pattern matching.\n return (bindingName: string) => stringMatchesSomePattern(bindingName, bindings, true);\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,oBAAoB,MAAe,KAAA;AACzC,MAAM,mBAAmB,MAAe,IAAA;AAcjC,SAAS,6BAA6B,OAAA,EAA0E;AACrH,EAAA,MAAM,WAAW,OAAA,EAAS,2BAAA;AAE1B,EAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,IAAA,OAAO,OAAA,IAAW,0BAAA,CAA2B,OAAO,CAAA,GAAI,gBAAA,GAAmB,iBAAA;AAAA,EAC7E;AAEA,EAAA,IAAI,CAAC,SAAS,MAAA,EAAQ;AACpB,IAAA,OAAO,iBAAA;AAAA,EACT;AAIA,EAAA,OAAO,CAAC,WAAA,KAAwB,wBAAA,CAAyB,WAAA,EAAa,UAAU,IAAI,CAAA;AACtF;;;;"}
|
|
@@ -74,7 +74,8 @@ function sentryCloudflareAutoInstrumentPlugin(options = {}) {
|
|
|
74
74
|
classWrappers,
|
|
75
75
|
agentClasses,
|
|
76
76
|
optionsFn,
|
|
77
|
-
optionsImport
|
|
77
|
+
optionsImport,
|
|
78
|
+
sameWorkerBindings: wranglerConfig.sameWorkerBindings
|
|
78
79
|
});
|
|
79
80
|
const wrappedClasses = result?.wrappedClasses ?? /* @__PURE__ */ new Set();
|
|
80
81
|
const missing = [...classWrappers.keys()].filter((name) => !wrappedClasses.has(name));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoInstrument.js","sources":["../../../src/vite/autoInstrument.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { collectAgentCandidates, detectAgentClasses, type ModuleResolver } from './agentClass';\nimport { 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(options: { wranglerConfigPath?: string } = {}) {\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, options.wranglerConfigPath);\n if (!result) {\n // An explicit path that fails is a misconfiguration worth naming;\n // without one, hint at the option so custom-named configs (e.g. a\n // `configPath` handed to @cloudflare/vite-plugin) are discoverable.\n config.logger?.warn(\n options.wranglerConfigPath\n ? `[sentry] Could not find or parse the wrangler config \"${basename(options.wranglerConfigPath)}\" ` +\n '(resolved against the Vite root) — auto-instrumentation disabled.'\n : '[sentry] No parseable wrangler config found — auto-instrumentation disabled. ' +\n 'Set `wranglerConfigPath` if your config uses a custom name.',\n );\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 async transform(\n this: ModuleResolver & { warn?(msg: string): void; environment?: { name?: string } },\n code: string,\n id: string,\n ): Promise<{ 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 // An `agents` Agent is a Durable Object, so wrangler lists it among the DO bindings and only\n // its base-class chain tells the two apart. Detection walks the module graph (base classes\n // usually live in their own file), so it is limited to the configured DO classes.\n //\n // Only `resolve` is handed over — never `load`: awaiting `load()` from inside a transform\n // hook deadlocks the build, since the module can't finish loading while this transform is\n // still pending. `agentClass` reads sibling modules off disk instead.\n const agentCandidates = collectAgentCandidates(\n ast,\n [...classWrappers].filter(([, kind]) => kind === 'durableObject').map(([name]) => name),\n );\n const agentClasses =\n agentCandidates.size > 0\n ? await detectAgentClasses(ast, normalizedId, agentCandidates, {\n parse: code => this.parse(code),\n resolve: this.resolve ? (source, importer) => this.resolve!(source, importer) : undefined,\n })\n : undefined;\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 agentClasses,\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":["code"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"autoInstrument.js","sources":["../../../src/vite/autoInstrument.ts"],"sourcesContent":["import { basename } from 'node:path';\nimport { collectAgentCandidates, detectAgentClasses, type ModuleResolver } from './agentClass';\nimport { 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(options: { wranglerConfigPath?: string } = {}) {\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, options.wranglerConfigPath);\n if (!result) {\n // An explicit path that fails is a misconfiguration worth naming;\n // without one, hint at the option so custom-named configs (e.g. a\n // `configPath` handed to @cloudflare/vite-plugin) are discoverable.\n config.logger?.warn(\n options.wranglerConfigPath\n ? `[sentry] Could not find or parse the wrangler config \"${basename(options.wranglerConfigPath)}\" ` +\n '(resolved against the Vite root) — auto-instrumentation disabled.'\n : '[sentry] No parseable wrangler config found — auto-instrumentation disabled. ' +\n 'Set `wranglerConfigPath` if your config uses a custom name.',\n );\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 async transform(\n this: ModuleResolver & { warn?(msg: string): void; environment?: { name?: string } },\n code: string,\n id: string,\n ): Promise<{ 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 // An `agents` Agent is a Durable Object, so wrangler lists it among the DO bindings and only\n // its base-class chain tells the two apart. Detection walks the module graph (base classes\n // usually live in their own file), so it is limited to the configured DO classes.\n //\n // Only `resolve` is handed over — never `load`: awaiting `load()` from inside a transform\n // hook deadlocks the build, since the module can't finish loading while this transform is\n // still pending. `agentClass` reads sibling modules off disk instead.\n const agentCandidates = collectAgentCandidates(\n ast,\n [...classWrappers].filter(([, kind]) => kind === 'durableObject').map(([name]) => name),\n );\n const agentClasses =\n agentCandidates.size > 0\n ? await detectAgentClasses(ast, normalizedId, agentCandidates, {\n parse: code => this.parse(code),\n resolve: this.resolve ? (source, importer) => this.resolve!(source, importer) : undefined,\n })\n : undefined;\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 agentClasses,\n optionsFn,\n optionsImport,\n sameWorkerBindings: wranglerConfig.sameWorkerBindings,\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":["code"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bindings.js","sources":["../../../src/vite/bindings.ts"],"sourcesContent":["/**\n * Binding vocabulary shared by the wrangler config reader and the AST transform.\n *\n * It lives apart from `wranglerConfig.ts` so the transform never has to import that module, which\n * pulls in `wrangler` and with it a Node 20+ runtime.\n */\n\n/** Stands in for a class name where a binding targets the module's default export. */\nexport const DEFAULT_EXPORT = Symbol('defaultExport');\n\n/** The name a binding or an export is known by, either an exported class name or the default export. */\nexport type ExportName = string | typeof DEFAULT_EXPORT;\n\nexport interface SameWorkerBinding {\n bindingName: string;\n className: ExportName;\n}\n"],"names":[],"mappings":"AAQO,MAAM,cAAA,0BAAwB,eAAe;;;;"}
|
|
@@ -1 +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 * Path to the wrangler config, relative to the Vite root (or absolute).\n * Set this when your config doesn't use a default name — e.g. when you\n * pass `configPath: './wrangler.agent.jsonc'` to `@cloudflare/vite-plugin`,\n * which the Sentry plugin cannot see. When set, only this file is read\n * (no default-name probing), and a warning is emitted if it is missing or\n * unparseable.\n *\n * @default undefined (probes `wrangler.json`, `wrangler.jsonc`, `wrangler.toml` at the Vite root)\n */\n wranglerConfigPath?: string;\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\n ? [sentryCloudflareAutoInstrumentPlugin({ wranglerConfigPath: options.wranglerConfigPath })]\n : []),\n ];\n}\n"],"names":[],"mappings":";;;
|
|
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 * Path to the wrangler config, relative to the Vite root (or absolute).\n * Set this when your config doesn't use a default name — e.g. when you\n * pass `configPath: './wrangler.agent.jsonc'` to `@cloudflare/vite-plugin`,\n * which the Sentry plugin cannot see. When set, only this file is read\n * (no default-name probing), and a warning is emitted if it is missing or\n * unparseable.\n *\n * @default undefined (probes `wrangler.json`, `wrangler.jsonc`, `wrangler.toml` at the Vite root)\n */\n wranglerConfigPath?: string;\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 * The plugin also adds the bindings that resolve to the wrapped classes (this worker's own\n * Durable Objects and self service bindings) to `rpcTracePropagationBindings`. Bindings to\n * other workers stay opt-in, their receivers may not run Sentry.\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\n ? [sentryCloudflareAutoInstrumentPlugin({ wranglerConfigPath: options.wranglerConfigPath })]\n : []),\n ];\n}\n"],"names":[],"mappings":";;;AA4FO,SAAS,0BAAA,CAA2B,OAAA,GAA6C,EAAC,EAAG;AAC1F,EAAA,OAAO;AAAA,IACL,GAAI,OAAA,CAAQ,aAAA,EAAe,8BAAA,GACvB,CAAC,uBAAA,CAAwB,EAAE,wBAAA,EAA0B,IAAA,EAAM,CAAC,CAAA,GAC5D,EAAC;AAAA,IACL,GAAI,OAAA,CAAQ,aAAA,EAAe,mBAAA,GACvB,CAAC,oCAAA,CAAqC,EAAE,kBAAA,EAAoB,OAAA,CAAQ,kBAAA,EAAoB,CAAC,IACzF;AAAC,GACP;AACF;;;;"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import MagicString from 'magic-string';
|
|
2
|
+
import { DEFAULT_EXPORT } from './bindings.js';
|
|
2
3
|
import { detectWorkerEntrypointClasses } from './workerEntrypoint.js';
|
|
3
4
|
|
|
5
|
+
const MERGED_OPTIONS_IDENTIFIER = "__SENTRY_OPTIONS__";
|
|
4
6
|
function isCallToMethod(node, methodName) {
|
|
5
7
|
if (node.type !== "CallExpression") return false;
|
|
6
8
|
const callee = node.callee;
|
|
@@ -17,6 +19,7 @@ const WRAPPER_METHODS = {
|
|
|
17
19
|
function applyAutoInstrumentTransforms(code, ast, ctx) {
|
|
18
20
|
const ms = new MagicString(code);
|
|
19
21
|
const topLevelClasses = collectTopLevelClasses(ast);
|
|
22
|
+
const sameWorkerBindings = ctx.sameWorkerBindings ?? [];
|
|
20
23
|
const state = {
|
|
21
24
|
ms,
|
|
22
25
|
needsImport: false,
|
|
@@ -25,7 +28,10 @@ function applyAutoInstrumentTransforms(code, ast, ctx) {
|
|
|
25
28
|
renamedLocals: /* @__PURE__ */ new Set(),
|
|
26
29
|
classWrappers: ctx.classWrappers,
|
|
27
30
|
agentClasses: ctx.agentClasses ?? /* @__PURE__ */ new Set(),
|
|
28
|
-
workerEntrypointClasses: detectWorkerEntrypointClasses(ast)
|
|
31
|
+
workerEntrypointClasses: detectWorkerEntrypointClasses(ast),
|
|
32
|
+
// The identifier must be chosen before wrapping, which bindings survive is only known after.
|
|
33
|
+
optionsFn: sameWorkerBindings.length > 0 ? MERGED_OPTIONS_IDENTIFIER : ctx.optionsFn,
|
|
34
|
+
autoWrapped: /* @__PURE__ */ new Set()
|
|
29
35
|
};
|
|
30
36
|
const { wrappedClasses } = state;
|
|
31
37
|
for (const node of ast.body) {
|
|
@@ -42,6 +48,9 @@ function applyAutoInstrumentTransforms(code, ast, ctx) {
|
|
|
42
48
|
if (wrappedClasses.size === 0) return void 0;
|
|
43
49
|
return { code, map: ms.generateMap({ hires: true }), wrappedClasses };
|
|
44
50
|
}
|
|
51
|
+
if (sameWorkerBindings.length > 0) {
|
|
52
|
+
ms.prepend(buildMergedOptionsDeclaration(sameWorkerBindings, ctx.optionsFn, state));
|
|
53
|
+
}
|
|
45
54
|
if (ctx.optionsImport) ms.prepend(ctx.optionsImport);
|
|
46
55
|
ms.prepend("import * as __SENTRY__ from '@sentry/cloudflare';\n");
|
|
47
56
|
return {
|
|
@@ -50,6 +59,16 @@ function applyAutoInstrumentTransforms(code, ast, ctx) {
|
|
|
50
59
|
wrappedClasses
|
|
51
60
|
};
|
|
52
61
|
}
|
|
62
|
+
function buildMergedOptionsDeclaration(sameWorkerBindings, optionsFn, state) {
|
|
63
|
+
const bindingNames = sameWorkerBindings.filter(({ className }) => state.autoWrapped.has(className)).map(({ bindingName }) => bindingName);
|
|
64
|
+
if (!bindingNames.length) {
|
|
65
|
+
return `const ${MERGED_OPTIONS_IDENTIFIER} = ${optionsFn};
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
const names = bindingNames.map((name) => JSON.stringify(name)).join(", ");
|
|
69
|
+
return `const ${MERGED_OPTIONS_IDENTIFIER} = (env) => { const opts = (${optionsFn})(env); return { ...opts, enableRpcTracePropagation: opts?.enableRpcTracePropagation ?? true, rpcTracePropagationBindings: [${names}, ...(opts?.rpcTracePropagationBindings ?? [])] }; };
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
53
72
|
function resolveWrapperKind(exportedName, localName, state) {
|
|
54
73
|
const configured = state.classWrappers.get(exportedName);
|
|
55
74
|
if (configured === "durableObject" && localName && state.agentClasses.has(localName)) return "agent";
|
|
@@ -69,12 +88,16 @@ function collectTopLevelClasses(ast) {
|
|
|
69
88
|
function wrapDefaultExport(node, ctx, state) {
|
|
70
89
|
const decl = node.declaration;
|
|
71
90
|
if (isCallToMethod(decl, "withSentry")) return;
|
|
72
|
-
if (decl.type === "Identifier" && state.renamedLocals.has(decl.name))
|
|
91
|
+
if (decl.type === "Identifier" && state.renamedLocals.has(decl.name)) {
|
|
92
|
+
state.autoWrapped.add(DEFAULT_EXPORT);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
73
95
|
state.ms.overwrite(node.start, decl.start, "const __SENTRY_DEFAULT_EXPORT__ = ");
|
|
74
96
|
state.ms.append(`
|
|
75
|
-
export default __SENTRY__.withSentry(${
|
|
97
|
+
export default __SENTRY__.withSentry(${state.optionsFn}, __SENTRY_DEFAULT_EXPORT__);
|
|
76
98
|
`);
|
|
77
99
|
state.needsImport = true;
|
|
100
|
+
state.autoWrapped.add(DEFAULT_EXPORT);
|
|
78
101
|
}
|
|
79
102
|
function handleNamedExport(node, ctx, state) {
|
|
80
103
|
const decl = node.declaration;
|
|
@@ -113,10 +136,11 @@ function wrapInlineClassExport(exportNode, classDecl, ctx, state) {
|
|
|
113
136
|
state.ms.appendLeft(
|
|
114
137
|
exportNode.end,
|
|
115
138
|
`
|
|
116
|
-
export const ${className} = __SENTRY__.${WRAPPER_METHODS[kind]}(${
|
|
139
|
+
export const ${className} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${renamedClass});
|
|
117
140
|
`
|
|
118
141
|
);
|
|
119
142
|
state.wrappedClasses.add(className);
|
|
143
|
+
state.autoWrapped.add(className);
|
|
120
144
|
state.renamedLocals.add(className);
|
|
121
145
|
state.needsImport = true;
|
|
122
146
|
}
|
|
@@ -130,6 +154,7 @@ function wrapSpecifierExport(specifier, ctx, state) {
|
|
|
130
154
|
const localClass = localName ? state.topLevelClasses.get(localName) : void 0;
|
|
131
155
|
if (!localName || !localClass?.id) return;
|
|
132
156
|
state.wrappedClasses.add(exportedName);
|
|
157
|
+
state.autoWrapped.add(exportedName);
|
|
133
158
|
state.needsImport = true;
|
|
134
159
|
if (state.renamedLocals.has(localName)) return;
|
|
135
160
|
state.renamedLocals.add(localName);
|
|
@@ -138,7 +163,7 @@ function wrapSpecifierExport(specifier, ctx, state) {
|
|
|
138
163
|
state.ms.appendLeft(
|
|
139
164
|
localClass.end,
|
|
140
165
|
`
|
|
141
|
-
const ${localName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${
|
|
166
|
+
const ${localName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${renamedClass});
|
|
142
167
|
`
|
|
143
168
|
);
|
|
144
169
|
}
|
|
@@ -1 +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' | 'agent' | '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 agent: 'instrumentAgentWithSentry',\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 /**\n * Local class names detected as `agents` Agents. An Agent is configured as a Durable Object in\n * wrangler, so this upgrades those entries from `durableObject` to `agent`.\n */\n agentClasses?: ReadonlySet<string>;\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 agentClasses: ctx.agentClasses ?? new Set<string>(),\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 /** Local class names detected as `agents` Agents (see {@link TransformContext.agentClasses}). */\n agentClasses: ReadonlySet<string>;\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 *\n * The one case where config is refined rather than obeyed is an `agents` Agent:\n * it *is* a Durable Object, so wrangler can only ever describe it as one, and\n * only the detected base chain distinguishes the two.\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 === 'durableObject' && localName && state.agentClasses.has(localName)) return 'agent';\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) continue;\n\n // A hand-wrapped Agent is configured as a Durable Object, so accept either helper there —\n // otherwise an already-instrumented Agent would be reported as unwrapped.\n const accepted =\n kind === 'durableObject' ? [WRAPPER_METHODS.durableObject, WRAPPER_METHODS.agent] : [WRAPPER_METHODS[kind]];\n\n if (accepted.some(method => isCallToMethod(declarator.init as BaseNode, method))) {\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":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.js","sources":["../../../src/vite/transform.ts"],"sourcesContent":["import MagicString from 'magic-string';\nimport { DEFAULT_EXPORT, type ExportName, type SameWorkerBinding } from './bindings';\nimport { detectWorkerEntrypointClasses } from './workerEntrypoint';\n\nconst MERGED_OPTIONS_IDENTIFIER = '__SENTRY_OPTIONS__';\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' | 'agent' | '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 agent: 'instrumentAgentWithSentry',\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 /**\n * Local class names detected as `agents` Agents. An Agent is configured as a Durable Object in\n * wrangler, so this upgrades those entries from `durableObject` to `agent`.\n */\n agentClasses?: ReadonlySet<string>;\n optionsFn: string;\n /** Import statement prepended when `optionsFn` references a separate module. */\n optionsImport?: string;\n /** @see {@link import('./wranglerConfig').WranglerConfig.sameWorkerBindings} */\n sameWorkerBindings?: readonly SameWorkerBinding[];\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 sameWorkerBindings = ctx.sameWorkerBindings ?? [];\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 agentClasses: ctx.agentClasses ?? new Set<string>(),\n workerEntrypointClasses: detectWorkerEntrypointClasses(ast),\n // The identifier must be chosen before wrapping, which bindings survive is only known after.\n optionsFn: sameWorkerBindings.length > 0 ? MERGED_OPTIONS_IDENTIFIER : ctx.optionsFn,\n autoWrapped: new Set<ExportName>(),\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 // `prepend` inserts before earlier prepends, yielding: Sentry import, options import, declaration.\n if (sameWorkerBindings.length > 0) {\n ms.prepend(buildMergedOptionsDeclaration(sameWorkerBindings, ctx.optionsFn, state));\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 /** Local class names detected as `agents` Agents (see {@link TransformContext.agentClasses}). */\n agentClasses: ReadonlySet<string>;\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 optionsFn: string;\n /**\n * Export names wrapped by this transform, so their options can be extended with\n * `rpcTracePropagationBindings`. Hand-wrapped exports stay out, they keep the options they were\n * wrapped with. `wrappedClasses` counts both.\n */\n autoWrapped: Set<ExportName>;\n}\n\n/**\n * Builds the callback that merges same-worker binding names into `rpcTracePropagationBindings` at\n * runtime, the options object only exists once the callback runs with `env`. Only bindings whose\n * class this transform wrapped survive, a hand-wrapped class runs on its own options.\n *\n * The same callback also turns `enableRpcTracePropagation` on, because it is what the wrapped\n * receivers read to continue an incoming trace. An explicit value in the user's options wins.\n */\nfunction buildMergedOptionsDeclaration(\n sameWorkerBindings: readonly SameWorkerBinding[],\n optionsFn: string,\n state: TransformState,\n): string {\n const bindingNames = sameWorkerBindings\n .filter(({ className }) => state.autoWrapped.has(className))\n .map(({ bindingName }) => bindingName);\n\n if (!bindingNames.length) {\n return `const ${MERGED_OPTIONS_IDENTIFIER} = ${optionsFn};\\n`;\n }\n\n const names = bindingNames.map(name => JSON.stringify(name)).join(', ');\n return (\n `const ${MERGED_OPTIONS_IDENTIFIER} = (env) => { ` +\n `const opts = (${optionsFn})(env); ` +\n 'return { ...opts, ' +\n 'enableRpcTracePropagation: opts?.enableRpcTracePropagation ?? true, ' +\n `rpcTracePropagationBindings: [${names}, ...(opts?.rpcTracePropagationBindings ?? [])] }; };\\n`\n );\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 *\n * The one case where config is refined rather than obeyed is an `agents` Agent:\n * it *is* a Durable Object, so wrangler can only ever describe it as one, and\n * only the detected base chain distinguishes the two.\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 === 'durableObject' && localName && state.agentClasses.has(localName)) return 'agent';\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(...))`. The binding still\n // points at the wrapped class, so the default export counts as auto-wrapped.\n if (decl.type === 'Identifier' && state.renamedLocals.has((decl as IdentifierNode).name)) {\n state.autoWrapped.add(DEFAULT_EXPORT);\n return;\n }\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(${state.optionsFn}, __SENTRY_DEFAULT_EXPORT__);\\n`);\n state.needsImport = true;\n state.autoWrapped.add(DEFAULT_EXPORT);\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) continue;\n\n // A hand-wrapped Agent is configured as a Durable Object, so accept either helper there —\n // otherwise an already-instrumented Agent would be reported as unwrapped.\n const accepted =\n kind === 'durableObject' ? [WRAPPER_METHODS.durableObject, WRAPPER_METHODS.agent] : [WRAPPER_METHODS[kind]];\n\n if (accepted.some(method => isCallToMethod(declarator.init as BaseNode, method))) {\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]}(${state.optionsFn}, ${renamedClass});\\n`,\n );\n\n state.wrappedClasses.add(className);\n state.autoWrapped.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.autoWrapped.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]}(${state.optionsFn}, ${renamedClass});\\n`,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { resolve, dirname } from 'node:path';
|
|
3
3
|
import { unstable_readConfig } from 'wrangler';
|
|
4
|
+
import { DEFAULT_EXPORT } from './bindings.js';
|
|
4
5
|
|
|
5
6
|
function resolveWranglerConfig(root, explicitPath) {
|
|
6
7
|
const configPath = explicitPath ? resolve(root, explicitPath) : ["wrangler.json", "wrangler.jsonc", "wrangler.toml"].map((name) => resolve(root, name)).find(existsSync);
|
|
@@ -18,7 +19,8 @@ function resolveWranglerConfig(root, explicitPath) {
|
|
|
18
19
|
main: raw.main,
|
|
19
20
|
durableObjects: collectClassBindings(raw.durable_objects?.bindings),
|
|
20
21
|
workflows: collectClassBindings(raw.workflows),
|
|
21
|
-
workerEntrypoints: collectSelfBoundEntrypoints(raw)
|
|
22
|
+
workerEntrypoints: collectSelfBoundEntrypoints(raw),
|
|
23
|
+
sameWorkerBindings: collectSameWorkerBindings(raw)
|
|
22
24
|
},
|
|
23
25
|
configDir: dirname(raw.configPath ?? configPath)
|
|
24
26
|
};
|
|
@@ -35,6 +37,23 @@ function collectSelfBoundEntrypoints(raw) {
|
|
|
35
37
|
}
|
|
36
38
|
return [...entrypoints];
|
|
37
39
|
}
|
|
40
|
+
function collectSameWorkerBindings(raw) {
|
|
41
|
+
const bindings = [];
|
|
42
|
+
for (const binding of raw.durable_objects?.bindings ?? []) {
|
|
43
|
+
if (typeof binding?.name === "string" && typeof binding.class_name === "string" && !binding.script_name) {
|
|
44
|
+
bindings.push({ bindingName: binding.name, className: binding.class_name });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
for (const binding of raw.services ?? []) {
|
|
48
|
+
if (raw.name && binding?.service === raw.name && typeof binding.binding === "string") {
|
|
49
|
+
bindings.push({
|
|
50
|
+
bindingName: binding.binding,
|
|
51
|
+
className: typeof binding.entrypoint === "string" ? binding.entrypoint : DEFAULT_EXPORT
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return bindings;
|
|
56
|
+
}
|
|
38
57
|
function collectClassBindings(bindings) {
|
|
39
58
|
const result = [];
|
|
40
59
|
const seenClassNames = /* @__PURE__ */ new Set();
|
|
@@ -48,5 +67,5 @@ function collectClassBindings(bindings) {
|
|
|
48
67
|
return result;
|
|
49
68
|
}
|
|
50
69
|
|
|
51
|
-
export { resolveWranglerConfig };
|
|
70
|
+
export { DEFAULT_EXPORT, resolveWranglerConfig };
|
|
52
71
|
//# sourceMappingURL=wranglerConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wranglerConfig.js","sources":["../../../src/vite/wranglerConfig.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { type Unstable_Config, unstable_readConfig } from 'wrangler';\n\n/**\n * The slice of the wrangler configuration the auto-instrument plugin cares\n * about. `main` is an absolute path (wrangler resolves it against the config\n * file's directory).\n */\nexport interface WranglerConfig {\n main?: string;\n durableObjects: Array<{ name: string; className: string }>;\n workflows: Array<{ name: string; className: string }>;\n /**\n * Named `WorkerEntrypoint` exports this worker binds to itself via a service\n * binding (`services[]` whose `service` is this worker's own `name`). Only\n * self-bindings appear here: a service binding's `entrypoint` otherwise names\n * an export on a *different* worker, which this build can't wrap.\n */\n workerEntrypoints: string[];\n}\n\n/**\n * Locate and resolve the wrangler configuration via wrangler's own\n * `unstable_readConfig` — the API `@cloudflare/vite-plugin` uses.\n *\n * We only locate the file (probing `wrangler.json`, `.jsonc`, `.toml` inside\n * `root` with wrangler's own precedence, since it discovers from `cwd` rather\n * than an arbitrary root); wrangler then parses it, flattens the active\n * environment (honoring `CLOUDFLARE_ENV`), and resolves `main` to an absolute\n * path. Durable Object and Workflow bindings are the active environment's,\n * matching what the deployed Worker actually binds.\n *\n * Returns `undefined` when no config file is found or it can't be read/parsed\n * (the caller warns and disables auto-instrumentation rather than failing the\n * whole build).\n */\nexport function resolveWranglerConfig(\n root: string,\n explicitPath?: string,\n): { config: WranglerConfig; configDir: string } | undefined {\n const configPath = explicitPath\n ? resolve(root, explicitPath)\n : ['wrangler.json', 'wrangler.jsonc', 'wrangler.toml'].map(name => resolve(root, name)).find(existsSync);\n\n if (!configPath || !existsSync(configPath)) {\n return undefined;\n }\n\n let raw: Unstable_Config;\n try {\n // `hideWarnings` keeps wrangler's config diagnostics (e.g. missing DO\n // migrations) out of the Vite build output.\n raw = unstable_readConfig({ config: configPath }, { hideWarnings: true });\n } catch {\n return undefined;\n }\n\n return {\n config: {\n main: raw.main,\n durableObjects: collectClassBindings(raw.durable_objects?.bindings),\n workflows: collectClassBindings(raw.workflows),\n workerEntrypoints: collectSelfBoundEntrypoints(raw),\n },\n configDir: dirname(raw.configPath ?? configPath),\n };\n}\n\n/**\n * Collect named `WorkerEntrypoint` exports the worker binds to itself. A service\n * binding's `entrypoint` normally names an export on the *target* worker, so it\n * is only ours when `service` equals this worker's own `name`. Without a `name`\n * there is nothing to match against, so no entrypoints are derivable.\n */\nfunction collectSelfBoundEntrypoints(raw: Unstable_Config): string[] {\n if (!raw.name) {\n return [];\n }\n const entrypoints = new Set<string>();\n for (const binding of raw.services ?? []) {\n if (binding?.service === raw.name && typeof binding.entrypoint === 'string') {\n entrypoints.add(binding.entrypoint);\n }\n }\n return [...entrypoints];\n}\n\n/**\n * Map wrangler class bindings (Durable Objects, Workflows — same shape) to the\n * `{ name, className }` the transform needs, skipping duplicates and bindings\n * with a `script_name` (those reference a class exported by a *different*\n * worker, so there is nothing to wrap in this worker's entry file).\n */\nfunction collectClassBindings(\n bindings: ReadonlyArray<{ name: string; class_name?: string; script_name?: string }> | undefined,\n): Array<{ name: string; className: string }> {\n const result: Array<{ name: string; className: string }> = [];\n const seenClassNames = new Set<string>();\n for (const binding of bindings ?? []) {\n if (typeof binding?.class_name !== 'string' || binding.script_name || seenClassNames.has(binding.class_name)) {\n continue;\n }\n seenClassNames.add(binding.class_name);\n result.push({ name: binding.name, className: binding.class_name });\n }\n return result;\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wranglerConfig.js","sources":["../../../src/vite/wranglerConfig.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { type Unstable_Config, unstable_readConfig } from 'wrangler';\nimport { DEFAULT_EXPORT, type ExportName, type SameWorkerBinding } from './bindings';\n\nexport { DEFAULT_EXPORT, type ExportName, type SameWorkerBinding };\n\n/**\n * The slice of the wrangler configuration the auto-instrument plugin cares\n * about. `main` is an absolute path (wrangler resolves it against the config\n * file's directory).\n */\nexport interface WranglerConfig {\n main?: string;\n durableObjects: Array<{ name: string; className: string }>;\n workflows: Array<{ name: string; className: string }>;\n /**\n * Named `WorkerEntrypoint` exports this worker binds to itself via a service\n * binding (`services[]` whose `service` is this worker's own `name`). Only\n * self-bindings appear here: a service binding's `entrypoint` otherwise names\n * an export on a *different* worker, which this build can't wrap.\n */\n workerEntrypoints: string[];\n /**\n * Bindings whose RPC receiver lives in this worker, so this build instruments it. Not deduped by\n * class, two bindings may point at the same class and both names have to be listed.\n */\n sameWorkerBindings: SameWorkerBinding[];\n}\n\n/**\n * Locate and resolve the wrangler configuration via wrangler's own\n * `unstable_readConfig` — the API `@cloudflare/vite-plugin` uses.\n *\n * We only locate the file (probing `wrangler.json`, `.jsonc`, `.toml` inside\n * `root` with wrangler's own precedence, since it discovers from `cwd` rather\n * than an arbitrary root); wrangler then parses it, flattens the active\n * environment (honoring `CLOUDFLARE_ENV`), and resolves `main` to an absolute\n * path. Durable Object and Workflow bindings are the active environment's,\n * matching what the deployed Worker actually binds.\n *\n * Returns `undefined` when no config file is found or it can't be read/parsed\n * (the caller warns and disables auto-instrumentation rather than failing the\n * whole build).\n */\nexport function resolveWranglerConfig(\n root: string,\n explicitPath?: string,\n): { config: WranglerConfig; configDir: string } | undefined {\n const configPath = explicitPath\n ? resolve(root, explicitPath)\n : ['wrangler.json', 'wrangler.jsonc', 'wrangler.toml'].map(name => resolve(root, name)).find(existsSync);\n\n if (!configPath || !existsSync(configPath)) {\n return undefined;\n }\n\n let raw: Unstable_Config;\n try {\n // `hideWarnings` keeps wrangler's config diagnostics (e.g. missing DO\n // migrations) out of the Vite build output.\n raw = unstable_readConfig({ config: configPath }, { hideWarnings: true });\n } catch {\n return undefined;\n }\n\n return {\n config: {\n main: raw.main,\n durableObjects: collectClassBindings(raw.durable_objects?.bindings),\n workflows: collectClassBindings(raw.workflows),\n workerEntrypoints: collectSelfBoundEntrypoints(raw),\n sameWorkerBindings: collectSameWorkerBindings(raw),\n },\n configDir: dirname(raw.configPath ?? configPath),\n };\n}\n\n/**\n * Collect named `WorkerEntrypoint` exports the worker binds to itself. A service\n * binding's `entrypoint` normally names an export on the *target* worker, so it\n * is only ours when `service` equals this worker's own `name`. Without a `name`\n * there is nothing to match against, so no entrypoints are derivable.\n */\nfunction collectSelfBoundEntrypoints(raw: Unstable_Config): string[] {\n if (!raw.name) {\n return [];\n }\n const entrypoints = new Set<string>();\n for (const binding of raw.services ?? []) {\n if (binding?.service === raw.name && typeof binding.entrypoint === 'string') {\n entrypoints.add(binding.entrypoint);\n }\n }\n return [...entrypoints];\n}\n\n/**\n * Bindings with a `script_name` or naming another worker target a class this build does not wrap,\n * so they are excluded and stay opt-in.\n */\nfunction collectSameWorkerBindings(raw: Unstable_Config): SameWorkerBinding[] {\n const bindings: SameWorkerBinding[] = [];\n\n for (const binding of raw.durable_objects?.bindings ?? []) {\n if (typeof binding?.name === 'string' && typeof binding.class_name === 'string' && !binding.script_name) {\n bindings.push({ bindingName: binding.name, className: binding.class_name });\n }\n }\n\n for (const binding of raw.services ?? []) {\n // A service binding is only ours when `service` names this worker; without a `name` none can be.\n if (raw.name && binding?.service === raw.name && typeof binding.binding === 'string') {\n bindings.push({\n bindingName: binding.binding,\n className: typeof binding.entrypoint === 'string' ? binding.entrypoint : DEFAULT_EXPORT,\n });\n }\n }\n\n return bindings;\n}\n\n/**\n * Map wrangler class bindings (Durable Objects, Workflows — same shape) to the\n * `{ name, className }` the transform needs, skipping duplicates and bindings\n * with a `script_name` (those reference a class exported by a *different*\n * worker, so there is nothing to wrap in this worker's entry file).\n */\nfunction collectClassBindings(\n bindings: ReadonlyArray<{ name: string; class_name?: string; script_name?: string }> | undefined,\n): Array<{ name: string; className: string }> {\n const result: Array<{ name: string; className: string }> = [];\n const seenClassNames = new Set<string>();\n for (const binding of bindings ?? []) {\n if (typeof binding?.class_name !== 'string' || binding.script_name || seenClassNames.has(binding.class_name)) {\n continue;\n }\n seenClassNames.add(binding.class_name);\n result.push({ name: binding.name, className: binding.class_name });\n }\n return result;\n}\n"],"names":[],"mappings":"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"}
|