/
githubmirror
/
novu
Обзор
Документация
Войти
/
githubmirror
/
novu
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
next
packages/js/src/api/http-client.ts
153 строки
4 KB
Adam Chmara
fix(api-service,js): sync 402 on web chat accept when plan limits block fixes NV-8575 (#12307)
4 часа назад
Не верифицирован
4 часа назад
81982fc
Код
Авторство
О чём код?
export type HttpClientOptions = { apiVersion?: string; apiUrl?: string; headers?: Record<string, string>; }; export const DEFAULT_API_VERSION = 'v1'; const DEFAULT_CLIENT_VERSION = `${PACKAGE_NAME}@${PACKAGE_VERSION}`; export class HttpClient { // Environment variable for local development that overrides the default API endpoint without affecting the Inbox DX private DEFAULT_BACKEND_URL = (typeof window !== 'undefined' && (window as any).NOVU_LOCAL_BACKEND_URL) || 'https://api.novu.co'; private apiUrl: string; private apiVersion: string; private headers: Record<string, string>; constructor(options: HttpClientOptions = {}) { const { apiVersion = DEFAULT_API_VERSION, apiUrl = this.DEFAULT_BACKEND_URL, headers = {} } = options || {}; this.apiVersion = apiVersion; this.apiUrl = `${apiUrl}/${apiVersion}`; this.headers = { 'Novu-API-Version': NOVU_API_VERSION, 'Novu-Client-Version': DEFAULT_CLIENT_VERSION, 'Content-Type': 'application/json', ...headers, }; } setAuthorizationToken(token: string) { this.headers.Authorization = `Bearer ${token}`; } setKeylessHeader(identifier?: string) { const keylessAppIdentifier = identifier || (typeof window !== 'undefined' && window.localStorage?.getItem('novu_keyless_application_identifier')); if (!keylessAppIdentifier || !keylessAppIdentifier.startsWith('pk_keyless_')) { return; } this.headers['Novu-Application-Identifier'] = keylessAppIdentifier; } setHeaders(headers: Record<string, string>) { this.headers = { ...this.headers, ...headers, }; } async get<T>(path: string, searchParams?: URLSearchParams, unwrapEnvelope = true) { return this.doFetch<T>({ path, searchParams, options: { method: 'GET', }, unwrapEnvelope, }); } async post<T>(path: string, body?: any, options?: RequestInit) { return this.doFetch<T>({ path, options: { method: 'POST', body, headers: options?.headers, }, }); } async patch<T>(path: string, body?: any) { return this.doFetch<T>({ path, options: { method: 'PATCH', body, }, }); } async delete<T>(path: string, body?: any) { return this.doFetch<T>({ path, options: { method: 'DELETE', body, }, }); } private async doFetch<T>({ path, searchParams, options, unwrapEnvelope = true, }: { path: string; searchParams?: URLSearchParams; options?: RequestInit; unwrapEnvelope?: boolean; }) { const fullUrl = combineUrl(this.apiUrl, path, searchParams ? `?${searchParams.toString()}` : ''); const reqInit = { method: options?.method || 'GET', headers: { ...this.headers, ...(options?.headers || {}) }, body: options?.body ? JSON.stringify(options.body) : undefined, }; const response = await fetch(fullUrl, reqInit); if (!response.ok) { const errorData = await response.json(); const error = new Error( `${this.headers['Novu-Client-Version']} error. Status: ${response.status}, Message: ${errorData.message}` ) as Error & { status?: number; body?: unknown }; error.status = response.status; error.body = errorData; throw error; } if (response.status === 204) { return undefined as unknown as T; } const res = await response.json(); return (unwrapEnvelope ? res.data : res) as Promise<T>; } } function combineUrl(...args: string[]): string { return ( args .reduce<string[]>((acc, part) => { if (part) { /* * 1. Replace multiple slashes with a single slash unless they are part of a protocol (http:, https:) * 2. Remove leading and trailing slashes */ acc.push(part.replace(/(?<!https?:)\/+/g, '/').replace(/^\/+|\/+$/g, '')); } return acc; }, []) .join('/') // For search params, replace /foo/?bar=42 with /foo?bar=42 .replace(/\/\?/, '?') ); }