zlient 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/endpoint/base-endpoint.d.ts +117 -0
- package/dist/endpoint/base-endpoint.d.ts.map +1 -0
- package/dist/http/{HttpClient.d.ts → http-client.d.ts} +1 -1
- package/dist/http/http-client.d.ts.map +1 -0
- package/dist/index.cjs +83 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +83 -57
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/metrics.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/endpoint/BaseEndpoint.d.ts +0 -65
- package/dist/endpoint/BaseEndpoint.d.ts.map +0 -1
- package/dist/http/HttpClient.d.ts.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["z","s","opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","minLevel: LogLevel","logger: Logger","k: string","err: unknown","init: RequestInit & { __urlOverride?: string }","timeoutId: NodeJS.Timeout | number | undefined","client: HttpClient","mergedQuery: Record<string, string | number | boolean | undefined> | undefined","z"],"sources":["../lib/types.ts","../lib/auth.ts","../lib/validation.ts","../lib/logger.ts","../lib/metrics.ts","../lib/http/HttpClient.ts","../lib/endpoint/BaseEndpoint.ts","../lib/schemas/common.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\nimport { AuthProvider } from './auth';\nimport { Logger } from './logger';\nimport { MetricsCollector } from './metrics';\n\nexport type Dictionary<T = unknown> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Map of base URLs for different services.\n * The 'default' key is required and used when no specific key is provided.\n * \n * @example\n * ```ts\n * {\n * default: 'https://api.example.com',\n * auth: 'https://auth.example.com',\n * cdn: 'https://cdn.example.com'\n * }\n * ```\n */\nexport type BaseUrlMap = {\n default: string;\n [service: string]: string;\n};\n\n/**\n * Configuration for retry behavior on failed requests.\n * Implements exponential backoff with optional jitter.\n * \n * @example\n * ```ts\n * {\n * maxRetries: 3,\n * baseDelayMs: 1000,\n * jitter: 0.2,\n * retryMethods: ['GET', 'HEAD', 'PUT']\n * }\n * ```\n */\nexport type RetryStrategy = {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds (will be exponentially increased) */\n baseDelayMs: number;\n /** Jitter factor 0..1 to randomize delays and prevent thundering herd */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** Custom function to determine if a request should be retried */\n shouldRetry?: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean;\n};\n\nexport const HTTPMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n HEAD: 'HEAD',\n OPTIONS: 'OPTIONS',\n} as const;\n\nexport type HttpMethod = keyof typeof HTTPMethod;\n\n/**\n * Hook called after a response is received and parsed.\n * Useful for logging, metrics, or global error handling.\n */\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\n/**\n * Hook called before a request is sent.\n * Useful for logging, adding headers, or modifying the request.\n */\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n /** Hooks executed before each request is sent */\n beforeRequest?: BeforeRequestHook[];\n /** Hooks executed after each response is received */\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** Request timeout in milliseconds */\n requestTimeoutMs?: number;\n}\n\n/**\n * Configuration options for the HTTP client.\n * \n * @example\n * ```ts\n * const options: ClientOptions = {\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'X-API-Version': '1.0' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * }\n * ```\n */\nexport interface ClientOptions {\n /** Map of base URLs for different services */\n baseUrls: BaseUrlMap;\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: FetchLike;\n /** Default headers applied to all requests */\n headers?: Record<string, string>;\n /** Retry strategy configuration */\n retry?: RetryStrategy;\n /** Request/response interceptors */\n interceptors?: Interceptors;\n /** Timeout configuration */\n timeout?: TimeoutOptions;\n /** Authentication provider */\n auth?: AuthProvider;\n /** Logger instance */\n logger?: Logger;\n /** Metrics collector */\n metrics?: MetricsCollector;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\n\n/**\n * Custom error class for API-related errors.\n * Includes HTTP status codes, response details, and validation errors.\n * \n * @example\n * ```ts\n * throw new ApiError('Invalid request', {\n * status: 400,\n * details: { field: 'email', message: 'Invalid format' }\n * });\n * ```\n */\nexport class ApiError extends Error {\n public status?: number;\n public details?: unknown;\n public zodError?: ZodError;\n\n constructor(\n message: string,\n options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = options?.status;\n this.details = options?.details;\n this.cause = options?.cause as any;\n this.zodError = options?.zodError;\n\n // Maintains proper stack trace for where error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n\n /**\n * Check if this is a validation error (has zodError)\n */\n isValidationError(): boolean {\n return !!this.zodError;\n }\n\n /**\n * Check if this is a client error (4xx status)\n */\n isClientError(): boolean {\n return !!this.status && this.status >= 400 && this.status < 500;\n }\n\n /**\n * Check if this is a server error (5xx status)\n */\n isServerError(): boolean {\n return !!this.status && this.status >= 500;\n }\n\n /**\n * Get a formatted error message with all available details\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details,\n zodError: this.zodError?.issues,\n stack: this.stack,\n };\n }\n}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\n\n/**\n * Schema for paginated responses\n */\nexport const PaginationSchema = z.object({\n items: z.array(z.unknown()),\n total: z.number().int().nonnegative(),\n page: z.number().int().nonnegative(),\n pageSize: z.number().int().positive(),\n});\n\n/**\n * Options that can be passed to individual requests to override defaults.\n * \n * @example\n * ```ts\n * await endpoint.call(data, {\n * baseUrlKey: 'v2',\n * headers: { 'X-Custom': 'value' },\n * query: { filter: 'active' }\n * });\n * ```\n */\nexport type RequestOptions = {\n /** Override base URL for a single call */\n baseUrlKey?: keyof BaseUrlMap;\n /** Additional headers for this call only */\n headers?: Record<string, string>;\n /** Abort controller signal for cancellation */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n/**\n * Converts query parameters to a URL query string.\n * Filters out undefined values automatically.\n * \n * @param q - Query parameters as URLSearchParams or object\n * @returns Query string with leading '?' or empty string\n * \n * @example\n * ```ts\n * toQueryString({ page: 1, filter: 'active' }) // \"?page=1&filter=active\"\n * toQueryString({ optional: undefined }) // \"\"\n * ```\n */\nexport function toQueryString(q?: RequestOptions['query']): string {\n if (!q) return '';\n if (q instanceof URLSearchParams) {\n const s = q.toString();\n return s ? `?${s}` : '';\n }\n const params = new URLSearchParams();\n Object.entries(q).forEach(([k, v]) => {\n if (v !== undefined) {\n params.append(k, String(v));\n }\n });\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n","import type { RequestOptions as ReqOpts } from './types';\n\n/**\n * Extended RequestInit with URL override capability for query-based auth.\n */\nexport interface AuthContext {\n url: string;\n init: RequestInit & { __urlOverride?: string };\n options?: ReqOpts;\n}\n\n/**\n * Interface for authentication providers.\n * Implement this to create custom authentication strategies.\n * \n * @example\n * ```ts\n * class CustomAuth implements AuthProvider {\n * async apply({ init }) {\n * init.headers = { ...init.headers, 'X-Custom-Auth': 'token' };\n * }\n * }\n * ```\n */\nexport interface AuthProvider {\n /**\n * Apply authentication to the outgoing request.\n * Called after SDK headers are assembled, but before request is sent.\n * \n * @param req - Request context including URL, init, and options\n */\n apply(req: AuthContext): Promise<void> | void;\n}\n\n/**\n * No-op authentication provider (no authentication applied).\n * Use this when you don't need authentication.\n */\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\n/**\n * API Key authentication provider.\n * Supports both header-based and query parameter-based authentication.\n * \n * @example\n * ```ts\n * // Header-based\n * const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });\n * \n * // Query parameter-based\n * const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });\n * ```\n */\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {\n if (!opts.header && !opts.query) {\n throw new Error('ApiKeyAuth requires either \"header\" or \"query\" option');\n }\n if (opts.header && opts.query) {\n throw new Error('ApiKeyAuth cannot use both \"header\" and \"query\" options');\n }\n }\n apply({ url, init }: AuthContext) {\n if (this.opts.header) {\n init.headers = { ...(init.headers as any), [this.opts.header]: this.opts.value };\n } else if (this.opts.query) {\n const u = new URL(url);\n u.searchParams.set(this.opts.query, this.opts.value);\n init.__urlOverride = u.toString();\n }\n }\n}\n\n/**\n * Bearer token authentication provider.\n * Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).\n * \n * @example\n * ```ts\n * // Static token\n * const auth = new BearerTokenAuth(() => 'my-token');\n * \n * // Dynamic token with refresh\n * const auth = new BearerTokenAuth(async () => {\n * return await refreshAccessToken();\n * });\n * ```\n */\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) { }\n async apply({ init }: AuthContext) {\n const token = await this.getToken();\n if (!token) {\n throw new Error('BearerTokenAuth: token is empty or undefined');\n }\n init.headers = { ...(init.headers as any), Authorization: `Bearer ${token}` };\n }\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\n/**\n * Safely parse data with a Zod schema without throwing.\n * Returns a result object with success status and data or error.\n * \n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Result object with success flag and data/error\n * \n * @example\n * ```ts\n * const result = safeParse(UserSchema, userData);\n * if (result.success) {\n * console.log(result.data);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport function safeParse<T>(schema: z.ZodType, data: unknown): SafeParseResult<T> {\n const res = schema.safeParse(data);\n if (res.success) return { success: true, data: res.data as T };\n return { success: false, error: res.error };\n}\n\n/**\n * Parse data with a Zod schema, throwing an ApiError on validation failure.\n * Use this when you want to fail fast on invalid data.\n * \n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {ApiError} If validation fails\n * \n * @example\n * ```ts\n * try {\n * const user = parseOrThrow(UserSchema, userData);\n * console.log(user);\n * } catch (error) {\n * if (error instanceof ApiError && error.zodError) {\n * console.error('Validation failed:', error.zodError.issues);\n * }\n * }\n * ```\n */\nexport function parseOrThrow<T>(schema: z.ZodType, data: unknown): T {\n const res = schema.safeParse(data);\n if (!res.success) {\n throw new ApiError('Response validation failed', { zodError: res.error });\n }\n return res.data as T;\n}\n","/**\n * Log levels for structured logging.\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Structured log entry with metadata.\n */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/**\n * Logger interface for custom logger implementations.\n * Implement this to integrate with your logging infrastructure.\n * \n * @example\n * ```ts\n * class ConsoleLogger implements Logger {\n * log(entry: LogEntry) {\n * console.log(JSON.stringify(entry));\n * }\n * }\n * ```\n */\nexport interface Logger {\n log(entry: LogEntry): void;\n}\n\n/**\n * Default console logger implementation.\n * Formats log entries as JSON for easy parsing.\n */\nexport class ConsoleLogger implements Logger {\n constructor(private minLevel: LogLevel = LogLevel.INFO) { }\n\n log(entry: LogEntry): void {\n const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];\n const entryLevelIndex = levels.indexOf(entry.level);\n const minLevelIndex = levels.indexOf(this.minLevel);\n\n if (entryLevelIndex < minLevelIndex) return;\n\n const output = {\n ...entry,\n error: entry.error\n ? {\n message: entry.error.message,\n stack: entry.error.stack,\n name: entry.error.name,\n }\n : undefined,\n };\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(JSON.stringify(output));\n break;\n case LogLevel.INFO:\n console.info(JSON.stringify(output));\n break;\n case LogLevel.WARN:\n console.warn(JSON.stringify(output));\n break;\n case LogLevel.ERROR:\n console.error(JSON.stringify(output));\n break;\n }\n }\n}\n\n/**\n * No-op logger that discards all log entries.\n * Use this in production if you don't want any logging.\n */\nexport class NoOpLogger implements Logger {\n log(_entry: LogEntry): void {\n // no-op\n }\n}\n\n/**\n * Utility class for creating structured log entries.\n */\nexport class LoggerUtil {\n constructor(private logger: Logger) { }\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.DEBUG,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.INFO,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.WARN,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n error(message: string, error?: Error, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.ERROR,\n message,\n timestamp: new Date().toISOString(),\n context,\n error,\n });\n }\n}\n","/**\n * Metrics data for HTTP requests.\n */\nexport interface RequestMetrics {\n method: string;\n path: string;\n status?: number;\n durationMs: number;\n timestamp: string;\n success: boolean;\n error?: string;\n}\n\n/**\n * Interface for metrics collectors.\n * Implement this to integrate with your monitoring infrastructure (DataDog, Prometheus, etc.).\n * \n * @example\n * ```ts\n * class DataDogMetrics implements MetricsCollector {\n * collect(metrics: RequestMetrics) {\n * dogstatsd.histogram('http.request.duration', metrics.durationMs, {\n * method: metrics.method,\n * status: String(metrics.status)\n * });\n * }\n * }\n * ```\n */\nexport interface MetricsCollector {\n collect(metrics: RequestMetrics): void;\n}\n\n/**\n * No-op metrics collector that discards all metrics.\n */\nexport class NoOpMetricsCollector implements MetricsCollector {\n collect(_metrics: RequestMetrics): void {\n // no-op\n }\n}\n\n/**\n * In-memory metrics collector for testing and development.\n * Stores metrics in memory with configurable retention.\n */\nexport class InMemoryMetricsCollector implements MetricsCollector {\n private metrics: RequestMetrics[] = [];\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n collect(metrics: RequestMetrics): void {\n this.metrics.push(metrics);\n if (this.metrics.length > this.maxEntries) {\n this.metrics.shift();\n }\n }\n\n /**\n * Get all collected metrics.\n */\n getMetrics(): RequestMetrics[] {\n return [...this.metrics];\n }\n\n /**\n * Get metrics summary statistics.\n */\n getSummary(): {\n total: number;\n successful: number;\n failed: number;\n avgDurationMs: number;\n minDurationMs: number;\n maxDurationMs: number;\n } {\n if (this.metrics.length === 0) {\n return {\n total: 0,\n successful: 0,\n failed: 0,\n avgDurationMs: 0,\n minDurationMs: 0,\n maxDurationMs: 0,\n };\n }\n\n const successful = this.metrics.filter((m) => m.success).length;\n const durations = this.metrics.map((m) => m.durationMs);\n const sum = durations.reduce((a, b) => a + b, 0);\n\n return {\n total: this.metrics.length,\n successful,\n failed: this.metrics.length - successful,\n avgDurationMs: sum / this.metrics.length,\n minDurationMs: Math.min(...durations),\n maxDurationMs: Math.max(...durations),\n };\n }\n\n /**\n * Clear all collected metrics.\n */\n clear(): void {\n this.metrics = [];\n }\n}\n\n/**\n * Console-based metrics collector for debugging.\n */\nexport class ConsoleMetricsCollector implements MetricsCollector {\n collect(metrics: RequestMetrics): void {\n console.log('[METRICS]', JSON.stringify(metrics));\n }\n}\n","import type { AuthProvider } from '../auth';\nimport { NoAuth } from '../auth';\nimport { LoggerUtil, NoOpLogger } from '../logger';\nimport { MetricsCollector, NoOpMetricsCollector } from '../metrics';\nimport {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\n\n/**\n * HTTP client with built-in retry logic, authentication, and interceptors.\n * Supports multiple base URLs, type-safe requests, and comprehensive error handling.\n * \n * @example\n * ```ts\n * const client = new HttpClient({\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'Content-Type': 'application/json' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * });\n * \n * const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });\n * ```\n */\nexport class HttpClient {\n private fetchImpl: FetchLike;\n private baseUrls: ClientOptions['baseUrls'];\n private headers: Record<string, string>;\n private interceptors: Interceptors;\n private retry: RetryStrategy;\n private timeoutMs?: number;\n private auth: AuthProvider;\n private logger: LoggerUtil;\n private metrics: MetricsCollector;\n\n /**\n * Creates a new HTTP client instance.\n * \n * @param opts - Client configuration options\n * @throws {Error} If no fetch implementation is available\n */\n constructor(opts: ClientOptions) {\n this.fetchImpl = opts.fetch ?? (globalThis.fetch?.bind(globalThis) as FetchLike);\n if (!this.fetchImpl)\n throw new Error('No fetch implementation found. Pass one via options.fetch.');\n\n // Validate baseUrls configuration\n if (!opts.baseUrls || typeof opts.baseUrls !== 'object') {\n throw new Error('baseUrls must be provided and must be an object');\n }\n if (!opts.baseUrls.default) {\n throw new Error('baseUrls must include a \"default\" key');\n }\n\n this.baseUrls = opts.baseUrls;\n this.headers = opts.headers ?? { 'Content-Type': 'application/json' };\n this.interceptors = opts.interceptors ?? {};\n this.retry = opts.retry ?? {\n maxRetries: 2,\n baseDelayMs: 250,\n jitter: 0.2,\n retryMethods: ['GET', 'HEAD'],\n };\n\n // Validate retry configuration\n if (this.retry.maxRetries < 0) {\n throw new Error('retry.maxRetries must be non-negative');\n }\n if (this.retry.baseDelayMs < 0) {\n throw new Error('retry.baseDelayMs must be non-negative');\n }\n if (this.retry.jitter !== undefined && (this.retry.jitter < 0 || this.retry.jitter > 1)) {\n throw new Error('retry.jitter must be between 0 and 1');\n }\n\n this.timeoutMs = opts.timeout?.requestTimeoutMs;\n if (this.timeoutMs !== undefined && this.timeoutMs < 0) {\n throw new Error('timeout.requestTimeoutMs must be non-negative');\n }\n\n this.auth = opts['auth'] ?? new NoAuth();\n this.logger = new LoggerUtil(opts.logger ?? new NoOpLogger());\n this.metrics = opts.metrics ?? new NoOpMetricsCollector();\n }\n\n /**\n * Set or update the authentication provider.\n * \n * @param auth - Authentication provider instance\n * @example\n * ```ts\n * client.setAuth(new BearerTokenAuth(() => getToken()));\n * ```\n */\n setAuth(auth: AuthProvider) {\n this.auth = auth;\n }\n\n private resolveBaseUrl(key?: keyof typeof this.baseUrls) {\n const k: string = (key as string) || 'default';\n const url = this.baseUrls[k];\n if (!url) {\n const availableKeys = Object.keys(this.baseUrls).join(', ');\n throw new Error(`Unknown baseUrl key: \"${k}\". Available keys: ${availableKeys}`);\n }\n return url.replace(/\\/$/, '');\n }\n\n /**\n * Sleep for a specified duration (used for retry backoff).\n * @private\n */\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\n\n /**\n * Execute a function with retry logic and exponential backoff.\n * @private\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean\n ): Promise<T> {\n let attempt = 0;\n const { maxRetries, baseDelayMs, jitter = 0.2 } = this.retry;\n while (true) {\n try {\n return await fn();\n } catch (err: unknown) {\n if (attempt >= maxRetries || !canRetry({ attempt, error: err })) throw err;\n const backoff = baseDelayMs * 2 ** attempt;\n const j = 1 + (Math.random() * 2 - 1) * jitter;\n await this.sleep(backoff * j);\n attempt++;\n }\n }\n }\n\n /**\n * Run all registered before-request hooks.\n * @private\n */\n private async runBeforeHooks(url: string, init: RequestInit & { __urlOverride?: string }) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\n\n /**\n * Run all registered after-response hooks.\n * @private\n */\n private async runAfterHooks(req: Request, res: Response, parsed?: unknown) {\n for (const h of this.interceptors.afterResponse ?? []) {\n await h({ request: req, response: res, parsed });\n }\n }\n\n /**\n * Make an HTTP request with automatic retry, authentication, and validation.\n * \n * @param method - HTTP method (GET, POST, PUT, etc.)\n * @param path - Request path (will be appended to base URL)\n * @param body - Request body (will be JSON.stringify'd if Content-Type is json)\n * @param options - Additional request options (headers, query params, etc.)\n * @returns Promise resolving to response data and Response object\n * @throws {ApiError} If request fails or response validation fails\n * \n * @example\n * ```ts\n * const { data, response } = await client.request('GET', '/users', undefined, {\n * query: { page: 1, limit: 10 },\n * headers: { 'X-Custom': 'value' }\n * });\n * ```\n */\n async request<T = unknown>(\n method: keyof typeof HTTPMethod,\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n const startTime = Date.now();\n const base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\n\n this.logger.debug('HTTP request initiated', {\n method,\n path,\n baseUrlKey: options?.baseUrlKey,\n hasBody: body !== undefined,\n });\n\n const headers = { ...this.headers, ...(options?.headers ?? {}) };\n\n const controller = new AbortController();\n const signal = options?.signal ?? controller.signal;\n const init: RequestInit & { __urlOverride?: string } = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : String(body)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if (init.__urlOverride) url = init.__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: NodeJS.Timeout | number | undefined;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(() => {\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n controller.abort(timeoutError);\n }, this.timeoutMs);\n }\n\n try {\n const req = new Request(url, init);\n\n const res = await this.fetchImpl(req);\n if (!res.ok) {\n // Read response safely\n let text = '';\n try {\n text = await res.text();\n } catch (readError) {\n text = `Failed to read response: ${readError instanceof Error ? readError.message : String(readError)}`;\n }\n throw new ApiError(`HTTP ${res.status}: ${res.statusText}`, {\n status: res.status,\n details: text,\n });\n }\n const contentType = res.headers.get('content-type') || '';\n const data = contentType.includes('json') ? await res.json() : await res.text();\n await this.runAfterHooks(new Request(url, init), res, data);\n\n const duration = Date.now() - startTime;\n this.logger.info('HTTP request successful', {\n method,\n url,\n status: res.status,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: res.status,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: true,\n });\n\n return { data: data as T, response: res };\n } catch (error) {\n const duration = Date.now() - startTime;\n this.logger.error('HTTP request failed', error as Error, {\n method,\n url,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: error instanceof ApiError ? error.status : undefined,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n response,\n error,\n }: {\n response?: Response;\n error?: unknown;\n attempt: number;\n }) => {\n // Don't retry timeouts or aborts\n if (error && typeof error === 'object' && 'name' in error) {\n const errorName = (error as { name?: string }).name;\n if (errorName === 'AbortError' || errorName === 'TimeoutError') return false;\n }\n // Retry on network errors or 5xx\n if (error instanceof ApiError && error.status && error.status >= 500) return true;\n if (error && !response) return true; // network error\n return false;\n };\n\n if (!this.retry.retryMethods?.includes(method)) {\n return doFetch();\n }\n return this.withRetry(doFetch, canRetry);\n }\n\n /**\n * Convenience method for GET requests.\n * \n * @example\n * ```ts\n * const { data } = await client.get('/users', { query: { page: 1 } });\n * ```\n */\n async get<T = unknown>(path: string, options?: RequestOptions): Promise<{ data: T; response: Response }> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n /**\n * Convenience method for POST requests.\n * \n * @example\n * ```ts\n * const { data } = await client.post('/users', { name: 'John' });\n * ```\n */\n async post<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<{ data: T; response: Response }> {\n return this.request<T>('POST', path, body, options);\n }\n\n /**\n * Convenience method for PUT requests.\n * \n * @example\n * ```ts\n * const { data } = await client.put('/users/1', { name: 'John Updated' });\n * ```\n */\n async put<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<{ data: T; response: Response }> {\n return this.request<T>('PUT', path, body, options);\n }\n\n /**\n * Convenience method for PATCH requests.\n * \n * @example\n * ```ts\n * const { data } = await client.patch('/users/1', { name: 'John' });\n * ```\n */\n async patch<T = unknown>(path: string, body?: unknown, options?: RequestOptions): Promise<{ data: T; response: Response }> {\n return this.request<T>('PATCH', path, body, options);\n }\n\n /**\n * Convenience method for DELETE requests.\n * \n * @example\n * ```ts\n * const { data } = await client.delete('/users/1');\n * ```\n */\n async delete<T = unknown>(path: string, options?: RequestOptions): Promise<{ data: T; response: Response }> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n}\n","import { z } from 'zod';\nimport { HttpClient } from '../http/HttpClient';\nimport { HTTPMethod, RequestOptions } from '../types';\nimport { parseOrThrow } from '../validation';\n\n/**\n * Generic, strongly-typed endpoint with Zod schemas for request and response validation.\n * Extend this class to create type-safe API endpoints.\n * \n * @template ReqSchema - Zod schema for request validation\n * @template ResSchema - Zod schema for response validation\n * \n * @example\n * ```ts\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n * const CreateUserSchema = z.object({ name: z.string() });\n * \n * class GetUser extends BaseEndpoint<typeof CreateUserSchema, typeof UserSchema> {\n * protected method = 'GET' as const;\n * protected path = (args: z.infer<typeof CreateUserSchema>) => `/users/${args.id}`;\n * \n * constructor(client: HttpClient) {\n * super(client, { \n * requestSchema: CreateUserSchema,\n * responseSchema: UserSchema \n * });\n * }\n * }\n * ```\n */\nexport abstract class BaseEndpoint<ReqSchema extends z.ZodType, ResSchema extends z.ZodType> {\n /** HTTP method for this endpoint */\n protected abstract readonly method: keyof typeof HTTPMethod;\n /** URL path (can be a function for dynamic paths) */\n protected abstract readonly path: string | ((params: z.infer<ReqSchema>) => string);\n /** Optional request schema for validation */\n protected readonly requestSchema?: ReqSchema;\n /** Response schema for validation */\n protected readonly responseSchema: ResSchema;\n\n /**\n * @param client - HttpClient instance\n * @param cfg - Configuration with request and response schemas\n */\n constructor(\n protected client: HttpClient,\n cfg: { requestSchema?: ReqSchema; responseSchema: ResSchema }\n ) {\n this.requestSchema = cfg.requestSchema;\n this.responseSchema = cfg.responseSchema;\n }\n\n /**\n * Call the endpoint with strong typing derived from schemas.\n * Validates request data before sending and response data after receiving.\n * \n * @param args - Request arguments (typed by ReqSchema)\n * @param options - Additional request options\n * @returns Promise resolving to validated response data (typed by ResSchema)\n * @throws {ZodError} If request validation fails\n * @throws {ApiError} If response validation fails or request fails\n * \n * @example\n * ```ts\n * const endpoint = new GetUser(client);\n * const user = await endpoint.call({ id: 1 });\n * ```\n */\n async call(args: z.infer<ReqSchema>, options?: RequestOptions): Promise<z.infer<ResSchema>> {\n // Validate request body/params before sending (when schema provided)\n if (this.requestSchema) {\n const parsed = this.requestSchema.safeParse(args);\n if (!parsed.success) throw parsed.error;\n }\n\n const path = typeof this.path === 'function' ? this.path(args) : this.path;\n\n // For GET/HEAD methods, don't send body. Allow query params from args.query or options.query\n const shouldHaveBody = this.method !== 'GET' && this.method !== 'HEAD';\n const body = shouldHaveBody ? args : undefined;\n\n // Merge query params: args.query takes precedence over options.query\n const argsAsRecord = args as Record<string, unknown>;\n const queryFromArgs = argsAsRecord?.query;\n\n let mergedQuery: Record<string, string | number | boolean | undefined> | undefined;\n if (options?.query || queryFromArgs) {\n mergedQuery = {\n ...(typeof options?.query === 'object' && !(options?.query instanceof URLSearchParams) ? options.query : {}),\n ...(typeof queryFromArgs === 'object' && queryFromArgs !== null ? queryFromArgs as Record<string, string | number | boolean | undefined> : {}),\n };\n }\n\n const { data } = await this.client.request(this.method, path, body, {\n ...options,\n query: mergedQuery && Object.keys(mergedQuery).length > 0 ? mergedQuery : options?.query,\n });\n\n return parseOrThrow<z.infer<ResSchema>>(this.responseSchema, data);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Common ID type that supports strings, numbers, or UUIDs.\n * Use this for entity identifiers in your schemas.\n * \n * @example\n * ```ts\n * const UserSchema = z.object({ id: Id, name: z.string() });\n * ```\n */\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type IdType = z.infer<typeof Id>;\n\n/**\n * Common timestamp fields for entities.\n * Use this for database models with creation/update tracking.\n * \n * @example\n * ```ts\n * const UserSchema = z.object({\n * id: Id,\n * name: z.string(),\n * ...Timestamps.shape\n * });\n * ```\n */\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\n/**\n * Metadata information typically included in API responses.\n * Contains request tracking and debugging information.\n */\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\n/**\n * Detailed error information for a specific field or path.\n */\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\n/**\n * Standard API error response schema.\n * Use this for consistent error handling across your API.\n */\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\n/**\n * Generic envelope wrapper for API responses.\n * Provides consistent structure with success flag, data, error, and metadata.\n * \n * @param inner - Zod schema for the response data\n * @returns Envelope schema wrapping the inner schema\n * \n * @example\n * ```ts\n * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));\n * \n * // Response structure:\n * // {\n * // success: true,\n * // data: { id: 1, name: 'John' },\n * // meta: { requestId: '...' }\n * // }\n * ```\n */\nexport const Envelope = <T extends z.ZodType>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional().nullable(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["z","s","opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","minLevel: LogLevel","logger: Logger","k: string","err: unknown","init: RequestInit & { __urlOverride?: string }","timeoutId: NodeJS.Timeout | number | undefined","client: HttpClient","z"],"sources":["../lib/types.ts","../lib/auth.ts","../lib/validation.ts","../lib/logger.ts","../lib/metrics.ts","../lib/http/http-client.ts","../lib/endpoint/base-endpoint.ts","../lib/schemas/common.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\nimport { AuthProvider } from './auth';\nimport { Logger } from './logger';\nimport { MetricsCollector } from './metrics';\n\nexport type Dictionary<T = unknown> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Map of base URLs for different services.\n * The 'default' key is required and used when no specific key is provided.\n *\n * @example\n * ```ts\n * {\n * default: 'https://api.example.com',\n * auth: 'https://auth.example.com',\n * cdn: 'https://cdn.example.com'\n * }\n * ```\n */\nexport type BaseUrlMap = {\n default: string;\n [service: string]: string;\n};\n\n/**\n * Configuration for retry behavior on failed requests.\n * Implements exponential backoff with optional jitter.\n *\n * @example\n * ```ts\n * {\n * maxRetries: 3,\n * baseDelayMs: 1000,\n * jitter: 0.2,\n * retryMethods: ['GET', 'HEAD', 'PUT']\n * }\n * ```\n */\nexport type RetryStrategy = {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds (will be exponentially increased) */\n baseDelayMs: number;\n /** Jitter factor 0..1 to randomize delays and prevent thundering herd */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** Custom function to determine if a request should be retried */\n shouldRetry?: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean;\n};\n\nexport const HTTPMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n HEAD: 'HEAD',\n OPTIONS: 'OPTIONS',\n} as const;\n\nexport type HttpMethod = keyof typeof HTTPMethod;\n\n/**\n * Hook called after a response is received and parsed.\n * Useful for logging, metrics, or global error handling.\n */\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\n/**\n * Hook called before a request is sent.\n * Useful for logging, adding headers, or modifying the request.\n */\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n /** Hooks executed before each request is sent */\n beforeRequest?: BeforeRequestHook[];\n /** Hooks executed after each response is received */\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** Request timeout in milliseconds */\n requestTimeoutMs?: number;\n}\n\n/**\n * Configuration options for the HTTP client.\n *\n * @example\n * ```ts\n * const options: ClientOptions = {\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'X-API-Version': '1.0' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * }\n * ```\n */\nexport interface ClientOptions {\n /** Map of base URLs for different services */\n baseUrls: BaseUrlMap;\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: FetchLike;\n /** Default headers applied to all requests */\n headers?: Record<string, string>;\n /** Retry strategy configuration */\n retry?: RetryStrategy;\n /** Request/response interceptors */\n interceptors?: Interceptors;\n /** Timeout configuration */\n timeout?: TimeoutOptions;\n /** Authentication provider */\n auth?: AuthProvider;\n /** Logger instance */\n logger?: Logger;\n /** Metrics collector */\n metrics?: MetricsCollector;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\n\n/**\n * Custom error class for API-related errors.\n * Includes HTTP status codes, response details, and validation errors.\n *\n * @example\n * ```ts\n * throw new ApiError('Invalid request', {\n * status: 400,\n * details: { field: 'email', message: 'Invalid format' }\n * });\n * ```\n */\nexport class ApiError extends Error {\n public status?: number;\n public details?: unknown;\n public zodError?: ZodError;\n\n constructor(\n message: string,\n options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = options?.status;\n this.details = options?.details;\n this.cause = options?.cause as any;\n this.zodError = options?.zodError;\n\n // Maintains proper stack trace for where error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n\n /**\n * Check if this is a validation error (has zodError)\n */\n isValidationError(): boolean {\n return !!this.zodError;\n }\n\n /**\n * Check if this is a client error (4xx status)\n */\n isClientError(): boolean {\n return !!this.status && this.status >= 400 && this.status < 500;\n }\n\n /**\n * Check if this is a server error (5xx status)\n */\n isServerError(): boolean {\n return !!this.status && this.status >= 500;\n }\n\n /**\n * Get a formatted error message with all available details\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details,\n zodError: this.zodError?.issues,\n stack: this.stack,\n };\n }\n}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\n\n/**\n * Schema for paginated responses\n */\nexport const PaginationSchema = z.object({\n items: z.array(z.unknown()),\n total: z.number().int().nonnegative(),\n page: z.number().int().nonnegative(),\n pageSize: z.number().int().positive(),\n});\n\n/**\n * Options that can be passed to individual requests to override defaults.\n *\n * @example\n * ```ts\n * await endpoint.call(data, {\n * baseUrlKey: 'v2',\n * headers: { 'X-Custom': 'value' },\n * query: { filter: 'active' }\n * });\n * ```\n */\nexport type RequestOptions = {\n /** Override base URL for a single call */\n baseUrlKey?: keyof BaseUrlMap;\n /** Additional headers for this call only */\n headers?: Record<string, string>;\n /** Abort controller signal for cancellation */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n/**\n * Converts query parameters to a URL query string.\n * Filters out undefined values automatically.\n *\n * @param q - Query parameters as URLSearchParams or object\n * @returns Query string with leading '?' or empty string\n *\n * @example\n * ```ts\n * toQueryString({ page: 1, filter: 'active' }) // \"?page=1&filter=active\"\n * toQueryString({ optional: undefined }) // \"\"\n * ```\n */\nexport function toQueryString(q?: RequestOptions['query']): string {\n if (!q) return '';\n if (q instanceof URLSearchParams) {\n const s = q.toString();\n return s ? `?${s}` : '';\n }\n const params = new URLSearchParams();\n Object.entries(q).forEach(([k, v]) => {\n if (v !== undefined) {\n params.append(k, String(v));\n }\n });\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n","import type { RequestOptions as ReqOpts } from './types';\n\n/**\n * Extended RequestInit with URL override capability for query-based auth.\n */\nexport interface AuthContext {\n url: string;\n init: RequestInit & { __urlOverride?: string };\n options?: ReqOpts;\n}\n\n/**\n * Interface for authentication providers.\n * Implement this to create custom authentication strategies.\n *\n * @example\n * ```ts\n * class CustomAuth implements AuthProvider {\n * async apply({ init }) {\n * init.headers = { ...init.headers, 'X-Custom-Auth': 'token' };\n * }\n * }\n * ```\n */\nexport interface AuthProvider {\n /**\n * Apply authentication to the outgoing request.\n * Called after SDK headers are assembled, but before request is sent.\n *\n * @param req - Request context including URL, init, and options\n */\n apply(req: AuthContext): Promise<void> | void;\n}\n\n/**\n * No-op authentication provider (no authentication applied).\n * Use this when you don't need authentication.\n */\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\n/**\n * API Key authentication provider.\n * Supports both header-based and query parameter-based authentication.\n *\n * @example\n * ```ts\n * // Header-based\n * const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });\n *\n * // Query parameter-based\n * const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });\n * ```\n */\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {\n if (!opts.header && !opts.query) {\n throw new Error('ApiKeyAuth requires either \"header\" or \"query\" option');\n }\n if (opts.header && opts.query) {\n throw new Error('ApiKeyAuth cannot use both \"header\" and \"query\" options');\n }\n }\n apply({ url, init }: AuthContext) {\n if (this.opts.header) {\n init.headers = { ...(init.headers as any), [this.opts.header]: this.opts.value };\n } else if (this.opts.query) {\n const u = new URL(url);\n u.searchParams.set(this.opts.query, this.opts.value);\n init.__urlOverride = u.toString();\n }\n }\n}\n\n/**\n * Bearer token authentication provider.\n * Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).\n *\n * @example\n * ```ts\n * // Static token\n * const auth = new BearerTokenAuth(() => 'my-token');\n *\n * // Dynamic token with refresh\n * const auth = new BearerTokenAuth(async () => {\n * return await refreshAccessToken();\n * });\n * ```\n */\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: AuthContext) {\n const token = await this.getToken();\n if (!token) {\n throw new Error('BearerTokenAuth: token is empty or undefined');\n }\n init.headers = { ...(init.headers as any), Authorization: `Bearer ${token}` };\n }\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\n/**\n * Safely parse data with a Zod schema without throwing.\n * Returns a result object with success status and data or error.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Result object with success flag and data/error\n *\n * @example\n * ```ts\n * const result = safeParse(UserSchema, userData);\n * if (result.success) {\n * console.log(result.data);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport function safeParse<T>(schema: z.ZodType, data: unknown): SafeParseResult<T> {\n const res = schema.safeParse(data);\n if (res.success) return { success: true, data: res.data as T };\n return { success: false, error: res.error };\n}\n\n/**\n * Parse data with a Zod schema, throwing an ApiError on validation failure.\n * Use this when you want to fail fast on invalid data.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {ApiError} If validation fails\n *\n * @example\n * ```ts\n * try {\n * const user = parseOrThrow(UserSchema, userData);\n * console.log(user);\n * } catch (error) {\n * if (error instanceof ApiError && error.zodError) {\n * console.error('Validation failed:', error.zodError.issues);\n * }\n * }\n * ```\n */\nexport function parseOrThrow<T>(schema: z.ZodType, data: unknown): T {\n const res = schema.safeParse(data);\n if (!res.success) {\n throw new ApiError('Response validation failed', { zodError: res.error });\n }\n return res.data as T;\n}\n","/**\n * Log levels for structured logging.\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Structured log entry with metadata.\n */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/**\n * Logger interface for custom logger implementations.\n * Implement this to integrate with your logging infrastructure.\n *\n * @example\n * ```ts\n * class ConsoleLogger implements Logger {\n * log(entry: LogEntry) {\n * console.log(JSON.stringify(entry));\n * }\n * }\n * ```\n */\nexport interface Logger {\n log(entry: LogEntry): void;\n}\n\n/**\n * Default console logger implementation.\n * Formats log entries as JSON for easy parsing.\n */\nexport class ConsoleLogger implements Logger {\n constructor(private minLevel: LogLevel = LogLevel.INFO) {}\n\n log(entry: LogEntry): void {\n const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];\n const entryLevelIndex = levels.indexOf(entry.level);\n const minLevelIndex = levels.indexOf(this.minLevel);\n\n if (entryLevelIndex < minLevelIndex) return;\n\n const output = {\n ...entry,\n error: entry.error\n ? {\n message: entry.error.message,\n stack: entry.error.stack,\n name: entry.error.name,\n }\n : undefined,\n };\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(JSON.stringify(output));\n break;\n case LogLevel.INFO:\n console.info(JSON.stringify(output));\n break;\n case LogLevel.WARN:\n console.warn(JSON.stringify(output));\n break;\n case LogLevel.ERROR:\n console.error(JSON.stringify(output));\n break;\n }\n }\n}\n\n/**\n * No-op logger that discards all log entries.\n * Use this in production if you don't want any logging.\n */\nexport class NoOpLogger implements Logger {\n log(_entry: LogEntry): void {\n // no-op\n }\n}\n\n/**\n * Utility class for creating structured log entries.\n */\nexport class LoggerUtil {\n constructor(private logger: Logger) {}\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.DEBUG,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.INFO,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.WARN,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n error(message: string, error?: Error, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.ERROR,\n message,\n timestamp: new Date().toISOString(),\n context,\n error,\n });\n }\n}\n","/**\n * Metrics data for HTTP requests.\n */\nexport interface RequestMetrics {\n method: string;\n path: string;\n status?: number;\n durationMs: number;\n timestamp: string;\n success: boolean;\n error?: string;\n}\n\n/**\n * Interface for metrics collectors.\n * Implement this to integrate with your monitoring infrastructure (DataDog, Prometheus, etc.).\n *\n * @example\n * ```ts\n * class DataDogMetrics implements MetricsCollector {\n * collect(metrics: RequestMetrics) {\n * dogstatsd.histogram('http.request.duration', metrics.durationMs, {\n * method: metrics.method,\n * status: String(metrics.status)\n * });\n * }\n * }\n * ```\n */\nexport interface MetricsCollector {\n collect(metrics: RequestMetrics): void;\n}\n\n/**\n * No-op metrics collector that discards all metrics.\n */\nexport class NoOpMetricsCollector implements MetricsCollector {\n collect(_metrics: RequestMetrics): void {\n // no-op\n }\n}\n\n/**\n * In-memory metrics collector for testing and development.\n * Stores metrics in memory with configurable retention.\n */\nexport class InMemoryMetricsCollector implements MetricsCollector {\n private metrics: RequestMetrics[] = [];\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n collect(metrics: RequestMetrics): void {\n this.metrics.push(metrics);\n if (this.metrics.length > this.maxEntries) {\n this.metrics.shift();\n }\n }\n\n /**\n * Get all collected metrics.\n */\n getMetrics(): RequestMetrics[] {\n return [...this.metrics];\n }\n\n /**\n * Get metrics summary statistics.\n */\n getSummary(): {\n total: number;\n successful: number;\n failed: number;\n avgDurationMs: number;\n minDurationMs: number;\n maxDurationMs: number;\n } {\n if (this.metrics.length === 0) {\n return {\n total: 0,\n successful: 0,\n failed: 0,\n avgDurationMs: 0,\n minDurationMs: 0,\n maxDurationMs: 0,\n };\n }\n\n const successful = this.metrics.filter((m) => m.success).length;\n const durations = this.metrics.map((m) => m.durationMs);\n const sum = durations.reduce((a, b) => a + b, 0);\n\n return {\n total: this.metrics.length,\n successful,\n failed: this.metrics.length - successful,\n avgDurationMs: sum / this.metrics.length,\n minDurationMs: Math.min(...durations),\n maxDurationMs: Math.max(...durations),\n };\n }\n\n /**\n * Clear all collected metrics.\n */\n clear(): void {\n this.metrics = [];\n }\n}\n\n/**\n * Console-based metrics collector for debugging.\n */\nexport class ConsoleMetricsCollector implements MetricsCollector {\n collect(metrics: RequestMetrics): void {\n console.log('[METRICS]', JSON.stringify(metrics));\n }\n}\n","import type { AuthProvider } from '../auth';\nimport { NoAuth } from '../auth';\nimport { LoggerUtil, NoOpLogger } from '../logger';\nimport { MetricsCollector, NoOpMetricsCollector } from '../metrics';\nimport {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\n\n/**\n * HTTP client with built-in retry logic, authentication, and interceptors.\n * Supports multiple base URLs, type-safe requests, and comprehensive error handling.\n *\n * @example\n * ```ts\n * const client = new HttpClient({\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'Content-Type': 'application/json' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * });\n *\n * const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });\n * ```\n */\nexport class HttpClient {\n private fetchImpl: FetchLike;\n private baseUrls: ClientOptions['baseUrls'];\n private headers: Record<string, string>;\n private interceptors: Interceptors;\n private retry: RetryStrategy;\n private timeoutMs?: number;\n private auth: AuthProvider;\n private logger: LoggerUtil;\n private metrics: MetricsCollector;\n\n /**\n * Creates a new HTTP client instance.\n *\n * @param opts - Client configuration options\n * @throws {Error} If no fetch implementation is available\n */\n constructor(opts: ClientOptions) {\n this.fetchImpl = opts.fetch ?? (globalThis.fetch?.bind(globalThis) as FetchLike);\n if (!this.fetchImpl)\n throw new Error('No fetch implementation found. Pass one via options.fetch.');\n\n // Validate baseUrls configuration\n if (!opts.baseUrls || typeof opts.baseUrls !== 'object') {\n throw new Error('baseUrls must be provided and must be an object');\n }\n if (!opts.baseUrls.default) {\n throw new Error('baseUrls must include a \"default\" key');\n }\n\n this.baseUrls = opts.baseUrls;\n this.headers = opts.headers ?? { 'Content-Type': 'application/json' };\n this.interceptors = opts.interceptors ?? {};\n this.retry = opts.retry ?? {\n maxRetries: 2,\n baseDelayMs: 250,\n jitter: 0.2,\n retryMethods: ['GET', 'HEAD'],\n };\n\n // Validate retry configuration\n if (this.retry.maxRetries < 0) {\n throw new Error('retry.maxRetries must be non-negative');\n }\n if (this.retry.baseDelayMs < 0) {\n throw new Error('retry.baseDelayMs must be non-negative');\n }\n if (this.retry.jitter !== undefined && (this.retry.jitter < 0 || this.retry.jitter > 1)) {\n throw new Error('retry.jitter must be between 0 and 1');\n }\n\n this.timeoutMs = opts.timeout?.requestTimeoutMs;\n if (this.timeoutMs !== undefined && this.timeoutMs < 0) {\n throw new Error('timeout.requestTimeoutMs must be non-negative');\n }\n\n this.auth = opts['auth'] ?? new NoAuth();\n this.logger = new LoggerUtil(opts.logger ?? new NoOpLogger());\n this.metrics = opts.metrics ?? new NoOpMetricsCollector();\n }\n\n /**\n * Set or update the authentication provider.\n *\n * @param auth - Authentication provider instance\n * @example\n * ```ts\n * client.setAuth(new BearerTokenAuth(() => getToken()));\n * ```\n */\n setAuth(auth: AuthProvider) {\n this.auth = auth;\n }\n\n private resolveBaseUrl(key?: keyof typeof this.baseUrls) {\n const k: string = (key as string) || 'default';\n const url = this.baseUrls[k];\n if (!url) {\n const availableKeys = Object.keys(this.baseUrls).join(', ');\n throw new Error(`Unknown baseUrl key: \"${k}\". Available keys: ${availableKeys}`);\n }\n return url.replace(/\\/$/, '');\n }\n\n /**\n * Sleep for a specified duration (used for retry backoff).\n * @private\n */\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\n\n /**\n * Execute a function with retry logic and exponential backoff.\n * @private\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean\n ): Promise<T> {\n let attempt = 0;\n const { maxRetries, baseDelayMs, jitter = 0.2 } = this.retry;\n while (true) {\n try {\n return await fn();\n } catch (err: unknown) {\n if (attempt >= maxRetries || !canRetry({ attempt, error: err })) throw err;\n const backoff = baseDelayMs * 2 ** attempt;\n const j = 1 + (Math.random() * 2 - 1) * jitter;\n await this.sleep(backoff * j);\n attempt++;\n }\n }\n }\n\n /**\n * Run all registered before-request hooks.\n * @private\n */\n private async runBeforeHooks(url: string, init: RequestInit & { __urlOverride?: string }) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\n\n /**\n * Run all registered after-response hooks.\n * @private\n */\n private async runAfterHooks(req: Request, res: Response, parsed?: unknown) {\n for (const h of this.interceptors.afterResponse ?? []) {\n await h({ request: req, response: res, parsed });\n }\n }\n\n /**\n * Make an HTTP request with automatic retry, authentication, and validation.\n *\n * @param method - HTTP method (GET, POST, PUT, etc.)\n * @param path - Request path (will be appended to base URL)\n * @param body - Request body (will be JSON.stringify'd if Content-Type is json)\n * @param options - Additional request options (headers, query params, etc.)\n * @returns Promise resolving to response data and Response object\n * @throws {ApiError} If request fails or response validation fails\n *\n * @example\n * ```ts\n * const { data, response } = await client.request('GET', '/users', undefined, {\n * query: { page: 1, limit: 10 },\n * headers: { 'X-Custom': 'value' }\n * });\n * ```\n */\n async request<T = unknown>(\n method: keyof typeof HTTPMethod,\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n const startTime = Date.now();\n const base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\n\n this.logger.debug('HTTP request initiated', {\n method,\n path,\n baseUrlKey: options?.baseUrlKey,\n hasBody: body !== undefined,\n });\n\n const headers = { ...this.headers, ...(options?.headers ?? {}) };\n\n const controller = new AbortController();\n const signal = options?.signal ?? controller.signal;\n const init: RequestInit & { __urlOverride?: string } = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : String(body)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if (init.__urlOverride) url = init.__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: NodeJS.Timeout | number | undefined;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(() => {\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n controller.abort(timeoutError);\n }, this.timeoutMs);\n }\n\n try {\n const req = new Request(url, init);\n\n const res = await this.fetchImpl(req);\n if (!res.ok) {\n // Read response safely\n let text = '';\n try {\n text = await res.text();\n } catch (readError) {\n text = `Failed to read response: ${readError instanceof Error ? readError.message : String(readError)}`;\n }\n throw new ApiError(`HTTP ${res.status}: ${res.statusText}`, {\n status: res.status,\n details: text,\n });\n }\n const contentType = res.headers.get('content-type') || '';\n const data = contentType.includes('json') ? await res.json() : await res.text();\n await this.runAfterHooks(new Request(url, init), res, data);\n\n const duration = Date.now() - startTime;\n this.logger.info('HTTP request successful', {\n method,\n url,\n status: res.status,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: res.status,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: true,\n });\n\n return { data: data as T, response: res };\n } catch (error) {\n const duration = Date.now() - startTime;\n this.logger.error('HTTP request failed', error as Error, {\n method,\n url,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: error instanceof ApiError ? error.status : undefined,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n response,\n error,\n }: {\n response?: Response;\n error?: unknown;\n attempt: number;\n }) => {\n // Don't retry timeouts or aborts\n if (error && typeof error === 'object' && 'name' in error) {\n const errorName = (error as { name?: string }).name;\n if (errorName === 'AbortError' || errorName === 'TimeoutError') return false;\n }\n // Retry on network errors or 5xx\n if (error instanceof ApiError && error.status && error.status >= 500) return true;\n if (error && !response) return true; // network error\n return false;\n };\n\n if (!this.retry.retryMethods?.includes(method)) {\n return doFetch();\n }\n return this.withRetry(doFetch, canRetry);\n }\n\n /**\n * Convenience method for GET requests.\n *\n * @example\n * ```ts\n * const { data } = await client.get('/users', { query: { page: 1 } });\n * ```\n */\n async get<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n /**\n * Convenience method for POST requests.\n *\n * @example\n * ```ts\n * const { data } = await client.post('/users', { name: 'John' });\n * ```\n */\n async post<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n return this.request<T>('POST', path, body, options);\n }\n\n /**\n * Convenience method for PUT requests.\n *\n * @example\n * ```ts\n * const { data } = await client.put('/users/1', { name: 'John Updated' });\n * ```\n */\n async put<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n return this.request<T>('PUT', path, body, options);\n }\n\n /**\n * Convenience method for PATCH requests.\n *\n * @example\n * ```ts\n * const { data } = await client.patch('/users/1', { name: 'John' });\n * ```\n */\n async patch<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n return this.request<T>('PATCH', path, body, options);\n }\n\n /**\n * Convenience method for DELETE requests.\n *\n * @example\n * ```ts\n * const { data } = await client.delete('/users/1');\n * ```\n */\n async delete<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; response: Response }> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n}\n","import { z } from 'zod';\nimport { HttpClient } from '../http/http-client';\nimport { HTTPMethod } from '../types';\nimport { parseOrThrow } from '../validation';\n\n/**\n * Request configuration for endpoint calls.\n * Wrapper object containing all request parameters.\n *\n * @template ReqSchema - Zod schema for request validation\n * @template PathParams - Type for path parameters\n * @template QueryParams - Type for query parameters\n */\nexport type EndpointCallConfig<\n ReqSchema extends z.ZodType,\n PathParams = never,\n QueryParams = never,\n> = {\n /** Request body data (for POST, PUT, PATCH, etc.) or request args */\n data?: z.infer<ReqSchema>;\n /** Path parameters for dynamic path construction */\n pathParams?: PathParams;\n /** Query string parameters */\n query?: QueryParams;\n /** Request headers */\n headers?: Record<string, string>;\n /** Override base URL for this call */\n baseUrlKey?: string;\n /** Abort controller signal for cancellation */\n signal?: globalThis.AbortSignal;\n};\n\n/**\n * Generic, strongly-typed endpoint with Zod schemas for request and response validation.\n * Extend this class to create type-safe API endpoints.\n *\n * @template ReqSchema - Zod schema for request validation\n * @template ResSchema - Zod schema for response validation\n * @template PathParams - Type for path parameters (optional)\n * @template QueryParams - Type for query parameters (optional)\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ id: z.number(), name: z.string() });\n * const CreateUserSchema = z.object({ name: z.string() });\n *\n * type UserPathParams = { id: string };\n * type UserQueryParams = { include?: string; limit?: number };\n *\n * class GetUser extends BaseEndpoint<\n * typeof CreateUserSchema,\n * typeof UserSchema,\n * UserPathParams,\n * UserQueryParams\n * > {\n * protected method = 'GET' as const;\n * protected path = (params: UserPathParams) => `/users/${params.id}`;\n *\n * constructor(client: HttpClient) {\n * super(client, {\n * requestSchema: CreateUserSchema,\n * responseSchema: UserSchema\n * });\n * }\n * }\n *\n * // Usage:\n * const user = await endpoint.call({\n * pathParams: { id: '123' },\n * query: { include: 'posts', limit: 10 }\n * });\n * ```\n */\nexport abstract class BaseEndpoint<\n ReqSchema extends z.ZodType,\n ResSchema extends z.ZodType,\n PathParams = never,\n QueryParams = never,\n> {\n /** HTTP method for this endpoint */\n protected abstract readonly method: keyof typeof HTTPMethod;\n /** URL path (can be a function for dynamic paths) */\n protected abstract readonly path: string | ((params: PathParams) => string);\n /** Additional options for the request */\n protected readonly options?: {\n /** Override base URL for this call */\n baseUrlKey?: string;\n };\n /** Optional request schema for validation */\n protected readonly requestSchema?: ReqSchema;\n /** Response schema for validation */\n protected readonly responseSchema: ResSchema;\n\n /**\n * @param client - HttpClient instance\n * @param cfg - Configuration with request and response schemas\n */\n constructor(\n protected client: HttpClient,\n cfg: {\n requestSchema?: ReqSchema;\n responseSchema: ResSchema;\n }\n ) {\n this.requestSchema = cfg.requestSchema;\n this.responseSchema = cfg.responseSchema;\n }\n\n /**\n * Call the endpoint with strong typing derived from schemas.\n * Validates request data before sending and response data after receiving.\n *\n * @param config - Request configuration object containing all parameters\n * @returns Promise resolving to validated response data (typed by ResSchema)\n * @throws {ZodError} If request validation fails\n * @throws {ApiError} If response validation fails or request fails\n *\n * @example\n * ```ts\n * const endpoint = new GetUser(client);\n * const user = await endpoint.call({\n * pathParams: { id: '123' },\n * query: { include: 'posts' }\n * });\n * // With additional options:\n * const user = await endpoint.call({\n * data: { name: 'John' },\n * pathParams: { id: '123' },\n * headers: { 'X-Custom': 'value' },\n * query: { include: 'posts' }\n * });\n * ```\n */\n async call(\n config: EndpointCallConfig<ReqSchema, PathParams, QueryParams> = {} as EndpointCallConfig<\n ReqSchema,\n PathParams,\n QueryParams\n >\n ): Promise<z.infer<ResSchema>> {\n const { data, query, headers, baseUrlKey, signal, pathParams } = config;\n\n // Validate request body/params before sending (when schema provided)\n if (this.requestSchema && data !== undefined) {\n const parsed = this.requestSchema.safeParse(data);\n if (!parsed.success) throw parsed.error;\n }\n\n // Build path - use pathParams if provided, otherwise use data for backwards compatibility\n const pathArgs = (pathParams ?? data) as PathParams;\n const path = typeof this.path === 'function' ? this.path(pathArgs) : this.path;\n\n // For GET/HEAD methods, don't send body\n const shouldHaveBody = this.method !== 'GET' && this.method !== 'HEAD';\n const body = shouldHaveBody ? data : undefined;\n\n // Convert query params to the format expected by http-client\n const queryForRequest = query as\n | Record<string, string | number | boolean | undefined>\n | URLSearchParams\n | undefined;\n\n const { data: responseData } = await this.client.request(this.method, path, body, {\n query: queryForRequest,\n headers,\n baseUrlKey: baseUrlKey ?? this.options?.baseUrlKey,\n signal,\n });\n\n return parseOrThrow<z.infer<ResSchema>>(this.responseSchema, responseData);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Common ID type that supports strings, numbers, or UUIDs.\n * Use this for entity identifiers in your schemas.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ id: Id, name: z.string() });\n * ```\n */\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type IdType = z.infer<typeof Id>;\n\n/**\n * Common timestamp fields for entities.\n * Use this for database models with creation/update tracking.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({\n * id: Id,\n * name: z.string(),\n * ...Timestamps.shape\n * });\n * ```\n */\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\n/**\n * Metadata information typically included in API responses.\n * Contains request tracking and debugging information.\n */\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\n/**\n * Detailed error information for a specific field or path.\n */\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\n/**\n * Standard API error response schema.\n * Use this for consistent error handling across your API.\n */\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\n/**\n * Generic envelope wrapper for API responses.\n * Provides consistent structure with success flag, data, error, and metadata.\n *\n * @param inner - Zod schema for the response data\n * @returns Envelope schema wrapping the inner schema\n *\n * @example\n * ```ts\n * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));\n *\n * // Response structure:\n * // {\n * // success: true,\n * // data: { id: 1, name: 'John' },\n * // meta: { requestId: '...' }\n * // }\n * ```\n */\nexport const Envelope = <T extends z.ZodType>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional().nullable(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export * from './auth';
|
|
|
3
3
|
export * from './validation';
|
|
4
4
|
export * from './logger';
|
|
5
5
|
export * from './metrics';
|
|
6
|
-
export { HttpClient } from './http/
|
|
7
|
-
export { BaseEndpoint } from './endpoint/
|
|
6
|
+
export { HttpClient } from './http/http-client';
|
|
7
|
+
export { BaseEndpoint, type EndpointCallConfig } from './endpoint/base-endpoint';
|
|
8
8
|
export * from './schemas/common';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AACA,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAG1B,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAGjF,cAAc,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ const HTTPMethod = {
|
|
|
13
13
|
/**
|
|
14
14
|
* Custom error class for API-related errors.
|
|
15
15
|
* Includes HTTP status codes, response details, and validation errors.
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* @example
|
|
18
18
|
* ```ts
|
|
19
19
|
* throw new ApiError('Invalid request', {
|
|
@@ -79,10 +79,10 @@ const PaginationSchema = z.object({
|
|
|
79
79
|
/**
|
|
80
80
|
* Converts query parameters to a URL query string.
|
|
81
81
|
* Filters out undefined values automatically.
|
|
82
|
-
*
|
|
82
|
+
*
|
|
83
83
|
* @param q - Query parameters as URLSearchParams or object
|
|
84
84
|
* @returns Query string with leading '?' or empty string
|
|
85
|
-
*
|
|
85
|
+
*
|
|
86
86
|
* @example
|
|
87
87
|
* ```ts
|
|
88
88
|
* toQueryString({ page: 1, filter: 'active' }) // "?page=1&filter=active"
|
|
@@ -115,12 +115,12 @@ var NoAuth = class {
|
|
|
115
115
|
/**
|
|
116
116
|
* API Key authentication provider.
|
|
117
117
|
* Supports both header-based and query parameter-based authentication.
|
|
118
|
-
*
|
|
118
|
+
*
|
|
119
119
|
* @example
|
|
120
120
|
* ```ts
|
|
121
121
|
* // Header-based
|
|
122
122
|
* const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });
|
|
123
|
-
*
|
|
123
|
+
*
|
|
124
124
|
* // Query parameter-based
|
|
125
125
|
* const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });
|
|
126
126
|
* ```
|
|
@@ -146,12 +146,12 @@ var ApiKeyAuth = class {
|
|
|
146
146
|
/**
|
|
147
147
|
* Bearer token authentication provider.
|
|
148
148
|
* Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).
|
|
149
|
-
*
|
|
149
|
+
*
|
|
150
150
|
* @example
|
|
151
151
|
* ```ts
|
|
152
152
|
* // Static token
|
|
153
153
|
* const auth = new BearerTokenAuth(() => 'my-token');
|
|
154
|
-
*
|
|
154
|
+
*
|
|
155
155
|
* // Dynamic token with refresh
|
|
156
156
|
* const auth = new BearerTokenAuth(async () => {
|
|
157
157
|
* return await refreshAccessToken();
|
|
@@ -177,11 +177,11 @@ var BearerTokenAuth = class {
|
|
|
177
177
|
/**
|
|
178
178
|
* Safely parse data with a Zod schema without throwing.
|
|
179
179
|
* Returns a result object with success status and data or error.
|
|
180
|
-
*
|
|
180
|
+
*
|
|
181
181
|
* @param schema - Zod schema to validate against
|
|
182
182
|
* @param data - Data to validate
|
|
183
183
|
* @returns Result object with success flag and data/error
|
|
184
|
-
*
|
|
184
|
+
*
|
|
185
185
|
* @example
|
|
186
186
|
* ```ts
|
|
187
187
|
* const result = safeParse(UserSchema, userData);
|
|
@@ -206,12 +206,12 @@ function safeParse(schema, data) {
|
|
|
206
206
|
/**
|
|
207
207
|
* Parse data with a Zod schema, throwing an ApiError on validation failure.
|
|
208
208
|
* Use this when you want to fail fast on invalid data.
|
|
209
|
-
*
|
|
209
|
+
*
|
|
210
210
|
* @param schema - Zod schema to validate against
|
|
211
211
|
* @param data - Data to validate
|
|
212
212
|
* @returns Validated and typed data
|
|
213
213
|
* @throws {ApiError} If validation fails
|
|
214
|
-
*
|
|
214
|
+
*
|
|
215
215
|
* @example
|
|
216
216
|
* ```ts
|
|
217
217
|
* try {
|
|
@@ -400,11 +400,11 @@ var ConsoleMetricsCollector = class {
|
|
|
400
400
|
};
|
|
401
401
|
|
|
402
402
|
//#endregion
|
|
403
|
-
//#region lib/http/
|
|
403
|
+
//#region lib/http/http-client.ts
|
|
404
404
|
/**
|
|
405
405
|
* HTTP client with built-in retry logic, authentication, and interceptors.
|
|
406
406
|
* Supports multiple base URLs, type-safe requests, and comprehensive error handling.
|
|
407
|
-
*
|
|
407
|
+
*
|
|
408
408
|
* @example
|
|
409
409
|
* ```ts
|
|
410
410
|
* const client = new HttpClient({
|
|
@@ -413,7 +413,7 @@ var ConsoleMetricsCollector = class {
|
|
|
413
413
|
* retry: { maxRetries: 3, baseDelayMs: 1000 },
|
|
414
414
|
* timeout: { requestTimeoutMs: 30000 }
|
|
415
415
|
* });
|
|
416
|
-
*
|
|
416
|
+
*
|
|
417
417
|
* const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });
|
|
418
418
|
* ```
|
|
419
419
|
*/
|
|
@@ -429,7 +429,7 @@ var HttpClient = class {
|
|
|
429
429
|
metrics;
|
|
430
430
|
/**
|
|
431
431
|
* Creates a new HTTP client instance.
|
|
432
|
-
*
|
|
432
|
+
*
|
|
433
433
|
* @param opts - Client configuration options
|
|
434
434
|
* @throws {Error} If no fetch implementation is available
|
|
435
435
|
*/
|
|
@@ -458,7 +458,7 @@ var HttpClient = class {
|
|
|
458
458
|
}
|
|
459
459
|
/**
|
|
460
460
|
* Set or update the authentication provider.
|
|
461
|
-
*
|
|
461
|
+
*
|
|
462
462
|
* @param auth - Authentication provider instance
|
|
463
463
|
* @example
|
|
464
464
|
* ```ts
|
|
@@ -527,14 +527,14 @@ var HttpClient = class {
|
|
|
527
527
|
}
|
|
528
528
|
/**
|
|
529
529
|
* Make an HTTP request with automatic retry, authentication, and validation.
|
|
530
|
-
*
|
|
530
|
+
*
|
|
531
531
|
* @param method - HTTP method (GET, POST, PUT, etc.)
|
|
532
532
|
* @param path - Request path (will be appended to base URL)
|
|
533
533
|
* @param body - Request body (will be JSON.stringify'd if Content-Type is json)
|
|
534
534
|
* @param options - Additional request options (headers, query params, etc.)
|
|
535
535
|
* @returns Promise resolving to response data and Response object
|
|
536
536
|
* @throws {ApiError} If request fails or response validation fails
|
|
537
|
-
*
|
|
537
|
+
*
|
|
538
538
|
* @example
|
|
539
539
|
* ```ts
|
|
540
540
|
* const { data, response } = await client.request('GET', '/users', undefined, {
|
|
@@ -649,7 +649,7 @@ var HttpClient = class {
|
|
|
649
649
|
}
|
|
650
650
|
/**
|
|
651
651
|
* Convenience method for GET requests.
|
|
652
|
-
*
|
|
652
|
+
*
|
|
653
653
|
* @example
|
|
654
654
|
* ```ts
|
|
655
655
|
* const { data } = await client.get('/users', { query: { page: 1 } });
|
|
@@ -660,7 +660,7 @@ var HttpClient = class {
|
|
|
660
660
|
}
|
|
661
661
|
/**
|
|
662
662
|
* Convenience method for POST requests.
|
|
663
|
-
*
|
|
663
|
+
*
|
|
664
664
|
* @example
|
|
665
665
|
* ```ts
|
|
666
666
|
* const { data } = await client.post('/users', { name: 'John' });
|
|
@@ -671,7 +671,7 @@ var HttpClient = class {
|
|
|
671
671
|
}
|
|
672
672
|
/**
|
|
673
673
|
* Convenience method for PUT requests.
|
|
674
|
-
*
|
|
674
|
+
*
|
|
675
675
|
* @example
|
|
676
676
|
* ```ts
|
|
677
677
|
* const { data } = await client.put('/users/1', { name: 'John Updated' });
|
|
@@ -682,7 +682,7 @@ var HttpClient = class {
|
|
|
682
682
|
}
|
|
683
683
|
/**
|
|
684
684
|
* Convenience method for PATCH requests.
|
|
685
|
-
*
|
|
685
|
+
*
|
|
686
686
|
* @example
|
|
687
687
|
* ```ts
|
|
688
688
|
* const { data } = await client.patch('/users/1', { name: 'John' });
|
|
@@ -693,7 +693,7 @@ var HttpClient = class {
|
|
|
693
693
|
}
|
|
694
694
|
/**
|
|
695
695
|
* Convenience method for DELETE requests.
|
|
696
|
-
*
|
|
696
|
+
*
|
|
697
697
|
* @example
|
|
698
698
|
* ```ts
|
|
699
699
|
* const { data } = await client.delete('/users/1');
|
|
@@ -705,33 +705,51 @@ var HttpClient = class {
|
|
|
705
705
|
};
|
|
706
706
|
|
|
707
707
|
//#endregion
|
|
708
|
-
//#region lib/endpoint/
|
|
708
|
+
//#region lib/endpoint/base-endpoint.ts
|
|
709
709
|
/**
|
|
710
710
|
* Generic, strongly-typed endpoint with Zod schemas for request and response validation.
|
|
711
711
|
* Extend this class to create type-safe API endpoints.
|
|
712
|
-
*
|
|
712
|
+
*
|
|
713
713
|
* @template ReqSchema - Zod schema for request validation
|
|
714
714
|
* @template ResSchema - Zod schema for response validation
|
|
715
|
-
*
|
|
715
|
+
* @template PathParams - Type for path parameters (optional)
|
|
716
|
+
* @template QueryParams - Type for query parameters (optional)
|
|
717
|
+
*
|
|
716
718
|
* @example
|
|
717
719
|
* ```ts
|
|
718
720
|
* const UserSchema = z.object({ id: z.number(), name: z.string() });
|
|
719
721
|
* const CreateUserSchema = z.object({ name: z.string() });
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
+
*
|
|
723
|
+
* type UserPathParams = { id: string };
|
|
724
|
+
* type UserQueryParams = { include?: string; limit?: number };
|
|
725
|
+
*
|
|
726
|
+
* class GetUser extends BaseEndpoint<
|
|
727
|
+
* typeof CreateUserSchema,
|
|
728
|
+
* typeof UserSchema,
|
|
729
|
+
* UserPathParams,
|
|
730
|
+
* UserQueryParams
|
|
731
|
+
* > {
|
|
722
732
|
* protected method = 'GET' as const;
|
|
723
|
-
* protected path = (
|
|
724
|
-
*
|
|
733
|
+
* protected path = (params: UserPathParams) => `/users/${params.id}`;
|
|
734
|
+
*
|
|
725
735
|
* constructor(client: HttpClient) {
|
|
726
|
-
* super(client, {
|
|
736
|
+
* super(client, {
|
|
727
737
|
* requestSchema: CreateUserSchema,
|
|
728
|
-
* responseSchema: UserSchema
|
|
738
|
+
* responseSchema: UserSchema
|
|
729
739
|
* });
|
|
730
740
|
* }
|
|
731
741
|
* }
|
|
742
|
+
*
|
|
743
|
+
* // Usage:
|
|
744
|
+
* const user = await endpoint.call({
|
|
745
|
+
* pathParams: { id: '123' },
|
|
746
|
+
* query: { include: 'posts', limit: 10 }
|
|
747
|
+
* });
|
|
732
748
|
* ```
|
|
733
749
|
*/
|
|
734
750
|
var BaseEndpoint = class {
|
|
751
|
+
/** Additional options for the request */
|
|
752
|
+
options;
|
|
735
753
|
/** Optional request schema for validation */
|
|
736
754
|
requestSchema;
|
|
737
755
|
/** Response schema for validation */
|
|
@@ -748,37 +766,45 @@ var BaseEndpoint = class {
|
|
|
748
766
|
/**
|
|
749
767
|
* Call the endpoint with strong typing derived from schemas.
|
|
750
768
|
* Validates request data before sending and response data after receiving.
|
|
751
|
-
*
|
|
752
|
-
* @param
|
|
753
|
-
* @param options - Additional request options
|
|
769
|
+
*
|
|
770
|
+
* @param config - Request configuration object containing all parameters
|
|
754
771
|
* @returns Promise resolving to validated response data (typed by ResSchema)
|
|
755
772
|
* @throws {ZodError} If request validation fails
|
|
756
773
|
* @throws {ApiError} If response validation fails or request fails
|
|
757
|
-
*
|
|
774
|
+
*
|
|
758
775
|
* @example
|
|
759
776
|
* ```ts
|
|
760
777
|
* const endpoint = new GetUser(client);
|
|
761
|
-
* const user = await endpoint.call({
|
|
778
|
+
* const user = await endpoint.call({
|
|
779
|
+
* pathParams: { id: '123' },
|
|
780
|
+
* query: { include: 'posts' }
|
|
781
|
+
* });
|
|
782
|
+
* // With additional options:
|
|
783
|
+
* const user = await endpoint.call({
|
|
784
|
+
* data: { name: 'John' },
|
|
785
|
+
* pathParams: { id: '123' },
|
|
786
|
+
* headers: { 'X-Custom': 'value' },
|
|
787
|
+
* query: { include: 'posts' }
|
|
788
|
+
* });
|
|
762
789
|
* ```
|
|
763
790
|
*/
|
|
764
|
-
async call(
|
|
765
|
-
|
|
766
|
-
|
|
791
|
+
async call(config = {}) {
|
|
792
|
+
const { data, query, headers, baseUrlKey, signal, pathParams } = config;
|
|
793
|
+
if (this.requestSchema && data !== void 0) {
|
|
794
|
+
const parsed = this.requestSchema.safeParse(data);
|
|
767
795
|
if (!parsed.success) throw parsed.error;
|
|
768
796
|
}
|
|
769
|
-
const
|
|
770
|
-
const
|
|
771
|
-
const
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
...options,
|
|
779
|
-
query: mergedQuery && Object.keys(mergedQuery).length > 0 ? mergedQuery : options?.query
|
|
797
|
+
const pathArgs = pathParams ?? data;
|
|
798
|
+
const path = typeof this.path === "function" ? this.path(pathArgs) : this.path;
|
|
799
|
+
const body = this.method !== "GET" && this.method !== "HEAD" ? data : void 0;
|
|
800
|
+
const queryForRequest = query;
|
|
801
|
+
const { data: responseData } = await this.client.request(this.method, path, body, {
|
|
802
|
+
query: queryForRequest,
|
|
803
|
+
headers,
|
|
804
|
+
baseUrlKey: baseUrlKey ?? this.options?.baseUrlKey,
|
|
805
|
+
signal
|
|
780
806
|
});
|
|
781
|
-
return parseOrThrow(this.responseSchema,
|
|
807
|
+
return parseOrThrow(this.responseSchema, responseData);
|
|
782
808
|
}
|
|
783
809
|
};
|
|
784
810
|
|
|
@@ -787,7 +813,7 @@ var BaseEndpoint = class {
|
|
|
787
813
|
/**
|
|
788
814
|
* Common ID type that supports strings, numbers, or UUIDs.
|
|
789
815
|
* Use this for entity identifiers in your schemas.
|
|
790
|
-
*
|
|
816
|
+
*
|
|
791
817
|
* @example
|
|
792
818
|
* ```ts
|
|
793
819
|
* const UserSchema = z.object({ id: Id, name: z.string() });
|
|
@@ -801,7 +827,7 @@ const Id = z.union([
|
|
|
801
827
|
/**
|
|
802
828
|
* Common timestamp fields for entities.
|
|
803
829
|
* Use this for database models with creation/update tracking.
|
|
804
|
-
*
|
|
830
|
+
*
|
|
805
831
|
* @example
|
|
806
832
|
* ```ts
|
|
807
833
|
* const UserSchema = z.object({
|
|
@@ -843,14 +869,14 @@ const ApiErrorSchema = z.object({
|
|
|
843
869
|
/**
|
|
844
870
|
* Generic envelope wrapper for API responses.
|
|
845
871
|
* Provides consistent structure with success flag, data, error, and metadata.
|
|
846
|
-
*
|
|
872
|
+
*
|
|
847
873
|
* @param inner - Zod schema for the response data
|
|
848
874
|
* @returns Envelope schema wrapping the inner schema
|
|
849
|
-
*
|
|
875
|
+
*
|
|
850
876
|
* @example
|
|
851
877
|
* ```ts
|
|
852
878
|
* const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));
|
|
853
|
-
*
|
|
879
|
+
*
|
|
854
880
|
* // Response structure:
|
|
855
881
|
* // {
|
|
856
882
|
* // success: true,
|