{"version":3,"file":"OAuthClient.mjs","names":["OAuthClient","repo: OpenBadgesOAuthRepository","tokens: OpenBadgesTokenRepository"],"sources":["../../src/services/OAuthClient.ts"],"sourcesContent":["import type { AgentContext } from '@credo-ts/core'\nimport { injectable, inject } from '@credo-ts/core'\nimport { OpenBadgesOAuthRepository } from '../repository/OpenBadgesOAuthRepository'\nimport { OpenBadgesTokenRepository } from '../repository/OpenBadgesTokenRepository'\nimport { OpenBadgesTokenRecord } from '../repository/OpenBadgesTokenRecord'\n\n@injectable()\nexport class OAuthClient {\n  public constructor(\n    @inject(OpenBadgesOAuthRepository) private readonly repo: OpenBadgesOAuthRepository,\n    @inject(OpenBadgesTokenRepository) private readonly tokens: OpenBadgesTokenRepository\n  ) {}\n\n  public async registerClient(agentContext: AgentContext, registrationUrl: string, body: Record<string, unknown>) {\n    const res = await fetch(registrationUrl, {\n      method: 'POST',\n      headers: { 'content-type': 'application/json' },\n      body: JSON.stringify(body),\n    })\n    if (!res.ok) throw new Error(`registration_failed: ${res.status}`)\n    const reg = await res.json()\n    const host = new URL(registrationUrl).origin\n    const rec = new (require('../repository/OpenBadgesOAuthRecord').OpenBadgesOAuthRecord)({ host, clientRegistration: reg })\n    await this.repo.save(agentContext, rec)\n    return reg\n  }\n\n  public buildAuthorizationUrl(_authorizationUrl: string, _params: Record<string, string>) {\n    const url = new URL(_authorizationUrl)\n    for (const [k, v] of Object.entries(_params)) url.searchParams.set(k, v)\n    return url.toString()\n  }\n\n  public async completeAuthorizationCode(agentContext: AgentContext, tokenUrl: string, params: Record<string, string> & { host?: string }) {\n    const { client_id, client_secret, host, ...rest } = params\n    const basic = Buffer.from(`${client_id}:${client_secret}`).toString('base64')\n    const res = await fetch(tokenUrl, {\n      method: 'POST',\n      headers: { 'content-type': 'application/x-www-form-urlencoded', authorization: `Basic ${basic}` },\n      body: new URLSearchParams({ grant_type: 'authorization_code', ...rest }).toString(),\n    })\n    if (!res.ok) throw new Error(`token_failed: ${res.status}`)\n    const json = (await res.json()) as {\n      access_token: string\n      refresh_token?: string\n      scope?: string\n      expires_in?: number\n    }\n    const pairId = Math.random().toString(36).slice(2)\n    await this.tokens.save(\n      agentContext as any,\n      new OpenBadgesTokenRecord({\n        token: json.access_token,\n        tokenType: 'access',\n        clientId: client_id,\n        subject: 'unknown',\n        scope: json.scope,\n        expiresAt: new Date(Date.now() + (json.expires_in ?? 180) * 1000),\n        pairId,\n        host,\n      })\n    )\n    if (json.refresh_token) {\n      await this.tokens.save(\n        agentContext as any,\n        new OpenBadgesTokenRecord({\n          token: json.refresh_token,\n          tokenType: 'refresh',\n          clientId: client_id,\n          subject: 'unknown',\n          scope: json.scope,\n          expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),\n          pairId,\n          host,\n        })\n      )\n    }\n    return json\n  }\n\n  public async getAccessToken(agentContext: AgentContext, tokenUrl: string, params: Record<string, string> & { host?: string }) {\n    const { client_id, client_secret, refresh_token, scope, host } = params\n    const basic = Buffer.from(`${client_id}:${client_secret}`).toString('base64')\n    const res = await fetch(tokenUrl, {\n      method: 'POST',\n      headers: { 'content-type': 'application/x-www-form-urlencoded', authorization: `Basic ${basic}` },\n      body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token, scope: scope ?? '' }).toString(),\n    })\n    if (!res.ok) throw new Error(`token_failed: ${res.status}`)\n    const json = (await res.json()) as {\n      access_token: string\n      refresh_token?: string\n      scope?: string\n      expires_in?: number\n    }\n    // Rotate stored refresh token: delete old, store new; store new access token\n    const pairId = Math.random().toString(36).slice(2)\n    await this.tokens.save(\n      agentContext as any,\n      new OpenBadgesTokenRecord({\n        token: json.access_token,\n        tokenType: 'access',\n        clientId: client_id,\n        subject: 'unknown',\n        scope: json.scope,\n        expiresAt: new Date(Date.now() + (json.expires_in ?? 180) * 1000),\n        pairId,\n        host,\n      })\n    )\n    if (json.refresh_token) {\n      await this.tokens.save(\n        agentContext as any,\n        new OpenBadgesTokenRecord({\n          token: json.refresh_token,\n          tokenType: 'refresh',\n          clientId: client_id,\n          subject: 'unknown',\n          scope: json.scope,\n          expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),\n          pairId,\n          host,\n        })\n      )\n    }\n    return json\n  }\n}\n"],"mappings":"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"}