import { withIsolationScope, withScope, getCurrentScope, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, captureException, flush } from '@sentry/core'; import { setAsyncLocalStorageAsyncContextStrategy } from './async.js'; import { flushAndDispose } from './flush.js'; import { instrumentEnv } from './instrumentations/worker/instrumentEnv.js'; import { addCloudResourceContext } from './scope-utils.js'; import { init } from './sdk.js'; import { instrumentContext } from './utils/instrumentContext.js'; const UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i; async function deterministicTraceIdFromInstanceId(instanceId) { const buf = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(instanceId)); return Array.from(new Uint8Array(buf)).slice(0, 16).map((b) => b.toString(16).padStart(2, "0")).join(""); } async function propagationContextFromInstanceId(instanceId) { const traceId = UUID_REGEX.test(instanceId) ? instanceId.replace(/-/g, "") : await deterministicTraceIdFromInstanceId(instanceId); const sampleRand = parseInt(traceId.slice(-4), 16) / 65535; return { traceId, sampleRand }; } class WrappedWorkflowStep { constructor(_instanceId, _options, _step, _waitUntil) { this._instanceId = _instanceId; this._options = _options; this._step = _step; this._waitUntil = _waitUntil; } async do(name, configOrCallback, maybeCallback) { const scopeForStep = getCurrentScope(); const userCallback = maybeCallback || configOrCallback; const config = typeof configOrCallback === "function" ? void 0 : configOrCallback; const instrumentedCallback = async (...args) => { const stepContext = args[0]; const attempt = stepContext?.attempt; const retryLimit = stepContext?.config?.retries?.limit; const hasStepContext = typeof attempt === "number" && typeof retryLimit === "number"; const isFinalAttempt = !hasStepContext || attempt > retryLimit; return startSpan( { op: "function.step.do", name, scope: scopeForStep, attributes: { "cloudflare.workflow.timeout": config?.timeout, "cloudflare.workflow.retries.backoff": config?.retries?.backoff, "cloudflare.workflow.retries.delay": config?.retries?.delay, "cloudflare.workflow.retries.limit": config?.retries?.limit, "cloudflare.workflow.attempt": attempt, [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.faas.cloudflare.workflow", [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "task" } }, async (span) => { try { const result = await userCallback(...args); span.setStatus({ code: 1 }); return result; } catch (error) { if (isFinalAttempt) { captureException(error, { mechanism: { handled: true, type: "auto.faas.cloudflare.workflow" } }); } throw error; } finally { this._waitUntil(flush(2e3)); } } ); }; return config ? this._step.do(name, config, instrumentedCallback) : this._step.do(name, instrumentedCallback); } async sleep(name, duration) { return this._step.sleep(name, duration); } async sleepUntil(name, timestamp) { return this._step.sleepUntil(name, timestamp); } async waitForEvent(name, options) { return this._step.waitForEvent(name, options); } } function instrumentWorkflowWithSentry(optionsCallback, WorkFlowClass) { return new Proxy(WorkFlowClass, { construct(target, args, newTarget) { const [ctx, env] = args; const context = instrumentContext(ctx); const options = optionsCallback(env); args[0] = context; args[1] = instrumentEnv(env, options); const instance = Reflect.construct(target, args, newTarget); return new Proxy(instance, { get(obj, prop, receiver) { if (prop === "run") { return async function(event, step) { setAsyncLocalStorageAsyncContextStrategy(); return withIsolationScope(async (isolationScope) => { const waitUntil = context.waitUntil.bind(context); const client = init({ ...options, ctx: context, enableDedupe: false }); isolationScope.setClient(client); addCloudResourceContext(isolationScope); return withScope(async (scope) => { const propagationContext = await propagationContextFromInstanceId(event.instanceId); scope.setPropagationContext(propagationContext); try { return await obj.run.call( obj, event, new WrappedWorkflowStep(event.instanceId, options, step, waitUntil) ); } finally { waitUntil(flushAndDispose(client)); } }); }); }; } return Reflect.get(obj, prop, receiver); } }); } }); } export { deterministicTraceIdFromInstanceId, instrumentWorkflowWithSentry }; //# sourceMappingURL=workflows.js.map