{"version":3,"file":"structured-error-CHg7DoIQ.cjs","names":["SpanStatusCode"],"sources":["../src/flatten-attributes.ts","../src/structured-error.ts"],"sourcesContent":["import type { AttributeValue } from './trace-context';\n\n/**\n * Convert an unknown value to an OTel-compatible AttributeValue.\n * Returns undefined when the value cannot be represented.\n */\nexport function toAttributeValue(value: unknown): AttributeValue | undefined {\n  if (\n    typeof value === 'string' ||\n    typeof value === 'number' ||\n    typeof value === 'boolean'\n  ) {\n    return value;\n  }\n  if (Array.isArray(value)) {\n    if (\n      value.every((v) => typeof v === 'string') ||\n      value.every((v) => typeof v === 'number') ||\n      value.every((v) => typeof v === 'boolean')\n    ) {\n      return value as AttributeValue;\n    }\n    try {\n      return JSON.stringify(value);\n    } catch {\n      return '<serialization-failed>';\n    }\n  }\n  if (value instanceof Date) {\n    return value.toISOString();\n  }\n  if (value instanceof Error) {\n    return value.message;\n  }\n  return undefined;\n}\n\n/**\n * Recursively flatten a nested object into dot-notation OTel attributes.\n * Includes circular reference protection via WeakSet.\n */\nexport function flattenToAttributes(\n  fields: Record<string, unknown>,\n  prefix = '',\n): Record<string, AttributeValue> {\n  const out: Record<string, AttributeValue> = {};\n  const seen = new WeakSet<object>();\n\n  function flatten(obj: Record<string, unknown>, currentPrefix: string): void {\n    for (const [key, value] of Object.entries(obj)) {\n      if (value == null) continue;\n      const nextKey = currentPrefix ? `${currentPrefix}.${key}` : key;\n\n      const attr = toAttributeValue(value);\n      if (attr !== undefined) {\n        out[nextKey] = attr;\n        continue;\n      }\n\n      if (typeof value === 'object' && value.constructor === Object) {\n        if (seen.has(value)) {\n          out[nextKey] = '<circular-reference>';\n          continue;\n        }\n        seen.add(value);\n        flatten(value as Record<string, unknown>, nextKey);\n        continue;\n      }\n\n      try {\n        out[nextKey] = JSON.stringify(value);\n      } catch {\n        out[nextKey] = '<serialization-failed>';\n      }\n    }\n  }\n\n  flatten(fields, prefix);\n  return out;\n}\n","import { SpanStatusCode } from '@opentelemetry/api';\nimport type { AttributeValue, TraceContext } from './trace-context';\nimport { flattenToAttributes } from './flatten-attributes';\n\nconst internalKey = Symbol.for('autotel.error.internal');\n\nexport interface StructuredErrorInput {\n  message: string;\n  why?: string;\n  fix?: string;\n  link?: string;\n  code?: string | number;\n  status?: number;\n  cause?: unknown;\n  details?: Record<string, unknown>;\n  name?: string;\n  /** Backend-only context. Omitted from toJSON() and never serialized to clients. */\n  internal?: Record<string, unknown>;\n}\n\nexport interface StructuredError extends Error {\n  why?: string;\n  fix?: string;\n  link?: string;\n  code?: string | number;\n  status?: number;\n  details?: Record<string, unknown>;\n  /** Backend-only context. Omitted from toJSON() and never serialized to clients. */\n  readonly internal?: Record<string, unknown>;\n}\n\nexport function createStructuredError(\n  input: StructuredErrorInput,\n): StructuredError {\n  const error = new Error(input.message, {\n    cause: input.cause,\n  }) as StructuredError;\n\n  error.name = input.name ?? 'StructuredError';\n  if (input.why !== undefined) error.why = input.why;\n  if (input.fix !== undefined) error.fix = input.fix;\n  if (input.link !== undefined) error.link = input.link;\n  if (input.code !== undefined) error.code = input.code;\n  if (input.status !== undefined) error.status = input.status;\n  if (input.details !== undefined) error.details = input.details;\n\n  if (input.internal !== undefined) {\n    Object.defineProperty(error, internalKey, {\n      value: input.internal,\n      enumerable: false,\n      writable: false,\n      configurable: true,\n    });\n  }\n\n  Object.defineProperty(error, 'internal', {\n    get() {\n      return (\n        this as StructuredError & { [internalKey]?: Record<string, unknown> }\n      )[internalKey];\n    },\n    enumerable: false,\n    configurable: true,\n  });\n\n  error.toString = () => {\n    const lines = [`${error.name}: ${error.message}`];\n    if (error.why) lines.push(`  Why: ${error.why}`);\n    if (error.fix) lines.push(`  Fix: ${error.fix}`);\n    if (error.link) lines.push(`  Link: ${error.link}`);\n    if (error.code !== undefined) lines.push(`  Code: ${error.code}`);\n    if (error.status !== undefined) lines.push(`  Status: ${error.status}`);\n    if (error.cause) {\n      const cause = error.cause as Error;\n      lines.push(`  Caused by: ${cause.name}: ${cause.message}`);\n    }\n    return lines.join('\\n');\n  };\n\n  return error;\n}\n\nexport function structuredErrorToJSON(\n  error: StructuredError,\n): Record<string, unknown> {\n  const result: Record<string, unknown> = {\n    name: error.name,\n    message: error.message,\n  };\n\n  if (error.status !== undefined) result.status = error.status;\n  if (error.why || error.fix || error.link) {\n    result.data = {\n      ...(error.why && { why: error.why }),\n      ...(error.fix && { fix: error.fix }),\n      ...(error.link && { link: error.link }),\n    };\n  }\n  if (error.code !== undefined) result.code = error.code;\n  if (error.details) result.details = error.details;\n  if (error.cause instanceof Error) {\n    result.cause = { name: error.cause.name, message: error.cause.message };\n  }\n\n  return result;\n}\n\nexport function getStructuredErrorAttributes(\n  error: Error,\n): Record<string, AttributeValue> {\n  const structured = error as StructuredError;\n  const attributes: Record<string, AttributeValue> = {\n    'error.type': error.name || 'Error',\n    'error.message': error.message,\n  };\n\n  if (error.stack) attributes['error.stack'] = error.stack;\n  if (structured.why) attributes['error.why'] = structured.why;\n  if (structured.fix) attributes['error.fix'] = structured.fix;\n  if (structured.link) attributes['error.link'] = structured.link;\n  if (structured.code !== undefined) {\n    attributes['error.code'] =\n      typeof structured.code === 'string'\n        ? structured.code\n        : String(structured.code);\n  }\n  if (structured.status !== undefined) {\n    attributes['error.status'] = structured.status;\n  }\n  if (structured.details) {\n    Object.assign(\n      attributes,\n      flattenToAttributes(structured.details, 'error.details'),\n    );\n  }\n\n  return attributes;\n}\n\nexport function recordStructuredError(\n  ctx: Pick<TraceContext, 'setAttributes' | 'setStatus'>,\n  error: Error,\n): void {\n  const maybeRecordException = (\n    ctx as unknown as {\n      recordException?: (e: Error) => void;\n    }\n  ).recordException;\n  if (typeof maybeRecordException === 'function') {\n    maybeRecordException(error);\n  }\n  ctx.setStatus({\n    code: SpanStatusCode.ERROR,\n    message: error.message,\n  });\n  ctx.setAttributes(getStructuredErrorAttributes(error));\n}\n"],"mappings":"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"}