{"version":3,"sources":["../src/normalize.ts"],"names":[],"mappings":"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","file":"normalize.mjs","sourcesContent":["/**\n * Schema Normalization\n *\n * Functions to normalize receipt claims to a canonical form for comparison.\n * Produces byte-identical JCS output regardless of how the receipt was created.\n */\n\nimport type { PEACReceiptClaims, Subject } from './types.js';\nimport type { PaymentEvidence } from './evidence.js';\nimport type { ControlBlock, ControlStep } from './control.js';\nimport type { AttestationReceiptClaims } from './attestation-receipt.js';\nimport type { ParseSuccess } from './receipt-parser.js';\n\n/**\n * Normalized core claims for comparison.\n *\n * This is the minimal set of fields that represent the semantic meaning\n * of a receipt. All optional fields that are undefined are omitted.\n */\nexport interface CoreClaims {\n  /** Issuer URL */\n  iss: string;\n  /** Audience / resource URL */\n  aud: string;\n  /** Receipt ID */\n  rid: string;\n  /** Issued at timestamp */\n  iat: number;\n  /** Expiry timestamp (omitted if not present) */\n  exp?: number;\n  /** Amount in smallest currency unit (commerce receipts) */\n  amt?: number;\n  /** Currency code (ISO 4217, commerce receipts) */\n  cur?: string;\n  /** Normalized payment evidence (commerce receipts) */\n  payment?: NormalizedPayment;\n  /** Subject (omitted if not present) */\n  subject?: Subject;\n  /** Control block (omitted if not present) */\n  control?: NormalizedControl;\n}\n\n/**\n * Normalized payment evidence for comparison.\n *\n * Only includes the semantic fields, not rail-specific evidence.\n */\nexport interface NormalizedPayment {\n  rail: string;\n  reference: string;\n  amount: number;\n  currency: string;\n  asset: string;\n  env: 'live' | 'test';\n  network?: string;\n  aggregator?: string;\n  routing?: 'direct' | 'callback' | 'role';\n}\n\n/**\n * Normalized control block for comparison.\n */\nexport interface NormalizedControl {\n  chain: NormalizedControlStep[];\n}\n\n/**\n * Normalized control step for comparison.\n */\nexport interface NormalizedControlStep {\n  engine: string;\n  result: string;\n}\n\n/**\n * Normalize a payment evidence object.\n *\n * Extracts only the semantic fields, omitting rail-specific evidence\n * and optional fields that are undefined.\n */\nfunction normalizePayment(payment: PaymentEvidence): NormalizedPayment {\n  const result: NormalizedPayment = {\n    rail: payment.rail,\n    reference: payment.reference,\n    amount: payment.amount,\n    currency: payment.currency,\n    asset: payment.asset,\n    env: payment.env,\n  };\n\n  // Only include optional fields if defined\n  if (payment.network !== undefined) {\n    result.network = payment.network;\n  }\n  if (payment.aggregator !== undefined) {\n    result.aggregator = payment.aggregator;\n  }\n  if (payment.routing !== undefined) {\n    result.routing = payment.routing;\n  }\n\n  return result;\n}\n\n/**\n * Normalize a control step.\n */\nfunction normalizeControlStep(step: ControlStep): NormalizedControlStep {\n  return {\n    engine: step.engine,\n    result: step.result,\n  };\n}\n\n/**\n * Normalize a control block.\n */\nfunction normalizeControl(control: ControlBlock): NormalizedControl {\n  return {\n    chain: control.chain.map(normalizeControlStep),\n  };\n}\n\n/**\n * Extract core claims from a receipt for comparison.\n *\n * Supports both commerce and attestation receipts. Accepts either a\n * ParseSuccess result from parseReceiptClaims() (preferred) or bare\n * PEACReceiptClaims (backward compat).\n *\n * For attestation receipts, maps sub -> subject.uri (normative mapping\n * per PEAC attestation profile -- sub is a URI identifying the\n * interaction target).\n *\n * The output:\n * - Contains only semantically meaningful fields\n * - Omits undefined optional fields (not null, not empty string)\n * - Uses consistent field ordering (JCS handles this)\n * - Strips rail-specific evidence details\n *\n * @param input - Parsed receipt result or bare commerce claims\n * @returns Normalized core claims\n *\n * @example\n * ```ts\n * import { parseReceiptClaims, toCoreClaims } from '@peac/schema';\n *\n * const parsed = parseReceiptClaims(decodedPayload);\n * if (parsed.ok) {\n *   const core = toCoreClaims(parsed);\n * }\n * ```\n */\nexport function toCoreClaims(parsed: ParseSuccess): CoreClaims;\nexport function toCoreClaims(claims: PEACReceiptClaims): CoreClaims;\nexport function toCoreClaims(input: ParseSuccess | PEACReceiptClaims): CoreClaims {\n  // Detect ParseSuccess shape\n  if ('ok' in input && input.ok === true && 'variant' in input) {\n    const parsed = input as ParseSuccess;\n    if (parsed.variant === 'commerce') {\n      return commerceCoreClaims(parsed.claims as PEACReceiptClaims);\n    }\n    return attestationCoreClaims(parsed.claims as AttestationReceiptClaims);\n  }\n  // Legacy: bare PEACReceiptClaims (backward compat)\n  return commerceCoreClaims(input as PEACReceiptClaims);\n}\n\nfunction commerceCoreClaims(claims: PEACReceiptClaims): CoreClaims {\n  const result: CoreClaims = {\n    iss: claims.iss,\n    aud: claims.aud,\n    rid: claims.rid,\n    iat: claims.iat,\n    ...(claims.amt !== undefined && { amt: claims.amt }),\n    ...(claims.cur !== undefined && { cur: claims.cur }),\n    ...(claims.payment !== undefined && { payment: normalizePayment(claims.payment) }),\n  };\n\n  if (claims.exp !== undefined) {\n    result.exp = claims.exp;\n  }\n\n  if (claims.subject !== undefined) {\n    result.subject = { uri: claims.subject.uri };\n  }\n\n  if (claims.ext?.control !== undefined) {\n    result.control = normalizeControl(claims.ext.control);\n  }\n\n  return result;\n}\n\nfunction attestationCoreClaims(claims: AttestationReceiptClaims): CoreClaims {\n  const result: CoreClaims = {\n    iss: claims.iss,\n    aud: claims.aud,\n    rid: claims.rid,\n    iat: claims.iat,\n  };\n\n  if (claims.exp !== undefined) {\n    result.exp = claims.exp;\n  }\n\n  // sub -> subject.uri mapping: attestation profile uses sub (string)\n  // as the interaction target URI, equivalent to commerce subject.uri\n  if (claims.sub !== undefined) {\n    result.subject = { uri: claims.sub };\n  }\n\n  return result;\n}\n"]}