import { HTTPException } from 'hono/http-exception' import type { Token } from '../../types' import { toQueryParams } from '../../utils/objectToQuery' import type { FacebookErrorResponse, FacebookMeResponse, FacebookTokenResponse, FacebookUser, Fields, Permissions, } from './types' type FacebookAuthFlow = { client_id: string client_secret: string redirect_uri: string scope: Permissions[] fields: Fields[] state: string code: string | undefined token: Token | undefined } export class AuthFlow { client_id: string client_secret: string redirect_uri: string scope: Permissions[] fields: Fields[] state: string code: string | undefined token: Token | undefined user: Partial | undefined constructor({ client_id, client_secret, redirect_uri, scope, state, fields, code, token, }: FacebookAuthFlow) { this.client_id = client_id this.client_secret = client_secret this.redirect_uri = redirect_uri this.scope = scope this.fields = fields this.state = state this.code = code this.token = token this.user = undefined } redirect() { const parsedOptions = toQueryParams({ client_id: this.client_id, redirect_uri: this.redirect_uri, response_type: ['code', 'granted_scopes'], scope: this.scope, state: this.state, }) return `https://www.facebook.com/v18.0/dialog/oauth?${parsedOptions}` } private async getTokenFromCode() { const parsedOptions = toQueryParams({ client_id: this.client_id, redirect_uri: this.redirect_uri, client_secret: this.client_secret, code: this.code, }) const url = `https://graph.facebook.com/v18.0/oauth/access_token?${parsedOptions}` const response = (await fetch(url).then((res) => res.json())) as | FacebookTokenResponse | FacebookErrorResponse if ('error' in response) { throw new HTTPException(400, { message: response.error?.message }) } if ('access_token' in response) { this.token = { token: response.access_token, expires_in: response.expires_in, } } } private async getUserId() { const response = (await fetch( `https://graph.facebook.com/v18.0/me?access_token=${this.token?.token}` ).then((res) => res.json())) as FacebookMeResponse | FacebookErrorResponse if ('error' in response) { throw new HTTPException(400, { message: response.error?.message }) } if ('id' in response) { this.user = response } } async getUserData() { await this.getTokenFromCode() await this.getUserId() const parsedFields = this.fields.join() const response = (await fetch( `https://graph.facebook.com/${this.user?.id}?fields=${parsedFields}&access_token=${this.token?.token}` ).then((res) => res.json())) as FacebookUser | FacebookErrorResponse if ('error' in response) { throw new HTTPException(400, { message: response.error?.message }) } if ('id' in response) { this.user = response } } }