import { withIsolationScope, withScope, getCurrentScope, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, captureException, flush } from '@sentry/core'; import { setAsyncLocalStorageAsyncContextStrategy } from './async.js'; import { getOriginalWaitUntil, flushAndDispose } from './flush.js'; import { markAsInstrumented } from './instrument.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, callbackOrRollback, maybeRollback) { const scopeForStep = getCurrentScope(); const hasConfig = typeof configOrCallback !== "function"; const config = hasConfig ? configOrCallback : void 0; const userCallback = hasConfig ? callbackOrRollback : configOrCallback; const rollbackOptions = hasConfig ? maybeRollback : callbackOrRollback; 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, // In workers-types v5, `delay` may be a `WorkflowDelayFunction`, which isn't a valid span attribute value. "cloudflare.workflow.retries.delay": typeof config?.retries?.delay === "function" ? void 0 : 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)); } } ); }; if (config) { return rollbackOptions ? this._step.do(name, config, instrumentedCallback, rollbackOptions) : this._step.do(name, config, instrumentedCallback); } return rollbackOptions ? this._step.do(name, instrumentedCallback, rollbackOptions) : 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) { const InstrumentedClass = 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 = getOriginalWaitUntil(context).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); } }); } }); markAsInstrumented(InstrumentedClass); return InstrumentedClass; } export { deterministicTraceIdFromInstanceId, instrumentWorkflowWithSentry }; //# sourceMappingURL=workflows.js.map