{"version":3,"sources":["../src/core/errors.ts","../src/core/oauth.ts"],"sourcesContent":["export class RevKeenError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"RevKeenError\";\n  }\n}\n\nexport class RevKeenAPIError extends RevKeenError {\n  constructor(\n    public readonly status: number,\n    message: string,\n    public readonly body: unknown,\n  ) {\n    super(message);\n    this.name = \"RevKeenAPIError\";\n  }\n}\n\nexport class RevKeenTimeoutError extends RevKeenError {\n  constructor(message: string) {\n    super(message);\n    this.name = \"RevKeenTimeoutError\";\n  }\n}\n","import { RevKeenError } from \"./errors.js\";\n\nexport interface OAuthConfig {\n  clientId: string;\n  clientSecret: string;\n  tokenEndpoint?: string;\n  scopes?: string[];\n}\n\ninterface TokenResponse {\n  access_token: string;\n  token_type: string;\n  expires_in: number;\n  refresh_token?: string;\n  scope?: string;\n}\n\ninterface CachedToken {\n  accessToken: string;\n  refreshToken?: string;\n  expiresAt: number;\n}\n\nconst DEFAULT_TOKEN_ENDPOINT = \"https://api.revkeen.com/api/auth/oauth2/token\";\nconst PRE_EXPIRY_BUFFER_MS = 60_000; // Refresh 60s before expiry\n\nexport class OAuthTokenManager {\n  private config: Required<Pick<OAuthConfig, \"clientId\" | \"clientSecret\" | \"tokenEndpoint\">> &\n    Pick<OAuthConfig, \"scopes\">;\n  private cachedToken: CachedToken | null = null;\n  private inflightRequest: Promise<string> | null = null;\n\n  constructor(config: OAuthConfig) {\n    this.config = {\n      clientId: config.clientId,\n      clientSecret: config.clientSecret,\n      tokenEndpoint: config.tokenEndpoint || DEFAULT_TOKEN_ENDPOINT,\n      scopes: config.scopes,\n    };\n  }\n\n  async getToken(): Promise<string> {\n    // Return cached token if still valid\n    if (this.cachedToken && Date.now() < this.cachedToken.expiresAt - PRE_EXPIRY_BUFFER_MS) {\n      return this.cachedToken.accessToken;\n    }\n\n    // Deduplicate concurrent requests\n    if (this.inflightRequest) {\n      return this.inflightRequest;\n    }\n\n    this.inflightRequest = this.fetchToken();\n    try {\n      return await this.inflightRequest;\n    } finally {\n      this.inflightRequest = null;\n    }\n  }\n\n  private async fetchToken(): Promise<string> {\n    // Try refresh token first if available\n    if (this.cachedToken?.refreshToken) {\n      try {\n        return await this.requestToken(\"refresh_token\");\n      } catch {\n        // Fall back to client_credentials\n      }\n    }\n\n    return await this.requestToken(\"client_credentials\");\n  }\n\n  private async requestToken(grantType: \"client_credentials\" | \"refresh_token\"): Promise<string> {\n    const body = new URLSearchParams();\n    body.set(\"grant_type\", grantType);\n\n    if (grantType === \"client_credentials\") {\n      body.set(\"client_id\", this.config.clientId);\n      body.set(\"client_secret\", this.config.clientSecret);\n      if (this.config.scopes?.length) {\n        body.set(\"scope\", this.config.scopes.join(\" \"));\n      }\n    } else if (grantType === \"refresh_token\" && this.cachedToken?.refreshToken) {\n      body.set(\"refresh_token\", this.cachedToken.refreshToken);\n      body.set(\"client_id\", this.config.clientId);\n      body.set(\"client_secret\", this.config.clientSecret);\n    }\n\n    const res = await fetch(this.config.tokenEndpoint, {\n      method: \"POST\",\n      headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n      body: body.toString(),\n    });\n\n    if (!res.ok) {\n      const errorBody = await res.text().catch(() => \"\");\n      throw new RevKeenError(\n        `OAuth token request failed (${res.status}): ${errorBody || res.statusText}`\n      );\n    }\n\n    const data = (await res.json()) as TokenResponse;\n\n    this.cachedToken = {\n      accessToken: data.access_token,\n      refreshToken: data.refresh_token ?? this.cachedToken?.refreshToken,\n      expiresAt: Date.now() + data.expires_in * 1000,\n    };\n\n    return data.access_token;\n  }\n}\n"],"mappings":";AAAO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,kBAAN,cAA8B,aAAa;AAAA,EAChD,YACkB,QAChB,SACgB,MAChB;AACA,UAAM,OAAO;AAJG;AAEA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,sBAAN,cAAkC,aAAa;AAAA,EACpD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;;;ACAA,IAAM,yBAAyB;AAC/B,IAAM,uBAAuB;AAEtB,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EAEA,cAAkC;AAAA,EAClC,kBAA0C;AAAA,EAElD,YAAY,QAAqB;AAC/B,SAAK,SAAS;AAAA,MACZ,UAAU,OAAO;AAAA,MACjB,cAAc,OAAO;AAAA,MACrB,eAAe,OAAO,iBAAiB;AAAA,MACvC,QAAQ,OAAO;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,WAA4B;AAEhC,QAAI,KAAK,eAAe,KAAK,IAAI,IAAI,KAAK,YAAY,YAAY,sBAAsB;AACtF,aAAO,KAAK,YAAY;AAAA,IAC1B;AAGA,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK;AAAA,IACd;AAEA,SAAK,kBAAkB,KAAK,WAAW;AACvC,QAAI;AACF,aAAO,MAAM,KAAK;AAAA,IACpB,UAAE;AACA,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAc,aAA8B;AAE1C,QAAI,KAAK,aAAa,cAAc;AAClC,UAAI;AACF,eAAO,MAAM,KAAK,aAAa,eAAe;AAAA,MAChD,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,MAAM,KAAK,aAAa,oBAAoB;AAAA,EACrD;AAAA,EAEA,MAAc,aAAa,WAAoE;AAC7F,UAAM,OAAO,IAAI,gBAAgB;AACjC,SAAK,IAAI,cAAc,SAAS;AAEhC,QAAI,cAAc,sBAAsB;AACtC,WAAK,IAAI,aAAa,KAAK,OAAO,QAAQ;AAC1C,WAAK,IAAI,iBAAiB,KAAK,OAAO,YAAY;AAClD,UAAI,KAAK,OAAO,QAAQ,QAAQ;AAC9B,aAAK,IAAI,SAAS,KAAK,OAAO,OAAO,KAAK,GAAG,CAAC;AAAA,MAChD;AAAA,IACF,WAAW,cAAc,mBAAmB,KAAK,aAAa,cAAc;AAC1E,WAAK,IAAI,iBAAiB,KAAK,YAAY,YAAY;AACvD,WAAK,IAAI,aAAa,KAAK,OAAO,QAAQ;AAC1C,WAAK,IAAI,iBAAiB,KAAK,OAAO,YAAY;AAAA,IACpD;AAEA,UAAM,MAAM,MAAM,MAAM,KAAK,OAAO,eAAe;AAAA,MACjD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oCAAoC;AAAA,MAC/D,MAAM,KAAK,SAAS;AAAA,IACtB,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,YAAY,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,YAAM,IAAI;AAAA,QACR,+BAA+B,IAAI,MAAM,MAAM,aAAa,IAAI,UAAU;AAAA,MAC5E;AAAA,IACF;AAEA,UAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,SAAK,cAAc;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,cAAc,KAAK,iBAAiB,KAAK,aAAa;AAAA,MACtD,WAAW,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA,IAC5C;AAEA,WAAO,KAAK;AAAA,EACd;AACF;","names":[]}