import {v4 as createUuid} from 'uuid' import { Book } from './book' interface ClientOptions { clientId: string clientSecret: string redirectUrl: string } interface GetTokenResponse { access_token: string } export class Client { clientId: string clientSecret: string redirectUrl: string accessToken: string private state: string endpoint = 'https://reflect.app' authPath = '/oauth' tokenPath = '/api/oauth/token' booksPath = '/api/books' syncBooksPath = '/api/books/sync' notesPath = '/api/notes' backlinksPath = '/api/backlinks' constructor ({clientId, clientSecret, redirectUrl}: ClientOptions) { this.clientId = clientId this.clientSecret = clientSecret this.redirectUrl = redirectUrl } private generateState () { return this.state = createUuid() } generateAuthUrl () { const url = new URL(this.endpoint + this.authPath) url.searchParams.append('client_id', this.clientId) url.searchParams.append('state', this.generateState()) url.searchParams.append('redirect_uri', this.redirectUrl) return url.href } setToken (value: string) { this.accessToken = value } async getToken (code: string):Promise { const {access_token} = await this.jsonPost(this.endpoint + this.tokenPath, { client_id: this.clientId, client_secret: this.clientSecret, code, }) this.accessToken = access_token return access_token } createBook (attrs) { return this.jsonPost( this.endpoint + this.booksPath, attrs ) } syncBooks (books: Book[]) { return this.jsonPost( this.endpoint + this.syncBooksPath, {books: books} ) } createNote (attrs) { return this.jsonPost( this.endpoint + this.notesPath, attrs ) } getNotes () { return this.jsonGet( this.endpoint + this.notesPath ) } getBacklinks () { return this.jsonGet( this.endpoint + this.backlinksPath ) } private async jsonGet (url: string) { const result = await this.fetchWithAuth(url, { method: 'GET', }) return result.json() } private async jsonPost (url: string, params = {}) { const headers = { 'Content-Type': 'application/json; charset=utf-8', } const result = await this.fetchWithAuth(url, { method: 'POST', headers, body: JSON.stringify(params) }) return result.json() } private fetchWithAuth (url: string, init?: RequestInit) { const headers = init?.headers || {} if (this.accessToken) { Object.assign(headers, { 'Authorization': `Bearer ${this.accessToken}` }) } return fetch(url, { ...(init || {}), headers }) } }