{"version":3,"file":"ConsumerService.mjs","names":["ConsumerService","sddRepo: OpenBadgesServiceDescriptionRepository","oauthRepo: OpenBadgesOAuthRepository","oauth: OAuthClient"],"sources":["../../src/services/ConsumerService.ts"],"sourcesContent":["import type { AgentContext } from '@credo-ts/core'\nimport { injectable, inject } from '@credo-ts/core'\nimport { OpenBadgesServiceDescriptionRepository } from '../repository/OpenBadgesServiceDescriptionRepository'\nimport { OpenBadgesOAuthRepository } from '../repository/OpenBadgesOAuthRepository'\nimport { OAuthClient } from './OAuthClient'\n\n@injectable()\nexport class ConsumerService {\n  public constructor(\n    @inject(OpenBadgesServiceDescriptionRepository) private readonly sddRepo: OpenBadgesServiceDescriptionRepository,\n    @inject(OpenBadgesOAuthRepository) private readonly oauthRepo: OpenBadgesOAuthRepository,\n    @inject(OAuthClient) private readonly oauth: OAuthClient\n  ) {}\n\n  public async importFromUrl(agentContext: AgentContext, url: string, options?: { discoveryUrl?: string }) {\n    const discoveryUrl = options?.discoveryUrl ?? new URL('/ims/ob/v3p0/discovery', url).toString()\n    const sdd = await this.ensureServiceDescription(agentContext, discoveryUrl)\n    const regUrl = sdd?.components?.securitySchemes?.OAuth2ACG?.['x-imssf-registrationUrl'] as string\n    const authUrl = sdd?.components?.securitySchemes?.OAuth2ACG?.flows?.authorizationCode?.authorizationUrl as string\n    if (!regUrl || !authUrl) throw new Error('discovery_incomplete')\n    const registration = await this.oauth.registerClient(agentContext, regUrl, {\n      client_name: 'Credo OB Client',\n      redirect_uris: ['http://localhost/callback'],\n      scope: Object.keys(\n        (sdd.components?.securitySchemes?.OAuth2ACG?.flows?.authorizationCode?.scopes as Record<string, string>) ?? {}\n      ).join(' '),\n      grant_types: ['authorization_code', 'refresh_token'],\n      response_types: ['code'],\n      application_type: 'web',\n    }) as { client_id: string; redirect_uris?: string[]; scope?: string }\n    const authorizationUrl = this.oauth.buildAuthorizationUrl(authUrl, {\n      response_type: 'code',\n      client_id: registration.client_id,\n      redirect_uri: registration.redirect_uris?.[0] ?? '',\n      scope: registration.scope ?? '',\n      state: Math.random().toString(36).slice(2),\n      code_challenge_method: 'S256',\n      code_challenge: Math.random().toString(36).slice(2),\n    })\n    return { discovery: sdd, registration, authorizationUrl, host: new URL(url).origin }\n  }\n\n  public async ensureServiceDescription(agentContext: AgentContext, discoveryUrl: string) {\n    try {\n      const existing = await this.sddRepo.findByDiscoveryUrl(agentContext as any, discoveryUrl)\n      if (existing) return existing.serviceDescription as any\n    } catch {}\n    const res = await fetch(discoveryUrl)\n    if (!res.ok) throw new Error(`discovery_failed: ${res.status}`)\n    const json = await res.json()\n    await this.sddRepo.save(agentContext as any, {\n      discoveryUrl,\n      serviceDescription: json,\n    } as any)\n    return json\n  }\n\n  public async upsertToRemote(agentContext: AgentContext, baseUrl: string, credential: unknown) {\n    const host = new URL(baseUrl).origin\n    const oauth = await this.oauthRepo.findByHost(agentContext as any, host)\n    if (!oauth?.[0]?.clientRegistration) throw new Error('no_client_registration')\n    const reg = oauth[0].clientRegistration as any\n    const tokenUrl = reg?.token_endpoint || reg?.tokenUrl || new URL('/token', baseUrl).toString()\n    const clientId = reg.client_id\n    const clientSecret = reg.client_secret\n    if (!clientId || !clientSecret) throw new Error('missing_client_credentials')\n\n    // Try to get a valid access token from token repository\n    const { OpenBadgesTokenRepository } = await import('../repository/OpenBadgesTokenRepository')\n    const tokens = agentContext.dependencyManager.resolve(OpenBadgesTokenRepository)\n    let access = await tokens.findValidAccessByClientHost(agentContext as any, clientId, host)\n    if (!access) {\n      // refresh\n      const refresh = await tokens.findRefreshByClientHost(agentContext as any, clientId, host)\n      if (!refresh) throw new Error('no_refresh_token')\n      const refreshed = await this.oauth.getAccessToken(agentContext, tokenUrl, {\n        client_id: clientId,\n        client_secret: clientSecret,\n        refresh_token: refresh.token,\n        host,\n      })\n      access = await tokens.findValidAccessByClientHost(agentContext as any, clientId, host)\n      if (!access) throw new Error('refresh_failed')\n    }\n\n    const url = new URL('/ims/ob/v3p0/credentials', baseUrl).toString()\n    const res = await fetch(url, {\n      method: 'POST',\n      headers: { authorization: `Bearer ${access.token}`, 'content-type': 'application/json' },\n      body: JSON.stringify(credential),\n    })\n    if (!res.ok) throw new Error(`upsert_failed: ${res.status}`)\n    return res.json()\n  }\n}\n"],"mappings":"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"}