UNPKG

zodsei

Version:

Contract-first type-safe HTTP client with Zod validation

1 lines 57.8 kB
{"version":3,"sources":["../src/validation.ts","../src/errors.ts","../src/utils/path.ts","../src/middleware/index.ts","../src/adapters/axios.ts","../src/schema.ts","../src/client.ts","../src/types.ts","../src/middleware/retry.ts","../src/middleware/cache.ts","../src/utils/request.ts","../src/index.ts"],"sourcesContent":["import { z } from 'zod';\nimport { ValidationError } from './errors';\n\n/**\n * Validation utility functions\n */\n\n// Validate request data\nexport function validateRequest<T>(schema: z.ZodType<T> | undefined, data: unknown): T {\n if (!schema) {\n return data as T;\n }\n \n try {\n return schema.parse(data);\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw ValidationError.fromZodError(error, 'request');\n }\n throw error;\n }\n}\n\n// Validate response data\nexport function validateResponse<T>(schema: z.ZodType<T> | undefined, data: unknown): T {\n if (!schema) {\n return data as T;\n }\n \n try {\n return schema.parse(data);\n } catch (error) {\n if (error instanceof z.ZodError) {\n throw ValidationError.fromZodError(error, 'response');\n }\n throw error;\n }\n}\n\n// Safe parse (no error throwing)\nexport function safeParseRequest<T>(\n schema: z.ZodType<T> | undefined, \n data: unknown\n): { success: true; data: T } | { success: false; error: ValidationError } {\n if (!schema) {\n return { success: true, data: data as T };\n }\n \n try {\n const result = schema.parse(data);\n return { success: true, data: result };\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: ValidationError.fromZodError(error, 'request') };\n }\n return { \n success: false, \n error: new ValidationError('Unknown validation error', [], 'request') \n };\n }\n}\n\n// Safe parse response\nexport function safeParseResponse<T>(\n schema: z.ZodType<T> | undefined, \n data: unknown\n): { success: true; data: T } | { success: false; error: ValidationError } {\n if (!schema) {\n return { success: true, data: data as T };\n }\n \n try {\n const result = schema.parse(data);\n return { success: true, data: result };\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { success: false, error: ValidationError.fromZodError(error, 'response') };\n }\n return { \n success: false, \n error: new ValidationError('Unknown validation error', [], 'response') \n };\n }\n}\n\n// Create optional validator\nexport function createValidator<T>(schema: z.ZodType<T> | undefined, enabled: boolean) {\n return {\n validateRequest: enabled \n ? (data: unknown) => validateRequest(schema, data)\n : (data: unknown) => data as T,\n \n validateResponse: enabled \n ? (data: unknown) => validateResponse(schema, data)\n : (data: unknown) => data as T,\n \n safeParseRequest: (data: unknown) => safeParseRequest(schema, data),\n safeParseResponse: (data: unknown) => safeParseResponse(schema, data),\n };\n}\n","import { z } from 'zod';\n\n// Base error class\nexport class ZodseiError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'ZodseiError';\n }\n}\n\n// Validation error\nexport class ValidationError extends ZodseiError {\n constructor(\n message: string,\n public readonly issues: z.core.$ZodIssue[],\n public readonly type: 'request' | 'response' = 'request'\n ) {\n super(message, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n\n static fromZodError(\n error: z.ZodError,\n type: 'request' | 'response' = 'request'\n ): ValidationError {\n const message = `${type} validation failed: ${error.issues\n .map((issue) => `${issue.path.join('.')}: ${issue.message}`)\n .join(', ')}`;\n\n return new ValidationError(message, error.issues, type);\n }\n}\n\n// HTTP error\nexport class HttpError extends ZodseiError {\n constructor(\n message: string,\n public readonly status: number,\n public readonly statusText: string,\n public readonly response?: unknown\n ) {\n super(message, 'HTTP_ERROR');\n this.name = 'HttpError';\n }\n\n static fromResponse(response: Response, data?: unknown): HttpError {\n const message = `HTTP ${response.status}: ${response.statusText}`;\n return new HttpError(message, response.status, response.statusText, data);\n }\n}\n\n// Network error\nexport class NetworkError extends ZodseiError {\n constructor(\n message: string,\n public readonly originalError: Error\n ) {\n super(message, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\n// Configuration error\nexport class ConfigError extends ZodseiError {\n constructor(message: string) {\n super(message, 'CONFIG_ERROR');\n this.name = 'ConfigError';\n }\n}\n\n// Timeout error\nexport class TimeoutError extends ZodseiError {\n constructor(timeout: number) {\n super(`Request timeout after ${timeout}ms`, 'TIMEOUT_ERROR');\n this.name = 'TimeoutError';\n }\n}\n","/**\n * Path handling utility functions\n */\n\n// Extract path parameter names\nexport function extractPathParamNames(path: string): string[] {\n const matches = path.match(/:([^/]+)/g);\n return matches ? matches.map((match) => match.slice(1)) : [];\n}\n\n// Replace path parameters\nexport function replacePath(path: string, params: Record<string, string>): string {\n let result = path;\n\n for (const [key, value] of Object.entries(params)) {\n result = result.replace(`:${key}`, encodeURIComponent(value));\n }\n\n return result;\n}\n\n// Build query string\nexport function buildQueryString(params: Record<string, unknown>): string {\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n value.forEach((item) => searchParams.append(key, String(item)));\n } else {\n searchParams.append(key, String(value));\n }\n }\n }\n\n const queryString = searchParams.toString();\n return queryString ? `?${queryString}` : '';\n}\n\n// Build path with optional query string\nexport function buildUrl(path: string, query?: Record<string, unknown>): string {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n const queryString = query ? buildQueryString(query) : '';\n return `${cleanPath}${queryString}`;\n}\n\n// Separate path params and query params\nexport function separateParams(\n path: string,\n data: Record<string, unknown> | null | undefined\n): { pathParams: Record<string, string>; queryParams: Record<string, unknown> } {\n const pathParamNames = extractPathParamNames(path);\n const pathParams: Record<string, string> = {};\n const queryParams: Record<string, unknown> = {};\n\n // Handle null/undefined data\n if (!data) {\n return { pathParams, queryParams };\n }\n\n for (const [key, value] of Object.entries(data)) {\n if (pathParamNames.includes(key)) {\n pathParams[key] = String(value);\n } else {\n queryParams[key] = value;\n }\n }\n\n return { pathParams, queryParams };\n}\n\n// Check if request body is needed\nexport function shouldHaveBody(method: string): boolean {\n return !['GET', 'HEAD', 'DELETE'].includes(method.toUpperCase());\n}\n","import type { Middleware, RequestContext, ResponseContext } from '../types';\n\n/**\n * Middleware system\n */\n\n// Middleware executor\nexport class MiddlewareExecutor {\n constructor(private middleware: Middleware[] = []) {}\n\n // Execute middleware chain\n async execute(\n request: RequestContext,\n finalHandler: (request: RequestContext) => Promise<ResponseContext>\n ): Promise<ResponseContext> {\n if (this.middleware.length === 0) {\n return finalHandler(request);\n }\n\n let index = 0;\n\n const next = async (req: RequestContext): Promise<ResponseContext> => {\n if (index >= this.middleware.length) {\n return finalHandler(req);\n }\n\n const middleware = this.middleware[index++];\n return middleware(req, next);\n };\n\n return next(request);\n }\n\n // Add middleware\n use(middleware: Middleware): void {\n this.middleware.push(middleware);\n }\n\n // Get middleware list\n getMiddleware(): Middleware[] {\n return [...this.middleware];\n }\n}\n\n// Create middleware executor\nexport function createMiddlewareExecutor(middleware: Middleware[] = []): MiddlewareExecutor {\n return new MiddlewareExecutor(middleware);\n}\n\n// Compose multiple middleware\nexport function composeMiddleware(...middleware: Middleware[]): Middleware {\n return async (request, next) => {\n const executor = new MiddlewareExecutor(middleware);\n return executor.execute(request, next);\n };\n}\n","import type { RequestContext, ResponseContext } from '../types';\nimport { HttpError, NetworkError, TimeoutError } from '../errors';\nimport type { AxiosInstance, AxiosRequestConfig } from 'axios';\nimport { isAxiosError } from 'axios';\n\n/**\n * Axios HTTP adapter\n */\nexport class AxiosAdapter {\n readonly name = 'axios';\n private axios: AxiosInstance;\n\n constructor(axiosInstance: AxiosInstance) {\n this.axios = axiosInstance;\n }\n\n // Interceptors are not supported. Use middleware in the client instead.\n\n async request(context: RequestContext): Promise<ResponseContext> {\n try {\n const axiosConfig = this.createAxiosConfig(context);\n\n const response = await this.axios.request(axiosConfig);\n\n const headers: Record<string, string> = (() => {\n const rh = (response.headers ?? {}) as Record<string, unknown>;\n if (!rh) return {};\n try {\n return Object.fromEntries(\n Object.entries(rh).map(([k, v]) => [k, typeof v === 'string' ? v : String(v)])\n );\n } catch {\n return {};\n }\n })();\n\n const responseContext: ResponseContext = {\n status: response.status,\n statusText: response.statusText,\n headers,\n data: response.data,\n };\n\n // Check HTTP status\n if (response.status >= 400) {\n throw new HttpError(\n `HTTP ${response.status}: ${response.statusText}`,\n response.status,\n response.statusText,\n response.data\n );\n }\n\n return responseContext;\n } catch (error: unknown) {\n if (error instanceof HttpError) {\n throw error;\n }\n\n // Handle Axios errors\n if (isAxiosError(error)) {\n if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {\n const to = typeof error.config?.timeout === 'number' ? error.config.timeout : 0;\n throw new TimeoutError(to || 0);\n }\n\n if (error.response) {\n // Server responded with error status code\n throw new HttpError(\n `HTTP ${error.response.status}: ${error.response.statusText}`,\n error.response.status,\n error.response.statusText,\n error.response.data\n );\n } else if (error.request) {\n // Request was made but no response received\n const message = typeof error.message === 'string' ? error.message : 'Request failed';\n throw new NetworkError(`Network request failed: ${message}`, error as Error);\n }\n\n const message = typeof error.message === 'string' ? error.message : 'Axios error';\n throw new NetworkError(`Axios request failed: ${message}`, error as Error);\n }\n\n const message = error instanceof Error ? error.message : 'Unknown error';\n throw new NetworkError(\n `Axios request failed: ${message}`,\n (error as Error) ?? new Error(String(error))\n );\n }\n }\n\n private createAxiosConfig(context: RequestContext): AxiosRequestConfig {\n const config: AxiosRequestConfig = {\n url: context.url,\n method: context.method.toLowerCase() as AxiosRequestConfig['method'],\n headers: {\n 'Content-Type': 'application/json',\n ...context.headers,\n },\n };\n\n // Add request body\n if (context.body !== undefined && !['GET', 'HEAD'].includes(context.method.toUpperCase())) {\n config.data = context.body;\n }\n\n // Add query parameters\n if (context.query && Object.keys(context.query).length > 0) {\n config.params = context.query as Record<string, unknown>;\n }\n\n return config;\n }\n}\n","import { z } from 'zod';\nimport type { Contract, EndpointDefinition } from './types';\n\n/**\n * Schema inference and extraction utilities\n */\n\n/**\n * Extract request type from endpoint definition\n */\nexport type InferRequestType<T extends EndpointDefinition> = \n T['request'] extends z.ZodType ? z.infer<T['request']> : void;\n\n/**\n * Extract response type from endpoint definition\n */\nexport type InferResponseType<T extends EndpointDefinition> = \n T['response'] extends z.ZodType ? z.infer<T['response']> : unknown;\n\n/**\n * Extract all endpoint types from a contract\n */\nexport type InferContractTypes<T extends Contract> = {\n [K in keyof T]: T[K] extends EndpointDefinition\n ? {\n request: InferRequestType<T[K]>;\n response: InferResponseType<T[K]>;\n endpoint: T[K];\n }\n : T[K] extends Contract\n ? InferContractTypes<T[K]>\n : never;\n};\n\n/**\n * Schema extraction utilities\n */\nexport class SchemaExtractor<T extends Contract> {\n constructor(private contract: T) {}\n\n /**\n * Get endpoint definition by path\n */\n getEndpoint<K extends keyof T>(path: K): T[K] extends EndpointDefinition ? T[K] : never {\n const endpoint = this.contract[path];\n if (this.isEndpointDefinition(endpoint)) {\n return endpoint as T[K] extends EndpointDefinition ? T[K] : never;\n }\n throw new Error(`Endpoint \"${String(path)}\" not found or is not a valid endpoint`);\n }\n\n /**\n * Get nested contract by path\n */\n getNested<K extends keyof T>(path: K): T[K] extends Contract ? SchemaExtractor<T[K]> : never {\n const nested = this.contract[path];\n if (this.isNestedContract(nested)) {\n return new SchemaExtractor(nested as T[K] & Contract) as T[K] extends Contract\n ? SchemaExtractor<T[K]>\n : never;\n }\n throw new Error(`Nested contract \"${String(path)}\" not found or is not a valid contract`);\n }\n\n /**\n * Get request schema for an endpoint\n */\n getRequestSchema<K extends keyof T>(\n path: K\n ): T[K] extends EndpointDefinition ? T[K]['request'] : never {\n const endpoint = this.getEndpoint(path);\n return endpoint.request as T[K] extends EndpointDefinition ? T[K]['request'] : never;\n }\n\n /**\n * Get response schema for an endpoint\n */\n getResponseSchema<K extends keyof T>(\n path: K\n ): T[K] extends EndpointDefinition ? T[K]['response'] : never {\n const endpoint = this.getEndpoint(path);\n return endpoint.response as T[K] extends EndpointDefinition ? T[K]['response'] : never;\n }\n\n /**\n * Get all schemas for an endpoint\n */\n getEndpointSchemas<K extends keyof T>(\n path: K\n ): T[K] extends EndpointDefinition\n ? { request: T[K]['request']; response: T[K]['response']; endpoint: T[K] }\n : never {\n const endpoint = this.getEndpoint(path);\n const result = {\n request: endpoint.request,\n response: endpoint.response,\n endpoint: endpoint as T[K] & EndpointDefinition,\n };\n return result as T[K] extends EndpointDefinition\n ? { request: T[K]['request']; response: T[K]['response']; endpoint: T[K] }\n : never;\n }\n\n /**\n * Get all endpoint paths in the contract\n */\n getEndpointPaths(): Array<keyof T> {\n return Object.keys(this.contract).filter((key) =>\n this.isEndpointDefinition(this.contract[key])\n ) as Array<keyof T>;\n }\n\n /**\n * Get all nested contract paths\n */\n getNestedPaths(): Array<keyof T> {\n return Object.keys(this.contract).filter((key) =>\n this.isNestedContract(this.contract[key])\n ) as Array<keyof T>;\n }\n\n /**\n * Generate OpenAPI-like schema description\n */\n describeEndpoint<K extends keyof T>(\n path: K\n ): T[K] extends EndpointDefinition\n ? {\n path: string;\n method: string;\n requestSchema: z.ZodType | undefined;\n responseSchema: z.ZodType | undefined;\n requestType: string;\n responseType: string;\n }\n : never {\n const endpoint = this.getEndpoint(path);\n\n const result = {\n path: endpoint.path,\n method: endpoint.method,\n requestSchema: endpoint.request,\n responseSchema: endpoint.response,\n requestType: endpoint.request ? this.getSchemaDescription(endpoint.request) : 'void',\n responseType: endpoint.response ? this.getSchemaDescription(endpoint.response) : 'unknown',\n };\n\n return result as T[K] extends EndpointDefinition\n ? {\n path: string;\n method: string;\n requestSchema: z.ZodType;\n responseSchema: z.ZodType;\n requestType: string;\n responseType: string;\n }\n : never;\n }\n\n /**\n * Generate schema description for documentation\n */\n private getSchemaDescription(schema: z.ZodType | undefined): string {\n if (!schema) {\n return 'undefined';\n }\n \n try {\n // Try to get a basic description of the schema\n if (schema instanceof z.ZodObject) {\n const shape = schema.shape;\n const fields = Object.keys(shape).map((key) => {\n const field = shape[key] as z.ZodType;\n return `${key}: ${this.getZodTypeDescription(field)}`;\n });\n return `{ ${fields.join(', ')} }`;\n }\n return this.getZodTypeDescription(schema);\n } catch {\n return 'unknown';\n }\n }\n\n /**\n * Get basic Zod type description\n */\n private getZodTypeDescription(schema: z.ZodType): string {\n // Use the _def property to determine the type, which is more reliable\n const meta = schema as unknown as { def?: { typeName?: string; type?: z.ZodType; innerType?: z.ZodType; value?: unknown }; _def?: { typeName?: string; type?: z.ZodType; innerType?: z.ZodType; value?: unknown } };\n const def = meta.def ?? meta._def;\n if (def?.typeName) {\n switch (def.typeName) {\n case 'ZodString': return 'string';\n case 'ZodNumber': return 'number';\n case 'ZodBoolean': return 'boolean';\n case 'ZodArray': \n return def.type ? `${this.getZodTypeDescription(def.type)}[]` : 'array';\n case 'ZodOptional': \n return def.innerType ? `${this.getZodTypeDescription(def.innerType)}?` : 'optional';\n case 'ZodNullable': \n return def.innerType ? `${this.getZodTypeDescription(def.innerType)} | null` : 'nullable';\n case 'ZodObject': return 'object';\n case 'ZodUnion': return 'union';\n case 'ZodLiteral': return `literal(${JSON.stringify(def.value)})`;\n case 'ZodEnum': return 'enum';\n default: return def.typeName.replace('Zod', '').toLowerCase();\n }\n }\n \n // Fallback to instanceof checks for older versions\n try {\n if (schema instanceof z.ZodString) return 'string';\n if (schema instanceof z.ZodNumber) return 'number';\n if (schema instanceof z.ZodBoolean) return 'boolean';\n if (schema instanceof z.ZodArray) {\n // Safe access to element property\n const element = (schema as z.ZodArray<z.ZodType>).element;\n return element ? `${this.getZodTypeDescription(element)}[]` : 'array';\n }\n if (schema instanceof z.ZodOptional) {\n // Safe access to unwrap method\n const inner = (schema as z.ZodOptional<z.ZodType>).unwrap();\n return inner ? `${this.getZodTypeDescription(inner)}?` : 'optional';\n }\n if (schema instanceof z.ZodNullable) {\n // Safe access to unwrap method\n const inner = (schema as z.ZodNullable<z.ZodType>).unwrap();\n return inner ? `${this.getZodTypeDescription(inner)} | null` : 'nullable';\n }\n if (schema instanceof z.ZodObject) return 'object';\n } catch {\n // Ignore errors and return unknown\n }\n return 'unknown';\n }\n\n /**\n * Check if a value is an endpoint definition\n */\n private isEndpointDefinition(value: unknown): value is EndpointDefinition {\n return (\n Boolean(value) &&\n typeof value === 'object' &&\n value !== null &&\n 'path' in value &&\n 'method' in value\n );\n }\n\n /**\n * Check if a value is a nested contract\n */\n private isNestedContract(value: unknown): value is Contract {\n return (\n Boolean(value) &&\n typeof value === 'object' &&\n value !== null &&\n !this.isEndpointDefinition(value)\n );\n }\n}\n\n/**\n * Create a schema extractor for a contract\n */\nexport function createSchemaExtractor<T extends Contract>(contract: T): SchemaExtractor<T> {\n return new SchemaExtractor(contract);\n}\n\n/**\n * Utility type to infer endpoint method signature\n */\nexport type InferEndpointMethod<T extends EndpointDefinition> = (\n ...args: T['request'] extends z.ZodSchema \n ? [data: InferRequestType<T>] \n : []\n) => Promise<InferResponseType<T>>;\n\n/**\n * Utility to extract type information at runtime\n */\nexport function extractTypeInfo<T extends EndpointDefinition>(endpoint: T) {\n return {\n requestSchema: endpoint.request,\n responseSchema: endpoint.response,\n method: endpoint.method,\n path: endpoint.path,\n hasRequestSchema: Boolean(endpoint.request),\n hasResponseSchema: Boolean(endpoint.response),\n };\n}\n","import {\n Contract,\n EndpointDefinition,\n ClientConfig,\n InternalClientConfig,\n RequestContext,\n ResponseContext,\n ApiClient,\n EndpointMethodWithSchema,\n InferRequestType,\n InferResponseType,\n} from './types';\nimport { validateRequest, validateResponse } from './validation';\nimport { separateParams, buildUrl, replacePath, shouldHaveBody } from './utils/path';\nimport { createMiddlewareExecutor, MiddlewareExecutor } from './middleware';\nimport { AxiosAdapter } from './adapters/axios';\nimport { SchemaExtractor, createSchemaExtractor } from './schema';\n\n/**\n * Zodsei client core implementation\n */\nexport class ZodseiClient<T extends Contract> {\n private readonly contract: T;\n private readonly config: InternalClientConfig;\n private readonly middlewareExecutor: MiddlewareExecutor;\n private adapter: AxiosAdapter | null = null;\n public readonly $schema: SchemaExtractor<T>;\n\n constructor(contract: T, config: ClientConfig) {\n this.contract = contract;\n this.config = this.normalizeConfig(config);\n this.middlewareExecutor = createMiddlewareExecutor(this.config.middleware);\n this.$schema = createSchemaExtractor(contract);\n\n // Create proxy object for dynamic method calls with nested support\n return new Proxy(this, {\n get: (target, prop: string | symbol) => {\n if (typeof prop === 'string') {\n // Check if it's a direct endpoint\n if (prop in this.contract && this.isEndpointDefinition(this.contract[prop])) {\n return this.createEndpointMethod(prop);\n }\n\n // Check if it's a nested contract\n if (prop in this.contract && this.isNestedContract(this.contract[prop])) {\n return this.createNestedClient(this.contract[prop] as Contract);\n }\n }\n return Reflect.get(target as object, prop) as unknown;\n },\n }) as ZodseiClient<T> & ApiClient<T>;\n }\n\n /**\n * Normalize configuration\n */\n private normalizeConfig(config: ClientConfig): InternalClientConfig {\n return {\n validateRequest: config.validateRequest ?? true,\n validateResponse: config.validateResponse ?? true,\n middleware: config.middleware ?? [],\n axios: config.axios,\n };\n }\n\n /**\n * Check if a value is an endpoint definition\n */\n private isEndpointDefinition(value: unknown): value is EndpointDefinition {\n return typeof value === 'object' && value !== null && 'path' in value && 'method' in value;\n }\n\n /**\n * Check if a value is a nested contract\n */\n private isNestedContract(value: unknown): value is Contract {\n return typeof value === 'object' && value !== null && !this.isEndpointDefinition(value);\n }\n\n /**\n * Create nested client for sub-contracts\n */\n private createNestedClient(nestedContract: Contract): ApiClient<Contract> {\n return new Proxy(\n {},\n {\n get: (_target, prop: string | symbol) => {\n if (typeof prop === 'string') {\n // Check if it's a direct endpoint in nested contract\n if (prop in nestedContract && this.isEndpointDefinition(nestedContract[prop])) {\n return this.createEndpointMethod(\n `${prop}`,\n nestedContract[prop] as EndpointDefinition\n );\n }\n\n // Check if it's further nested\n if (prop in nestedContract && this.isNestedContract(nestedContract[prop])) {\n return this.createNestedClient(nestedContract[prop] as Contract);\n }\n }\n return undefined as unknown;\n },\n }\n ) as ApiClient<Contract>;\n }\n\n /**\n * Create endpoint method with schema access\n */\n private createEndpointMethod(endpointName: string, endpoint?: EndpointDefinition) {\n const targetEndpoint = endpoint || (this.contract[endpointName] as EndpointDefinition);\n\n const method = async (...args: unknown[]) => {\n // 如果有 request schema,取第一个参数;否则传 undefined\n const data = targetEndpoint.request ? args[0] : undefined;\n return this.executeEndpoint(targetEndpoint, data) as Promise<\n InferResponseType<typeof targetEndpoint>\n >;\n };\n\n // Attach schema information to the method\n (method as EndpointMethodWithSchema<typeof targetEndpoint>).schema = {\n request: targetEndpoint.request,\n response: targetEndpoint.response,\n endpoint: targetEndpoint,\n };\n\n // Attach type inference helpers (for development/debugging)\n (method as EndpointMethodWithSchema<typeof targetEndpoint>).infer = {\n request: (targetEndpoint.request ? {} : undefined) as InferRequestType<typeof targetEndpoint>,\n response: (targetEndpoint.response ? {} : {}) as InferResponseType<typeof targetEndpoint>,\n };\n\n return method as EndpointMethodWithSchema<typeof targetEndpoint>;\n }\n\n /**\n * Execute endpoint request\n */\n private async executeEndpoint(endpoint: EndpointDefinition, data: unknown): Promise<unknown> {\n // Validate request data\n const validatedData = this.config.validateRequest\n ? validateRequest(endpoint.request, data)\n : data;\n\n // Build request context\n const requestContext = this.buildRequestContext(endpoint, validatedData);\n\n // Execute middleware chain\n const response = await this.middlewareExecutor.execute(requestContext, (ctx) =>\n this.executeHttpRequest(ctx)\n );\n\n // Validate response data\n const validatedResponse = this.config.validateResponse\n ? validateResponse(endpoint.response, response.data)\n : response.data;\n\n return validatedResponse;\n }\n\n /**\n * Build request context\n */\n private buildRequestContext(endpoint: EndpointDefinition, data: unknown): RequestContext {\n const { path, method } = endpoint;\n\n // Separate path params and query params\n const { pathParams, queryParams } = separateParams(\n path,\n typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : undefined\n );\n\n // Replace path parameters\n const finalPath = replacePath(path, pathParams);\n\n // Build URL (relative path; axios instance is responsible for baseURL)\n const url =\n method.toLowerCase() === 'get' ? buildUrl(finalPath, queryParams) : buildUrl(finalPath);\n\n // Determine request body\n const body = shouldHaveBody(method)\n ? method.toLowerCase() === 'get'\n ? undefined\n : data\n : undefined;\n\n return {\n url,\n method,\n headers: {},\n body,\n params: pathParams,\n query: method.toLowerCase() === 'get' ? (queryParams as Record<string, unknown>) : undefined,\n };\n }\n\n /**\n * Get adapter\n */\n private async getAdapter(): Promise<AxiosAdapter> {\n if (!this.adapter) {\n this.adapter = new AxiosAdapter(this.config.axios);\n }\n return this.adapter;\n }\n\n /**\n * Execute HTTP request\n */\n private async executeHttpRequest(context: RequestContext): Promise<ResponseContext> {\n const adapter = await this.getAdapter();\n return adapter.request(context);\n }\n\n /**\n * Get configuration\n */\n public getConfig(): Readonly<InternalClientConfig> {\n return { ...this.config };\n }\n\n /**\n * Get contract\n */\n public getContract(): Readonly<T> {\n return { ...this.contract };\n }\n\n /**\n * Add middleware\n */\n public use(\n middleware: (\n request: RequestContext,\n next: (request: RequestContext) => Promise<ResponseContext>\n ) => Promise<ResponseContext>\n ): void {\n this.middlewareExecutor.use(middleware);\n }\n}\n\n/**\n * Create client with enhanced schema support\n */\nexport function createClient<T extends Contract>(\n contract: T,\n config: ClientConfig\n): ZodseiClient<T> & ApiClient<T> {\n return new ZodseiClient(contract, config) as ZodseiClient<T> & ApiClient<T>;\n}\n","import { z } from 'zod';\nimport type { AxiosInstance } from 'axios';\nimport type { SchemaExtractor } from './schema';\n\n// HTTP method types\nexport type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options';\n\n// Endpoint definition interface\nexport interface EndpointDefinition {\n path: string;\n method: HttpMethod;\n request?: z.ZodType;\n response?: z.ZodType;\n}\n\n// Contract type\n/**\n * Contract definition - can be nested\n */\nexport interface Contract {\n [key: string]: EndpointDefinition | Contract;\n}\n\n/**\n * Helper function to define a contract with proper type inference\n * Preserves literal types while ensuring type safety\n * Supports nested contracts\n */\nexport function defineContract<T extends Contract>(contract: T): T {\n return contract;\n}\n\n/**\n * Create client type from contract - supports nested access with schema support\n */\nexport type ApiClient<T extends Contract> = {\n [K in keyof T]: T[K] extends EndpointDefinition\n ? EndpointMethodWithSchema<T[K]>\n : T[K] extends Contract\n ? ApiClient<T[K]>\n : never;\n} & {\n $schema: SchemaExtractor<T>;\n};\n\n// Base client configuration\ninterface BaseClientConfig {\n validateRequest?: boolean;\n validateResponse?: boolean;\n middleware?: Middleware[];\n}\n\n// Type-safe client configuration with conditional adapterConfig\nexport type ClientConfig = BaseClientConfig & {\n // User must provide an Axios instance\n axios: AxiosInstance;\n};\n\n// Internal configuration type for client implementation\nexport interface InternalClientConfig {\n validateRequest: boolean;\n validateResponse: boolean;\n middleware: Middleware[];\n axios: AxiosInstance;\n}\n\n// Middleware types\nexport type Middleware = (\n request: RequestContext,\n next: (request: RequestContext) => Promise<ResponseContext>\n) => Promise<ResponseContext>;\n\n// Request context\nexport interface RequestContext {\n url: string;\n method: HttpMethod;\n headers: Record<string, string>;\n body?: unknown;\n params?: Record<string, string>;\n query?: Record<string, unknown>;\n}\n\n// Response context\nexport interface ResponseContext {\n status: number;\n statusText: string;\n headers: Record<string, string>;\n data: unknown;\n}\n\n// Path parameter extraction type\nexport type ExtractPathParams<T extends string> =\n T extends `${infer _Start}:${infer Param}/${infer Rest}`\n ? { [K in Param]: string } & ExtractPathParams<`/${Rest}`>\n : T extends `${infer _Start}:${infer Param}`\n ? { [K in Param]: string }\n : object;\n\n// Request data separation type\nexport type SeparateRequestData<T> =\n T extends Record<string, unknown>\n ? {\n pathParams: ExtractPathParams<string>;\n queryParams: Omit<T, keyof ExtractPathParams<string>>;\n body: T;\n }\n : {\n pathParams: object;\n queryParams: object;\n body: T;\n };\n\n// Schema inference types\nexport type InferRequestType<T extends EndpointDefinition> = \n T['request'] extends z.ZodType ? z.infer<T['request']> : void;\n\nexport type InferResponseType<T extends EndpointDefinition> = \n T['response'] extends z.ZodType ? z.infer<T['response']> : unknown;\n\n// Enhanced endpoint method with schema access\nexport interface EndpointMethodWithSchema<T extends EndpointDefinition> {\n (\n ...args: T['request'] extends z.ZodType \n ? [data: InferRequestType<T>] \n : []\n ): Promise<InferResponseType<T>>;\n schema: {\n request: T['request'];\n response: T['response'];\n endpoint: T;\n };\n infer: {\n request: InferRequestType<T>;\n response: InferResponseType<T>;\n };\n}\n\n// Legacy type alias for backward compatibility\nexport type EnhancedApiClient<T extends Contract> = ApiClient<T>;\n","import type { Middleware } from '../types';\nimport { HttpError } from '../errors';\n\n/**\n * Retry middleware configuration\n */\nexport interface RetryConfig {\n retries: number;\n delay: number;\n backoff?: 'linear' | 'exponential';\n retryCondition?: (error: Error) => boolean;\n onRetry?: (attempt: number, error: Error) => void;\n}\n\n// Default retry condition\nfunction defaultRetryCondition(error: Error): boolean {\n if (error instanceof HttpError) {\n // Retry server errors and some client errors\n return error.status >= 500 || error.status === 408 || error.status === 429;\n }\n // Retry network errors\n return true;\n}\n\n// Calculate delay time\nfunction calculateDelay(\n attempt: number,\n baseDelay: number,\n backoff: 'linear' | 'exponential'\n): number {\n switch (backoff) {\n case 'exponential':\n return baseDelay * Math.pow(2, attempt);\n case 'linear':\n default:\n return baseDelay * (attempt + 1);\n }\n}\n\n// Delay function\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Create retry middleware\n */\nexport function retryMiddleware(config: RetryConfig): Middleware {\n const {\n retries,\n delay: baseDelay,\n backoff = 'exponential',\n retryCondition = defaultRetryCondition,\n onRetry,\n } = config;\n\n return async (request, next) => {\n let lastError: Error;\n\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n return await next(request);\n } catch (error) {\n lastError = error as Error;\n\n // If it's the last attempt, throw error directly\n if (attempt === retries) {\n throw lastError;\n }\n\n // Check if should retry\n if (!retryCondition(lastError)) {\n throw lastError;\n }\n\n // Call retry callback\n if (onRetry) {\n onRetry(attempt + 1, lastError);\n }\n\n // Calculate delay and wait\n const delayTime = calculateDelay(attempt, baseDelay, backoff);\n await delay(delayTime);\n }\n }\n\n throw lastError!;\n };\n}\n\n/**\n * Create simple retry middleware\n */\nexport function simpleRetry(retries: number, delay: number = 1000): Middleware {\n return retryMiddleware({\n retries,\n delay,\n backoff: 'exponential',\n });\n}\n","import type { Middleware, RequestContext, ResponseContext } from '../types';\n\n/**\n * Cache middleware configuration\n */\nexport interface CacheConfig {\n ttl: number; // Cache time (milliseconds)\n keyGenerator?: (request: RequestContext) => string;\n shouldCache?: (request: RequestContext, response: ResponseContext) => boolean;\n storage?: CacheStorage;\n}\n\n/**\n * Cache storage interface\n */\nexport interface CacheStorage {\n get(key: string): Promise<CacheEntry | null>;\n set(key: string, entry: CacheEntry): Promise<void>;\n delete(key: string): Promise<void>;\n clear(): Promise<void>;\n}\n\n/**\n * Cache entry\n */\nexport interface CacheEntry {\n data: ResponseContext;\n timestamp: number;\n ttl: number;\n}\n\n/**\n * Memory cache storage implementation\n */\nexport class MemoryCacheStorage implements CacheStorage {\n private cache = new Map<string, CacheEntry>();\n\n async get(key: string): Promise<CacheEntry | null> {\n const entry = this.cache.get(key);\n\n if (!entry) {\n return null;\n }\n\n // Check if expired\n if (Date.now() - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n return null;\n }\n\n return entry;\n }\n\n async set(key: string, entry: CacheEntry): Promise<void> {\n this.cache.set(key, entry);\n }\n\n async delete(key: string): Promise<void> {\n this.cache.delete(key);\n }\n\n async clear(): Promise<void> {\n this.cache.clear();\n }\n\n // Get cache size\n size(): number {\n return this.cache.size;\n }\n\n // Clean expired cache\n cleanup(): void {\n const now = Date.now();\n for (const [key, entry] of this.cache.entries()) {\n if (now - entry.timestamp > entry.ttl) {\n this.cache.delete(key);\n }\n }\n }\n}\n\n// Default cache key generator\nfunction defaultKeyGenerator(request: RequestContext): string {\n const { url, method, body, query } = request;\n const parts = [method.toUpperCase(), url];\n\n if (query && Object.keys(query).length > 0) {\n parts.push(JSON.stringify(query));\n }\n\n if (body) {\n parts.push(JSON.stringify(body));\n }\n\n return parts.join('|');\n}\n\n// Default cache condition\nfunction defaultShouldCache(request: RequestContext, response: ResponseContext): boolean {\n // Only cache successful GET responses\n return request.method.toLowerCase() === 'get' && response.status >= 200 && response.status < 300;\n}\n\n/**\n * Create cache middleware\n */\nexport function cacheMiddleware(config: CacheConfig): Middleware {\n const {\n ttl,\n keyGenerator = defaultKeyGenerator,\n shouldCache = defaultShouldCache,\n storage = new MemoryCacheStorage(),\n } = config;\n\n return async (request, next) => {\n const cacheKey = keyGenerator(request);\n\n // Try to get from cache\n const cachedEntry = await storage.get(cacheKey);\n if (cachedEntry) {\n return cachedEntry.data;\n }\n\n // Execute request\n const response = await next(request);\n\n // Check if should cache\n if (shouldCache(request, response)) {\n const entry: CacheEntry = {\n data: response,\n timestamp: Date.now(),\n ttl,\n };\n\n await storage.set(cacheKey, entry);\n }\n\n return response;\n };\n}\n\n/**\n * Create simple cache middleware\n */\nexport function simpleCache(ttl: number): Middleware {\n return cacheMiddleware({ ttl });\n}\n","/**\n * Request handling utility functions\n *\n * Note: This file contains utility functions that were originally designed\n * for general HTTP request handling, but are now handled by individual adapters.\n * These functions are kept for backward compatibility and potential future use.\n */\n\n// Simple header merging utility\nexport function mergeHeaders(\n defaultHeaders: Record<string, string>,\n requestHeaders?: Record<string, string>\n): Record<string, string> {\n return {\n ...defaultHeaders,\n ...requestHeaders,\n };\n}\n","/**\n * Zodsei - Contract-first type-safe HTTP client with Zod validation\n */\n\n// Core exports\nexport { createClient, ZodseiClient } from './client';\nexport { defineContract } from './types';\n\n// Schema exports\nexport {\n SchemaExtractor,\n createSchemaExtractor,\n extractTypeInfo,\n type InferRequestType,\n type InferResponseType,\n type InferContractTypes,\n type InferEndpointMethod,\n} from './schema';\n\n// Type exports\nexport type {\n Contract,\n EndpointDefinition,\n ClientConfig,\n ApiClient,\n EnhancedApiClient,\n EndpointMethodWithSchema,\n HttpMethod,\n RequestContext,\n ResponseContext,\n Middleware,\n ExtractPathParams,\n SeparateRequestData,\n} from './types';\n\n// Error class exports\nexport {\n ZodseiError,\n ValidationError,\n HttpError,\n NetworkError,\n ConfigError,\n TimeoutError,\n} from './errors';\n\n// Validation utility exports\nexport {\n validateRequest,\n validateResponse,\n safeParseRequest,\n safeParseResponse,\n createValidator,\n} from './validation';\n\n// Middleware exports\nexport { createMiddlewareExecutor, composeMiddleware } from './middleware';\nexport { retryMiddleware, simpleRetry } from './middleware/retry';\nexport {\n cacheMiddleware,\n simpleCache,\n MemoryCacheStorage,\n type CacheConfig,\n type CacheStorage,\n type CacheEntry,\n} from './middleware/cache';\n\n// Utility function exports\nexport {\n extractPathParamNames,\n replacePath,\n buildQueryString,\n buildUrl,\n separateParams,\n shouldHaveBody,\n} from './utils/path';\n\nexport { mergeHeaders } from './utils/request';\n\n// Adapter exports\nexport { AxiosAdapter } from './adapters/axios';\n\n// Re-export zod for user convenience\nexport { z } from 'zod';\n"],"mappings":"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