{"version":3,"sources":["../../src/observability/otel.ts"],"names":["trace","context","SpanStatusCode","span"],"mappings":"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","file":"otel.cjs","sourcesContent":["/**\n * OpenTelemetry adapter for kompensa.\n *\n * Returns a {@link FlowHooks} object that opens spans for the flow and each\n * step, attaches retries as events on the step span, and surfaces compensation\n * as a sibling span. Plug it into `FlowConfig.hooks` and your existing OTel\n * pipeline picks the spans up automatically.\n *\n * @example\n * import { trace } from '@opentelemetry/api';\n * import { createOtelHooks } from 'kompensa/observability/otel';\n *\n * const flow = createFlow('checkout', {\n *   hooks: createOtelHooks({ tracer: trace.getTracer('my-service') }),\n * });\n *\n * Peer dependency: `@opentelemetry/api` ^1. Optional — only required when this\n * subpath is imported.\n */\nimport { context, trace, SpanStatusCode } from '@opentelemetry/api';\nimport type { Attributes, Context, Span, Tracer } from '@opentelemetry/api';\nimport type { FlowHooks } from '../types.js';\n\nexport interface CreateOtelHooksOptions {\n  /** Tracer obtained from `trace.getTracer('your-service')`. */\n  tracer: Tracer;\n  /**\n   * Prefix for span names. Default `\"kompensa\"` produces names like\n   * `kompensa.flow.<flowName>` and `kompensa.step.<stepName>`.\n   */\n  spanPrefix?: string;\n  /** Attributes added to every span emitted by this adapter. */\n  baseAttributes?: Attributes;\n}\n\n/**\n * Build a {@link FlowHooks} implementation that emits OpenTelemetry spans\n * mirroring the lifecycle of a kompensa flow.\n *\n * Span hierarchy:\n * ```\n * kompensa.flow.<flowName>\n *  ├─ kompensa.step.<stepName>          (one per sequential step)\n *  ├─ kompensa.step.<group>.<branch>    (one per parallel branch)\n *  └─ kompensa.compensate.<stepName>    (only when compensation runs)\n * ```\n *\n * Each step span carries `kompensa.step.attempts`, retries are recorded as\n * `retry` events on the same span, and failures call `recordException` so the\n * stack trace shows up on the tracing backend.\n */\nexport function createOtelHooks(opts: CreateOtelHooksOptions): FlowHooks {\n  const { tracer, spanPrefix = 'kompensa', baseAttributes = {} } = opts;\n\n  // Per-flow root spans (and the OTel context that has them set as active —\n  // child spans are anchored to that context so the hierarchy is correct in\n  // any backend).\n  const flowSpans = new Map<string, { span: Span; ctx: Context }>();\n  // Step + compensation spans keyed by `${flowId}::${stepName}` and\n  // `${flowId}::comp::${stepName}` respectively.\n  const stepSpans = new Map<string, Span>();\n\n  const stepKey = (flowId: string, stepName: string) => `${flowId}::${stepName}`;\n  const compKey = (flowId: string, stepName: string) => `${flowId}::comp::${stepName}`;\n\n  return {\n    onFlowStart(e) {\n      const span = tracer.startSpan(`${spanPrefix}.flow.${e.flowName}`, {\n        attributes: {\n          ...baseAttributes,\n          'kompensa.flow.name': e.flowName,\n          'kompensa.flow.id': e.flowId,\n          'kompensa.flow.resumed': e.resumed,\n        },\n      });\n      const ctx = trace.setSpan(context.active(), span);\n      flowSpans.set(e.flowId, { span, ctx });\n    },\n\n    onFlowEnd(e) {\n      const entry = flowSpans.get(e.flowId);\n      if (!entry) return;\n      entry.span.setAttributes({\n        'kompensa.flow.status': e.status,\n        'kompensa.flow.duration_ms': e.durationMs,\n      });\n      if (e.status === 'success') {\n        entry.span.setStatus({ code: SpanStatusCode.OK });\n      } else {\n        entry.span.setStatus({\n          code: SpanStatusCode.ERROR,\n          message: errorMessage(e.error),\n        });\n        if (e.error instanceof Error) entry.span.recordException(e.error);\n      }\n      entry.span.end();\n      flowSpans.delete(e.flowId);\n    },\n\n    onStepStart(e) {\n      const k = stepKey(e.flowId, e.stepName);\n      const existing = stepSpans.get(k);\n      if (existing) {\n        // Retry attempt — same logical step, record an event rather than open\n        // a sibling span. Attempt 1 already opened the span on the first call.\n        existing.addEvent('attempt', { attempt: e.attempt });\n        return;\n      }\n      const flowEntry = flowSpans.get(e.flowId);\n      const parentCtx = flowEntry?.ctx ?? context.active();\n      const span = tracer.startSpan(\n        `${spanPrefix}.step.${e.stepName}`,\n        {\n          attributes: {\n            ...baseAttributes,\n            'kompensa.flow.name': e.flowName,\n            'kompensa.flow.id': e.flowId,\n            'kompensa.step.name': e.stepName,\n            'kompensa.step.index': e.stepIndex,\n          },\n        },\n        parentCtx,\n      );\n      stepSpans.set(k, span);\n    },\n\n    onStepRetry(e) {\n      const span = stepSpans.get(stepKey(e.flowId, e.stepName));\n      if (!span) return;\n      span.addEvent('retry', {\n        attempt: e.attempt,\n        next_delay_ms: e.nextDelayMs,\n        error_message: errorMessage(e.error),\n      });\n      if (e.error instanceof Error) span.recordException(e.error);\n    },\n\n    onStepEnd(e) {\n      const k = stepKey(e.flowId, e.stepName);\n      const span = stepSpans.get(k);\n      if (!span) return;\n      span.setAttributes({\n        'kompensa.step.status': e.status,\n        'kompensa.step.attempts': e.attempts,\n        'kompensa.step.duration_ms': e.durationMs,\n      });\n      if (e.status === 'success' || e.status === 'skipped') {\n        span.setStatus({ code: SpanStatusCode.OK });\n      } else {\n        span.setStatus({\n          code: SpanStatusCode.ERROR,\n          message: errorMessage(e.error),\n        });\n        if (e.error instanceof Error) span.recordException(e.error);\n      }\n      span.end();\n      stepSpans.delete(k);\n    },\n\n    onCompensate(e) {\n      const k = compKey(e.flowId, e.stepName);\n      if (e.status === 'compensating') {\n        // Open a sibling span under the flow span so operators can see\n        // exactly which step rolled back and how long the compensation took.\n        const flowEntry = flowSpans.get(e.flowId);\n        const parentCtx = flowEntry?.ctx ?? context.active();\n        const span = tracer.startSpan(\n          `${spanPrefix}.compensate.${e.stepName}`,\n          {\n            attributes: {\n              ...baseAttributes,\n              'kompensa.flow.name': e.flowName,\n              'kompensa.flow.id': e.flowId,\n              'kompensa.step.name': e.stepName,\n              'kompensa.step.index': e.stepIndex,\n            },\n          },\n          parentCtx,\n        );\n        stepSpans.set(k, span);\n        return;\n      }\n      const span = stepSpans.get(k);\n      if (!span) return;\n      if (e.status === 'compensated') {\n        span.setStatus({ code: SpanStatusCode.OK });\n      } else {\n        span.setStatus({\n          code: SpanStatusCode.ERROR,\n          message: errorMessage(e.error),\n        });\n        if (e.error instanceof Error) span.recordException(e.error);\n      }\n      span.end();\n      stepSpans.delete(k);\n    },\n  };\n}\n\nfunction errorMessage(err: unknown): string {\n  if (err instanceof Error) return err.message;\n  if (typeof err === 'string') return err;\n  if (err == null) return '';\n  return String(err);\n}\n"]}