///
import 'isomorphic-fetch-with-cookie'
import { TeleError } from './error'
import type { Fn, PromiseReturnType, TeleRequest, TeleResponse } from './types'
const JSON_RPC_INVALID_REQUEST = -32600
let memoryStorage: Record = {}
let callId = 0
let tokenIsInHeader = false
export function reset(): void {
memoryStorage = {}
callId = 0
tokenIsInHeader = false
}
export default function telecall(endpoint: string, method: string) {
return async (...params: Parameters): PromiseReturnType => {
nextId()
const request: TeleRequest = {
jsonrpc: '2.0',
method,
params,
id: callId,
}
const rawResponse = await fetch(endpoint, {
method: 'POST',
headers: buildHeadersByPersistedToken(endpoint),
body: JSON.stringify(request),
credentials: 'include',
})
persistTokenFromResponseHeaders(rawResponse.headers, endpoint)
const response = (await rawResponse.json()) as TeleResponse
handleErrors(response, request)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return response.result!
}
}
function nextId() {
callId = callId >= Number.MAX_SAFE_INTEGER ? Number.MIN_SAFE_INTEGER : callId + 1
}
function buildHeadersByPersistedToken(endpoint: string) {
const headers = new Headers({ 'content-type': 'application/json' })
if (tokenIsInHeader) {
const tokenName = getTokenName(endpoint)
const token =
globalThis.localStorage?.getItem(tokenName) ?? memoryStorage[tokenName] ?? ''
headers.set('authorization', token)
}
return headers
}
function persistTokenFromResponseHeaders(headers: Headers, endpoint: string) {
const token = headers.get('authorization')
if (token == null) return
tokenIsInHeader = true
const tokenName = getTokenName(endpoint)
if (globalThis.localStorage) localStorage.setItem(tokenName, token)
else memoryStorage[tokenName] = token
}
function handleErrors(
response: TeleResponse,
request: TeleRequest,
) {
if (response.error) throw new TeleError(response.error)
if (response.jsonrpc !== '2.0' || response.id !== request.id)
throw new TeleError({
code: JSON_RPC_INVALID_REQUEST,
message: 'Invalid Request',
})
}
function getTokenName(endpoint: string) {
return `sessionToken::${endpoint}`
}