{"version":3,"sources":["../../src/integrations/api-keys.ts","../../src/resolvers/api-key-subject.resolver.ts"],"sourcesContent":["import type { ExecutionContext } from '@nestjs/common';\nimport type { RbacSubject, RbacSubjectResolver } from '../interfaces';\nimport { resolveApiKeySubject } from '../resolvers/api-key-subject.resolver';\n\nexport function createApiKeySubjectResolver(): RbacSubjectResolver {\n  return (context: ExecutionContext): RbacSubject | undefined => {\n    const request = context.switchToHttp().getRequest<Record<string, unknown>>();\n    return resolveApiKeySubject(request);\n  };\n}\n","import type { RbacSubject } from '../interfaces/subject';\n\ntype HttpRequest = Record<string, unknown>;\ntype ApiKeyRecord = Record<string, unknown>;\n\ntype ParsedApiKey = {\n  id: string;\n  tenantId?: string;\n  attributes: ApiKeyRecord;\n};\n\nconst isRecord = (value: unknown): value is ApiKeyRecord =>\n  typeof value === 'object' && value !== null;\n\nconst isOpaqueIdentifier = (value: unknown): value is string =>\n  typeof value === 'string' && value.length > 0;\n\nconst parseApiKey = (value: unknown): ParsedApiKey | undefined => {\n  if (!isRecord(value)) return undefined;\n\n  const hasKeyId = value.keyId !== undefined;\n  const hasLegacyId = value.id !== undefined;\n  const hasTenantId = value.tenantId !== undefined;\n\n  if (\n    (hasKeyId && !isOpaqueIdentifier(value.keyId)) ||\n    (hasLegacyId && !isOpaqueIdentifier(value.id)) ||\n    (hasTenantId && !isOpaqueIdentifier(value.tenantId))\n  ) {\n    return undefined;\n  }\n\n  const keyId = isOpaqueIdentifier(value.keyId) ? value.keyId : undefined;\n  const legacyId = isOpaqueIdentifier(value.id) ? value.id : undefined;\n  const id = keyId ?? legacyId;\n  if (id === undefined) return undefined;\n\n  const tenantId = isOpaqueIdentifier(value.tenantId) ? value.tenantId : undefined;\n\n  return {\n    id,\n    ...(tenantId !== undefined ? { tenantId } : {}),\n    attributes: value,\n  };\n};\n\nconst toSubject = (apiKey: ParsedApiKey): RbacSubject => ({\n  type: 'api_key',\n  id: apiKey.id,\n  ...(apiKey.tenantId !== undefined ? { tenantId: apiKey.tenantId } : {}),\n  attributes: apiKey.attributes,\n});\n\nexport const resolveApiKeySubject = (request: HttpRequest): RbacSubject | undefined => {\n  const canonicalValue = request.apiKey;\n  const legacyValue = request.apiKeyContext;\n  const hasCanonical = canonicalValue !== undefined && canonicalValue !== null;\n  const hasLegacy = legacyValue !== undefined && legacyValue !== null;\n\n  if (hasCanonical) {\n    const canonical = parseApiKey(canonicalValue);\n    if (canonical === undefined) return undefined;\n\n    if (hasLegacy) {\n      const legacy = parseApiKey(legacyValue);\n      if (\n        legacy === undefined ||\n        legacy.id !== canonical.id ||\n        legacy.tenantId !== canonical.tenantId\n      ) {\n        return undefined;\n      }\n    }\n\n    return toSubject(canonical);\n  }\n\n  if (!hasLegacy) return undefined;\n\n  const legacy = parseApiKey(legacyValue);\n  return legacy === undefined ? undefined : toSubject(legacy);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAEA;;;;;;;ACSA,IAAMA,WAAW,wBAACC,UAChB,OAAOA,UAAU,YAAYA,UAAU,MADxB;AAGjB,IAAMC,qBAAqB,wBAACD,UAC1B,OAAOA,UAAU,YAAYA,MAAME,SAAS,GADnB;AAG3B,IAAMC,cAAc,wBAACH,UAAAA;AACnB,MAAI,CAACD,SAASC,KAAAA,EAAQ,QAAOI;AAE7B,QAAMC,WAAWL,MAAMM,UAAUF;AACjC,QAAMG,cAAcP,MAAMQ,OAAOJ;AACjC,QAAMK,cAAcT,MAAMU,aAAaN;AAEvC,MACGC,YAAY,CAACJ,mBAAmBD,MAAMM,KAAK,KAC3CC,eAAe,CAACN,mBAAmBD,MAAMQ,EAAE,KAC3CC,eAAe,CAACR,mBAAmBD,MAAMU,QAAQ,GAClD;AACA,WAAON;EACT;AAEA,QAAME,QAAQL,mBAAmBD,MAAMM,KAAK,IAAIN,MAAMM,QAAQF;AAC9D,QAAMO,WAAWV,mBAAmBD,MAAMQ,EAAE,IAAIR,MAAMQ,KAAKJ;AAC3D,QAAMI,KAAKF,SAASK;AACpB,MAAIH,OAAOJ,OAAW,QAAOA;AAE7B,QAAMM,WAAWT,mBAAmBD,MAAMU,QAAQ,IAAIV,MAAMU,WAAWN;AAEvE,SAAO;IACLI;IACA,GAAIE,aAAaN,SAAY;MAAEM;IAAS,IAAI,CAAC;IAC7CE,YAAYZ;EACd;AACF,GA3BoB;AA6BpB,IAAMa,YAAY,wBAACC,YAAuC;EACxDC,MAAM;EACNP,IAAIM,OAAON;EACX,GAAIM,OAAOJ,aAAaN,SAAY;IAAEM,UAAUI,OAAOJ;EAAS,IAAI,CAAC;EACrEE,YAAYE,OAAOF;AACrB,IALkB;AAOX,IAAMI,uBAAuB,wBAACC,YAAAA;AACnC,QAAMC,iBAAiBD,QAAQH;AAC/B,QAAMK,cAAcF,QAAQG;AAC5B,QAAMC,eAAeH,mBAAmBd,UAAac,mBAAmB;AACxE,QAAMI,YAAYH,gBAAgBf,UAAae,gBAAgB;AAE/D,MAAIE,cAAc;AAChB,UAAME,YAAYpB,YAAYe,cAAAA;AAC9B,QAAIK,cAAcnB,OAAW,QAAOA;AAEpC,QAAIkB,WAAW;AACb,YAAME,UAASrB,YAAYgB,WAAAA;AAC3B,UACEK,YAAWpB,UACXoB,QAAOhB,OAAOe,UAAUf,MACxBgB,QAAOd,aAAaa,UAAUb,UAC9B;AACA,eAAON;MACT;IACF;AAEA,WAAOS,UAAUU,SAAAA;EACnB;AAEA,MAAI,CAACD,UAAW,QAAOlB;AAEvB,QAAMoB,SAASrB,YAAYgB,WAAAA;AAC3B,SAAOK,WAAWpB,SAAYA,SAAYS,UAAUW,MAAAA;AACtD,GA5BoC;;;ADjD7B,SAASC,8BAAAA;AACd,SAAO,CAACC,YAAAA;AACN,UAAMC,UAAUD,QAAQE,aAAY,EAAGC,WAAU;AACjD,WAAOC,qBAAqBH,OAAAA;EAC9B;AACF;AALgBF;","names":["isRecord","value","isOpaqueIdentifier","length","parseApiKey","undefined","hasKeyId","keyId","hasLegacyId","id","hasTenantId","tenantId","legacyId","attributes","toSubject","apiKey","type","resolveApiKeySubject","request","canonicalValue","legacyValue","apiKeyContext","hasCanonical","hasLegacy","canonical","legacy","createApiKeySubjectResolver","context","request","switchToHttp","getRequest","resolveApiKeySubject"]}