UNPKG

autotel

Version:
346 lines (343 loc) 12.1 kB
import { SafeBaggageSchema } from './business-baggage.js'; import { T as TraceContext } from './trace-context-t5X1AP-e.js'; import '@opentelemetry/api'; /** * Pre-built baggage schema for distributed workflows * * Use this to read/write workflow context that propagates across services. * * @example Setting workflow baggage * ```typescript * WorkflowBaggage.set(ctx, { * workflowId: 'order-12345', * workflowName: 'OrderFulfillment', * stepName: 'ReserveInventory', * stepIndex: 1, * }); * ``` * * @example Reading workflow baggage in downstream service * ```typescript * const { workflowId, workflowName, stepIndex } = WorkflowBaggage.get(ctx); * console.log(`Processing ${workflowName} step ${stepIndex}`); * ``` */ declare const WorkflowBaggage: SafeBaggageSchema<{ /** Unique identifier for the workflow instance */ readonly workflowId: { readonly type: "string"; readonly maxLength: 128; readonly required: true; }; /** Name/type of the workflow (e.g., "OrderFulfillment") */ readonly workflowName: { readonly type: "string"; readonly maxLength: 64; readonly required: true; }; /** Version of the workflow definition */ readonly workflowVersion: { readonly type: "string"; readonly maxLength: 32; }; /** Current step name */ readonly stepName: { readonly type: "string"; readonly maxLength: 64; }; /** Current step index (0-based) */ readonly stepIndex: { readonly type: "number"; }; /** Total number of steps (if known) */ readonly totalSteps: { readonly type: "number"; }; /** Parent workflow ID (for sub-workflows) */ readonly parentWorkflowId: { readonly type: "string"; readonly maxLength: 128; }; /** Correlation ID for external systems */ readonly correlationId: { readonly type: "string"; readonly maxLength: 128; }; /** Workflow priority */ readonly priority: { readonly type: "enum"; readonly values: readonly ["low", "normal", "high", "critical"]; }; /** Initiating user/system */ readonly initiatedBy: { readonly type: "string"; readonly maxLength: 64; }; /** Workflow start timestamp (ISO) */ readonly startedAt: { readonly type: "string"; readonly maxLength: 30; }; }>; /** * Type for workflow baggage values */ type WorkflowBaggageValues = { workflowId: string; workflowName: string; workflowVersion?: string; stepName?: string; stepIndex?: number; totalSteps?: number; parentWorkflowId?: string; correlationId?: string; priority?: 'low' | 'normal' | 'high' | 'critical'; initiatedBy?: string; startedAt?: string; }; /** * Configuration for distributed workflow tracing */ interface DistributedWorkflowConfig { /** Workflow name/type (e.g., "OrderFulfillment", "UserOnboarding") */ name: string; /** * Extract workflow ID from function arguments * * Receives all arguments passed to the workflow function, allowing * multi-parameter handlers to derive workflow IDs from any argument. * * @example Single argument * ```typescript * workflowIdFrom: (order) => order.id * ``` * * @example Multiple arguments (payload + metadata) * ```typescript * workflowIdFrom: (payload, metadata) => metadata.correlationId ?? payload.id * ``` */ workflowIdFrom: (...args: unknown[]) => string; /** Workflow version (e.g., "1.0.0", "2023-01-15") */ version?: string; /** Total number of steps if known */ totalSteps?: number; /** Parent workflow ID (for sub-workflows) */ parentWorkflowId?: string; /** Correlation ID for external systems */ correlationId?: string; /** Workflow priority */ priority?: 'low' | 'normal' | 'high' | 'critical'; /** User/system that initiated the workflow */ initiatedBy?: string; /** Additional span attributes */ attributes?: Record<string, string | number | boolean>; /** Callback on workflow start */ onStart?: (ctx: DistributedWorkflowContext) => void; /** Callback on workflow completion */ onComplete?: (ctx: DistributedWorkflowContext, result: unknown) => void; /** Callback on workflow error */ onError?: (ctx: DistributedWorkflowContext, error: Error) => void; } /** * Configuration for distributed workflow step */ interface DistributedStepConfig { /** Step name (e.g., "ReserveInventory", "ChargePayment") */ name: string; /** * Extract baggage from incoming message/request * * If true, reads workflow baggage from current context (assumes already extracted). * If function, extracts from arguments. * * @default true */ extractBaggage?: boolean | ((args: unknown[]) => WorkflowBaggageValues | null); /** Override step index (otherwise uses baggage or auto-increments) */ stepIndex?: number; /** Additional span attributes */ attributes?: Record<string, string | number | boolean>; /** Whether this step is idempotent (safe to retry) */ idempotent?: boolean; /** Whether this step is a compensation/rollback step */ isCompensation?: boolean; /** Callback on step start */ onStart?: (ctx: DistributedStepContext) => void; /** Callback on step completion */ onComplete?: (ctx: DistributedStepContext, result: unknown) => void; /** Callback on step error */ onError?: (ctx: DistributedStepContext, error: Error) => void; } /** * Extended context for distributed workflow root */ interface DistributedWorkflowContext extends TraceContext { /** The workflow ID */ workflowId: string; /** The workflow name */ workflowName: string; /** The workflow version */ workflowVersion?: string; /** Get workflow baggage for propagation to other services */ getWorkflowBaggage(): WorkflowBaggageValues; /** Set additional workflow baggage fields */ setWorkflowBaggage(values: Partial<WorkflowBaggageValues>): void; /** Get headers with workflow baggage for outgoing requests */ getWorkflowHeaders(): Record<string, string>; /** Record workflow step completion (for progress tracking) */ recordStepProgress(stepName: string, stepIndex: number): void; } /** * Extended context for distributed workflow step */ interface DistributedStepContext extends TraceContext { /** The workflow ID (from baggage) */ workflowId: string | null; /** The workflow name (from baggage) */ workflowName: string | null; /** The current step name */ stepName: string; /** The current step index */ stepIndex: number | null; /** Whether this step is a compensation */ isCompensation: boolean; /** Get the full workflow baggage */ getWorkflowBaggage(): WorkflowBaggageValues | null; /** Update workflow baggage (e.g., increment step index) */ updateWorkflowBaggage(values: Partial<WorkflowBaggageValues>): void; /** Get headers with updated workflow baggage for downstream calls */ getWorkflowHeaders(): Record<string, string>; /** Mark step as requiring compensation on failure */ requiresCompensation(compensationData?: Record<string, unknown>): void; } /** * Create a traced distributed workflow function * * Wraps a function as the entry point for a distributed workflow. Automatically: * - Generates or extracts workflow ID * - Sets workflow baggage for downstream propagation * - Creates root span with workflow attributes * * @param config - Workflow configuration * @returns Factory function for the workflow handler * * @example Basic usage * ```typescript * export const createOrder = traceDistributedWorkflow({ * name: 'OrderFulfillment', * workflowIdFrom: (order) => order.id, * version: '1.0.0', * })(ctx => async (order: Order) => { * ctx.recordStepProgress('ValidateOrder', 0); * await validateOrder(order); * * ctx.recordStepProgress('ReserveInventory', 1); * await publishToInventoryService(order); * * return { workflowId: ctx.workflowId, status: 'started' }; * }); * ``` */ declare function traceDistributedWorkflow<TArgs extends unknown[], TReturn>(config: DistributedWorkflowConfig): (fnFactory: (ctx: DistributedWorkflowContext) => (...args: TArgs) => Promise<TReturn>) => ((...args: TArgs) => Promise<TReturn>); /** * Create a traced distributed workflow step * * Use in downstream services to trace steps that are part of a distributed workflow. * Automatically extracts workflow baggage from the current context. * * @param config - Step configuration * @returns Factory function for the step handler * * @example Consumer in downstream service * ```typescript * export const processInventory = traceConsumer({ * system: 'kafka', * destination: 'inventory-requests', * extractBaggage: true, // Extracts workflow.* from headers * })(ctx => { * // Wrap inner logic with traceDistributedStep * return traceDistributedStep({ * name: 'ReserveInventory', * })(stepCtx => async (message) => { * console.log(`Processing workflow ${stepCtx.workflowId}`); * await reserveItems(message.items); * })(message); * }); * ``` * * @example Standalone step handler * ```typescript * export const reserveInventory = traceDistributedStep({ * name: 'ReserveInventory', * idempotent: true, * })(ctx => async (request: InventoryRequest) => { * if (ctx.workflowId) { * console.log(`Part of workflow ${ctx.workflowId}, step ${ctx.stepIndex}`); * } * return await inventoryService.reserve(request.items); * }); * ``` */ declare function traceDistributedStep<TArgs extends unknown[], TReturn>(config: DistributedStepConfig): (fnFactory: (ctx: DistributedStepContext) => (...args: TArgs) => Promise<TReturn>) => ((...args: TArgs) => Promise<TReturn>); /** * Generate a unique workflow ID * * @param prefix - Optional prefix for the ID * @returns A unique workflow ID * * @example * ```typescript * const workflowId = generateWorkflowId('order'); // "order-abc123def456" * ``` */ declare function generateWorkflowId(prefix?: string): string; /** * Check if the current context is part of a distributed workflow * * @param ctx - The trace context * @returns True if workflow baggage is present */ declare function isInDistributedWorkflow(ctx: TraceContext): boolean; /** * Get workflow progress information * * @param ctx - The trace context * @returns Progress info or null if not in a workflow */ declare function getWorkflowProgress(ctx: TraceContext): { workflowId: string; workflowName: string; currentStep: string | null; currentStepIndex: number | null; totalSteps: number | null; percentComplete: number | null; } | null; /** * Create workflow correlation headers for manual propagation * * Use when you need to manually add workflow context to outgoing requests. * * @param values - Workflow baggage values * @returns Headers object with workflow baggage * * @example * ```typescript * const headers = createWorkflowHeaders({ * workflowId: 'order-123', * workflowName: 'OrderFulfillment', * stepIndex: 2, * }); * * await fetch('/api/inventory', { headers }); * ``` */ declare function createWorkflowHeaders(values: Partial<WorkflowBaggageValues>): Record<string, string>; /** * Parse workflow context from baggage header * * @param baggageHeader - The baggage header value * @returns Parsed workflow values or null */ declare function parseWorkflowFromBaggage(baggageHeader: string): Partial<WorkflowBaggageValues> | null; export { type DistributedStepConfig, type DistributedStepContext, type DistributedWorkflowConfig, type DistributedWorkflowContext, WorkflowBaggage, type WorkflowBaggageValues, createWorkflowHeaders, generateWorkflowId, getWorkflowProgress, isInDistributedWorkflow, parseWorkflowFromBaggage, traceDistributedStep, traceDistributedWorkflow };