{"version":3,"sources":["../src/transformer.ts"],"sourcesContent":["import type { Mapping, Transformer } from '@walkeros/core';\nimport { getMappingValue, setByPath } from '@walkeros/core';\nimport { getHashServer } from '@walkeros/server-core';\nimport type { FingerprintSettings } from './types';\n\n/**\n * Fingerprint transformer - hash configurable fields for session continuity.\n *\n * Resolves fields from { event, ingest } source object using getMappingValue,\n * concatenates values in order, hashes with SHA-256, and stores at output path.\n *\n * @example\n * transformerFingerprint({\n *   config: {\n *     settings: {\n *       fields: [\n *         'ingest.ip',\n *         'ingest.userAgent',\n *         { fn: () => new Date().getDate() },\n *       ],\n *       output: 'user.hash',\n *       length: 16,\n *     },\n *   },\n * })\n */\nexport const transformerFingerprint: Transformer.Init<\n  Transformer.Types<FingerprintSettings>\n> = (context) => {\n  const { config } = context;\n  const settings: Partial<FingerprintSettings> = config.settings ?? {};\n  const fields: Mapping.Value[] = settings.fields || [];\n  const output: string = settings.output || 'user.hash';\n  const length: number | undefined = settings.length;\n\n  return {\n    type: 'fingerprint',\n    config: config as Transformer.Config<\n      Transformer.Types<FingerprintSettings>\n    >,\n\n    async push(event, context) {\n      const { ingest, collector } = context;\n\n      // Build source object for field resolution\n      const source = { event, ingest };\n\n      // Resolve each field via mapping (maintains order)\n      const values = await Promise.all(\n        fields.map((field: Mapping.Value) =>\n          getMappingValue(source, field, { collector }),\n        ),\n      );\n\n      // Safe string concatenation: '' prefix + String() cast for each value\n      // '' prefix ensures we always have a string even if fields is empty\n      // String(v ?? '') handles undefined/null gracefully\n      const input = '' + values.map((v: unknown) => String(v ?? '')).join('');\n\n      // Hash and store at output path\n      const hash = await getHashServer(input, length);\n      return { event: setByPath(event, output, hash) };\n    },\n  };\n};\n"],"mappings":";AACA,SAAS,iBAAiB,iBAAiB;AAC3C,SAAS,qBAAqB;AAwBvB,IAAM,yBAET,CAAC,YAAY;AACf,QAAM,EAAE,OAAO,IAAI;AACnB,QAAM,WAAyC,OAAO,YAAY,CAAC;AACnE,QAAM,SAA0B,SAAS,UAAU,CAAC;AACpD,QAAM,SAAiB,SAAS,UAAU;AAC1C,QAAM,SAA6B,SAAS;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IAIA,MAAM,KAAK,OAAOA,UAAS;AACzB,YAAM,EAAE,QAAQ,UAAU,IAAIA;AAG9B,YAAM,SAAS,EAAE,OAAO,OAAO;AAG/B,YAAM,SAAS,MAAM,QAAQ;AAAA,QAC3B,OAAO;AAAA,UAAI,CAAC,UACV,gBAAgB,QAAQ,OAAO,EAAE,UAAU,CAAC;AAAA,QAC9C;AAAA,MACF;AAKA,YAAM,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAe,OAAO,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE;AAGtE,YAAM,OAAO,MAAM,cAAc,OAAO,MAAM;AAC9C,aAAO,EAAE,OAAO,UAAU,OAAO,QAAQ,IAAI,EAAE;AAAA,IACjD;AAAA,EACF;AACF;","names":["context"]}