{"version":3,"file":"leak.mjs","names":[],"sources":["../src/leak.ts"],"sourcesContent":["import type { AnyEnvDefinition } from \"./types\";\n\ntype LeakReport = {\n  key: string;\n  chunk: string;\n};\n\ntype BundleChunk = {\n  type: string;\n  code?: string;\n  moduleIds?: string[];\n};\n\nconst NODE_MODULES_RE = /[\\\\/]node_modules[\\\\/]/;\n\nfunction isVendorChunk(chunk: BundleChunk): boolean {\n  const ids = chunk.moduleIds ?? [];\n  return ids.length > 0 && ids.every((id) => NODE_MODULES_RE.test(id));\n}\n\n/**\n * Scans client-destined chunks for server-only var values appearing as quoted\n * string literals. Bare substring matches are ignored — only quoted literals\n * indicate a real bundler-inlined leak. Values < 8 chars are skipped.\n * Pure vendor chunks (all modules from node_modules) are excluded to avoid\n * false positives from libraries that happen to contain the same string values.\n */\nexport function detectServerLeak(\n  def: AnyEnvDefinition,\n  data: Record<string, unknown>,\n  bundle: Record<string, BundleChunk>,\n  onSkipped?: (keys: string[]) => void,\n): LeakReport[] {\n  const serverKeys = new Set(Object.keys(def.server ?? {}));\n\n  const shortSecrets = Object.entries(data).filter(\n    (entry): entry is [string, string] =>\n      serverKeys.has(entry[0]) && typeof entry[1] === \"string\" && entry[1].length < 8,\n  );\n\n  if (shortSecrets.length > 0 && onSkipped) {\n    onSkipped(shortSecrets.map(([k]) => k));\n  }\n\n  const serverSecrets = Object.entries(data).filter(\n    (entry): entry is [string, string] =>\n      serverKeys.has(entry[0]) && typeof entry[1] === \"string\" && entry[1].length >= 8,\n  );\n\n  const chunks = Object.entries(bundle).filter(\n    ([, chunk]) => chunk.type === \"chunk\" && !!chunk.code && !isVendorChunk(chunk),\n  );\n\n  const leaks: LeakReport[] = [];\n  for (const [key, value] of serverSecrets) {\n    const escaped = value.replace(/[.*+?^${}()|[\\]\\\\]/g, String.raw`\\$&`);\n    const pattern = new RegExp(`([\"'\\`])${escaped}\\\\1`);\n    for (const [chunkName, chunk] of chunks) {\n      if (pattern.test(chunk.code!)) {\n        leaks.push({ key, chunk: chunkName });\n      }\n    }\n  }\n\n  return leaks;\n}\n"],"mappings":";AAaA,MAAM,kBAAkB;AAExB,SAAS,cAAc,OAA6B;CAClD,MAAM,MAAM,MAAM,aAAa,EAAE;AACjC,QAAO,IAAI,SAAS,KAAK,IAAI,OAAO,OAAO,gBAAgB,KAAK,GAAG,CAAC;;;;;;;;;AAUtE,SAAgB,iBACd,KACA,MACA,QACA,WACc;CACd,MAAM,aAAa,IAAI,IAAI,OAAO,KAAK,IAAI,UAAU,EAAE,CAAC,CAAC;CAEzD,MAAM,eAAe,OAAO,QAAQ,KAAK,CAAC,QACvC,UACC,WAAW,IAAI,MAAM,GAAG,IAAI,OAAO,MAAM,OAAO,YAAY,MAAM,GAAG,SAAS,EACjF;AAED,KAAI,aAAa,SAAS,KAAK,UAC7B,WAAU,aAAa,KAAK,CAAC,OAAO,EAAE,CAAC;CAGzC,MAAM,gBAAgB,OAAO,QAAQ,KAAK,CAAC,QACxC,UACC,WAAW,IAAI,MAAM,GAAG,IAAI,OAAO,MAAM,OAAO,YAAY,MAAM,GAAG,UAAU,EAClF;CAED,MAAM,SAAS,OAAO,QAAQ,OAAO,CAAC,QACnC,GAAG,WAAW,MAAM,SAAS,WAAW,CAAC,CAAC,MAAM,QAAQ,CAAC,cAAc,MAAM,CAC/E;CAED,MAAM,QAAsB,EAAE;AAC9B,MAAK,MAAM,CAAC,KAAK,UAAU,eAAe;EACxC,MAAM,UAAU,MAAM,QAAQ,uBAAuB,OAAO,GAAG,MAAM;EACrE,MAAM,UAAU,IAAI,OAAO,WAAW,QAAQ,KAAK;AACnD,OAAK,MAAM,CAAC,WAAW,UAAU,OAC/B,KAAI,QAAQ,KAAK,MAAM,KAAM,CAC3B,OAAM,KAAK;GAAE;GAAK,OAAO;GAAW,CAAC;;AAK3C,QAAO"}