UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

1 lines 25.6 kB
{"version":3,"file":"api.cjs","sources":["../../../src/utils/api.ts"],"sourcesContent":["import type {APIError, APIResponse, XID} from '../types';\n\n// HTTP methods\nexport type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\n// Request configuration\nexport interface RequestConfig {\n method?: HttpMethod;\n headers?: Record<string, string>;\n body?: any;\n params?: Record<string, any>;\n timeout?: number;\n retries?: number;\n cache?: boolean;\n organizationId?: XID;\n}\n\n// API client configuration\nexport interface APIClientConfig {\n baseUrl: string;\n apiKey?: string;\n publishableKey?: string;\n organizationId?: XID;\n timeout?: number;\n retries?: number;\n headers?: Record<string, string>;\n}\n\n// Request interceptor\nexport type RequestInterceptor = (config: RequestConfig) => RequestConfig | Promise<RequestConfig>;\n\n// Response interceptor\nexport type ResponseInterceptor = (response: Response) => Response | Promise<Response>;\n\n// Error handler\nexport type ErrorHandler = (error: APIError) => void;\n\n// API client class\nexport class APIClient {\n private config: APIClientConfig;\n private requestInterceptors: RequestInterceptor[] = [];\n private responseInterceptors: ResponseInterceptor[] = [];\n private errorHandlers: ErrorHandler[] = [];\n\n constructor(config: APIClientConfig) {\n this.config = config;\n }\n\n // Configuration methods\n setConfig(config: Partial<APIClientConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n setOrganizationContext(organizationId: XID): void {\n this.config.organizationId = organizationId;\n }\n\n clearOrganizationContext(): void {\n delete this.config.organizationId;\n }\n\n // Interceptor methods\n addRequestInterceptor(interceptor: RequestInterceptor): void {\n this.requestInterceptors.push(interceptor);\n }\n\n addResponseInterceptor(interceptor: ResponseInterceptor): void {\n this.responseInterceptors.push(interceptor);\n }\n\n addErrorHandler(handler: ErrorHandler): void {\n this.errorHandlers.push(handler);\n }\n\n // Main request method\n async request<T = any>(\n endpoint: string,\n config: RequestConfig = {}\n ): Promise<APIResponse<T>> {\n const url = this.buildUrl(endpoint, config.params);\n let requestConfig = this.buildRequestConfig(config);\n\n // Apply request interceptors\n for (const interceptor of this.requestInterceptors) {\n requestConfig = await interceptor(requestConfig);\n }\n\n try {\n const response = await this.executeRequest(url, requestConfig);\n\n // Apply response interceptors\n let processedResponse = response;\n for (const interceptor of this.responseInterceptors) {\n processedResponse = await interceptor(processedResponse);\n }\n\n return await this.parseResponse<T>(processedResponse);\n } catch (error) {\n const apiError = this.createAPIError(error);\n\n // Call error handlers\n for (const handler of this.errorHandlers) {\n handler(apiError);\n }\n\n throw apiError;\n }\n }\n\n // Convenience methods\n async get<T = any>(endpoint: string, config?: RequestConfig): Promise<APIResponse<T>> {\n return this.request<T>(endpoint, { ...config, method: 'GET' });\n }\n\n async post<T = any>(endpoint: string, data?: any, config?: RequestConfig): Promise<APIResponse<T>> {\n return this.request<T>(endpoint, { ...config, method: 'POST', body: data });\n }\n\n async put<T = any>(endpoint: string, data?: any, config?: RequestConfig): Promise<APIResponse<T>> {\n return this.request<T>(endpoint, { ...config, method: 'PUT', body: data });\n }\n\n async patch<T = any>(endpoint: string, data?: any, config?: RequestConfig): Promise<APIResponse<T>> {\n return this.request<T>(endpoint, { ...config, method: 'PATCH', body: data });\n }\n\n async delete<T = any>(endpoint: string, config?: RequestConfig): Promise<APIResponse<T>> {\n return this.request<T>(endpoint, { ...config, method: 'DELETE' });\n }\n\n // Private helper methods\n private buildUrl(endpoint: string, params?: Record<string, any>): string {\n const url = new URL(endpoint, this.config.baseUrl);\n\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n return url.toString();\n }\n\n private buildRequestConfig(config: RequestConfig): RequestConfig {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n ...config.headers,\n };\n\n // Add API key\n if (this.config.apiKey) {\n headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n } else if (this.config.publishableKey) {\n headers['X-Publishable-Key'] = this.config.publishableKey;\n }\n\n // Add organization context\n if (config.organizationId || this.config.organizationId) {\n headers['X-Organization-Id'] = config.organizationId || this.config.organizationId!;\n }\n\n return {\n method: 'GET',\n timeout: this.config.timeout || 30000,\n retries: this.config.retries || 3,\n ...config,\n headers,\n };\n }\n\n private async executeRequest(url: string, config: RequestConfig): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = config.timeout ?\n setTimeout(() => controller.abort(), config.timeout) : null;\n\n try {\n const fetchConfig: RequestInit = {\n method: config.method,\n headers: config.headers,\n signal: controller.signal,\n };\n\n if (config.body && config.method !== 'GET') {\n fetchConfig.body = typeof config.body === 'string'\n ? config.body\n : JSON.stringify(config.body);\n }\n\n const response = await fetch(url, fetchConfig);\n\n if (timeoutId) clearTimeout(timeoutId);\n\n return response;\n } catch (error) {\n if (timeoutId) clearTimeout(timeoutId);\n throw error;\n }\n }\n\n private async parseResponse<T>(response: Response): Promise<APIResponse<T>> {\n const contentType = response.headers.get('Content-Type') || '';\n\n let data: any;\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`, {\n cause: { status: response.status, data }\n });\n }\n\n // Handle different response formats\n if (data && typeof data === 'object' && 'success' in data) {\n return data as APIResponse<T>;\n }\n\n return {\n success: true,\n data: data as T,\n };\n }\n\n private createAPIError(error: any): APIError {\n if (error.cause && typeof error.cause === 'object') {\n const { status, data } = error.cause;\n\n if (data && typeof data === 'object' && 'errors' in data) {\n return {\n code: data.code || `HTTP_${status}`,\n message: data.message || error.message,\n details: data.details,\n };\n }\n }\n\n return {\n code: 'UNKNOWN_ERROR',\n message: error.message || 'An unknown error occurred',\n details: { originalError: error },\n };\n }\n}\n\n// Utility functions\nexport const createAPIClient = (config: APIClientConfig): APIClient => {\n return new APIClient(config);\n};\n\nexport const isAPIError = (error: any): error is APIError => {\n return error && typeof error === 'object' && 'code' in error && 'message' in error;\n};\n\nexport const handleAPIError = (error: any): APIError => {\n if (isAPIError(error)) return error;\n\n return {\n code: 'UNKNOWN_ERROR',\n message: error?.message || 'An unknown error occurred',\n details: { originalError: error },\n };\n};\n\nexport const retryRequest = async <T>(\n requestFn: () => Promise<T>,\n maxRetries = 3,\n delay = 1000\n): Promise<T> => {\n let lastError: Error;\n\n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n return await requestFn();\n } catch (error) {\n lastError = error as Error;\n\n if (attempt === maxRetries) break;\n\n // Exponential backoff\n const backoffDelay = delay * Math.pow(2, attempt - 1);\n await new Promise(resolve => setTimeout(resolve, backoffDelay));\n }\n }\n\n throw lastError!;\n};\n\nexport const withCache = <T>(\n requestFn: () => Promise<T>,\n cacheKey: string,\n ttl = 300000 // 5 minutes\n): Promise<T> => {\n const cache = new Map<string, { data: T; expires: number }>();\n\n return (async (): Promise<T> => {\n const cached = cache.get(cacheKey);\n\n if (cached && cached.expires > Date.now()) {\n return cached.data;\n }\n\n const data = await requestFn();\n cache.set(cacheKey, { data, expires: Date.now() + ttl });\n\n return data;\n })();\n};\n\nexport const batchRequests = async <T>(\n requests: (() => Promise<T>)[],\n batchSize = 5,\n delay = 100\n): Promise<T[]> => {\n const results: T[] = [];\n\n for (let i = 0; i < requests.length; i += batchSize) {\n const batch = requests.slice(i, i + batchSize);\n const batchResults = await Promise.all(batch.map(request => request()));\n results.push(...batchResults);\n\n // Add delay between batches\n if (i + batchSize < requests.length && delay > 0) {\n await new Promise(resolve => setTimeout(resolve, delay));\n }\n }\n\n return results;\n};\n\nexport const uploadFile = async (\n client: APIClient,\n endpoint: string,\n file: File,\n options: {\n onProgress?: (progress: number) => void;\n abortSignal?: AbortSignal;\n additionalData?: Record<string, any>;\n } = {}\n): Promise<APIResponse<any>> => {\n const formData = new FormData();\n formData.append('file', file);\n\n if (options.additionalData) {\n for (const [key, value] of Object.entries(options.additionalData)) {\n formData.append(key, String(value));\n }\n }\n\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n if (options.onProgress) {\n xhr.upload.addEventListener('progress', (event) => {\n if (event.lengthComputable) {\n const progress = (event.loaded / event.total) * 100;\n options.onProgress!(progress);\n }\n });\n }\n\n if (options.abortSignal) {\n options.abortSignal.addEventListener('abort', () => {\n xhr.abort();\n reject(new Error('Upload aborted'));\n });\n }\n\n xhr.addEventListener('load', async () => {\n try {\n const response = JSON.parse(xhr.responseText);\n if (xhr.status >= 200 && xhr.status < 300) {\n resolve(response);\n } else {\n reject(new Error(`Upload failed: ${response.message || xhr.statusText}`));\n }\n } catch (error) {\n reject(new Error('Failed to parse upload response'));\n }\n });\n\n xhr.addEventListener('error', () => {\n reject(new Error('Upload failed'));\n });\n\n xhr.open('POST', `${client['config'].baseUrl}${endpoint}`);\n\n // Add headers (except Content-Type, let browser set it for FormData)\n const headers = client['buildRequestConfig']({}).headers || {};\n for (const [key, value] of Object.entries(headers)) {\n if (key.toLowerCase() !== 'content-type') {\n xhr.setRequestHeader(key, value);\n }\n }\n\n xhr.send(formData);\n });\n};\n\nexport const downloadFile = async (\n client: APIClient,\n endpoint: string,\n filename?: string,\n options: {\n onProgress?: (progress: number) => void;\n abortSignal?: AbortSignal;\n } = {}\n): Promise<void> => {\n const response = await fetch(`${client['config'].baseUrl}${endpoint}`, {\n headers: client['buildRequestConfig']({}).headers,\n signal: options.abortSignal,\n });\n\n if (!response.ok) {\n throw new Error(`Download failed: ${response.statusText}`);\n }\n\n const blob = await response.blob();\n const url = window.URL.createObjectURL(blob);\n\n const a = document.createElement('a');\n a.style.display = 'none';\n a.href = url;\n a.download = filename || 'download';\n\n document.body.appendChild(a);\n a.click();\n\n window.URL.revokeObjectURL(url);\n document.body.removeChild(a);\n};\n\n// WebSocket utilities\nexport class APIWebSocket {\n private ws: WebSocket | null = null;\n private reconnectAttempts = 0;\n private maxReconnectAttempts = 5;\n private reconnectDelay = 1000;\n private messageQueue: any[] = [];\n private eventHandlers: Map<string, Set<(data: any) => void>> = new Map();\n\n constructor(\n private url: string,\n private config: {\n token?: string;\n organizationId?: XID;\n autoReconnect?: boolean;\n } = {}\n ) {}\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const wsUrl = new URL(this.url);\n\n if (this.config.token) {\n wsUrl.searchParams.set('token', this.config.token);\n }\n\n if (this.config.organizationId) {\n wsUrl.searchParams.set('organizationId', this.config.organizationId);\n }\n\n this.ws = new WebSocket(wsUrl.toString());\n\n this.ws.onopen = () => {\n this.reconnectAttempts = 0;\n\n // Send queued messages\n while (this.messageQueue.length > 0) {\n const message = this.messageQueue.shift();\n this.ws!.send(JSON.stringify(message));\n }\n\n resolve();\n };\n\n this.ws.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n this.handleMessage(data);\n } catch (error) {\n console.error('Failed to parse WebSocket message:', error);\n }\n };\n\n this.ws.onclose = () => {\n this.ws = null;\n\n if (this.config.autoReconnect !== false &&\n this.reconnectAttempts < this.maxReconnectAttempts) {\n setTimeout(() => {\n this.reconnectAttempts++;\n this.connect();\n }, this.reconnectDelay * Math.pow(2, this.reconnectAttempts));\n }\n };\n\n this.ws.onerror = (error) => {\n reject(error);\n };\n\n } catch (error) {\n reject(error);\n }\n });\n }\n\n disconnect(): void {\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n }\n\n send(message: any): void {\n if (this.ws && this.ws.readyState === WebSocket.OPEN) {\n this.ws.send(JSON.stringify(message));\n } else {\n this.messageQueue.push(message);\n }\n }\n\n on(event: string, handler: (data: any) => void): () => void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n\n this.eventHandlers.get(event)!.add(handler);\n\n return () => {\n this.eventHandlers.get(event)?.delete(handler);\n };\n }\n\n private handleMessage(data: any): void {\n const { type, payload } = data;\n\n if (this.eventHandlers.has(type)) {\n for (const handler of this.eventHandlers.get(type)!) {\n handler(payload);\n }\n }\n }\n}"],"names":["APIClient","config","__publicField","organizationId","interceptor","handler","endpoint","url","requestConfig","processedResponse","error","apiError","data","params","key","value","headers","controller","timeoutId","fetchConfig","response","contentType","status","createAPIClient","isAPIError","handleAPIError","retryRequest","requestFn","maxRetries","delay","lastError","attempt","backoffDelay","resolve","withCache","cacheKey","ttl","cache","cached","batchRequests","requests","batchSize","results","i","batch","batchResults","request","uploadFile","client","file","options","formData","reject","xhr","event","progress","downloadFile","filename","blob","APIWebSocket","wsUrl","message","type","payload"],"mappings":"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"}