zlient 1.0.1 → 1.0.2
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/README.md +80 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -27,38 +27,93 @@ bun add zlient zod
|
|
|
27
27
|
## Quick Start
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
|
-
import {
|
|
31
|
-
import
|
|
30
|
+
import { AuthProvider, BaseEndpoint, ClientOptions, HttpClient, HTTPMethod, RequestOptions } from "zlient";
|
|
31
|
+
import z from "zod";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Schemas
|
|
35
|
+
*/
|
|
36
|
+
const todoItem = z.object({
|
|
37
|
+
userId: z.number(),
|
|
38
|
+
id: z.number(),
|
|
39
|
+
title: z.string(),
|
|
40
|
+
completed: z.boolean(),
|
|
41
|
+
});
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
const ListTodosRequest = z.object({});
|
|
44
|
+
const ListTodosResponse = z.array(todoItem);
|
|
45
|
+
|
|
46
|
+
const GetTodoRequest = z.object({
|
|
47
|
+
id: z.number(),
|
|
38
48
|
});
|
|
49
|
+
const GetTodoResponse = todoItem;
|
|
39
50
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Endpoints
|
|
54
|
+
*/
|
|
55
|
+
class ListTodos extends BaseEndpoint<typeof ListTodosRequest, typeof ListTodosResponse> {
|
|
56
|
+
protected readonly method = HTTPMethod.GET;
|
|
57
|
+
protected readonly path = "/todos";
|
|
58
|
+
constructor(client: HttpClient) { super(client, { requestSchema: ListTodosRequest, responseSchema: ListTodosResponse }); }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class GetTodo extends BaseEndpoint<typeof GetTodoRequest, typeof GetTodoResponse> {
|
|
62
|
+
protected readonly method = HTTPMethod.GET;
|
|
63
|
+
protected readonly path = (args: z.infer<typeof GetTodoRequest>) => `/todos/${args.id}`;
|
|
64
|
+
constructor(client: HttpClient) { super(client, { requestSchema: GetTodoRequest, responseSchema: GetTodoResponse }); }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Service
|
|
69
|
+
*/
|
|
70
|
+
class TodosService {
|
|
71
|
+
constructor(private client: HttpClient) { }
|
|
72
|
+
list(args: z.infer<typeof ListTodosRequest>, options?: RequestOptions) { return new ListTodos(this.client).call(args, options); }
|
|
73
|
+
get(args: z.infer<typeof GetTodoRequest>, options?: RequestOptions) { return new GetTodo(this.client).call(args, options); }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* SDK class for initialization
|
|
78
|
+
*/
|
|
79
|
+
export class SDK {
|
|
80
|
+
readonly http: HttpClient;
|
|
81
|
+
readonly todos: TodosService;
|
|
82
|
+
|
|
83
|
+
constructor(opts: ClientOptions & { auth?: AuthProvider }) {
|
|
84
|
+
this.http = new HttpClient(opts);
|
|
85
|
+
if (opts.auth) this.http.setAuth(opts.auth);
|
|
86
|
+
|
|
87
|
+
// Services can map to distinct base URL keys via per-call options
|
|
88
|
+
this.todos = new TodosService(this.http);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Usage example
|
|
95
|
+
*/
|
|
96
|
+
const sdk = new SDK({
|
|
97
|
+
baseUrls: {
|
|
98
|
+
default: "https://jsonplaceholder.typicode.com",
|
|
99
|
+
},
|
|
100
|
+
headers: {
|
|
101
|
+
"X-SDK-Name": "example-sdk",
|
|
102
|
+
"X-SDK-Version": "1.0.0",
|
|
103
|
+
},
|
|
104
|
+
retry: { maxRetries: 2, baseDelayMs: 100, jitter: 0.2, retryMethods: ["GET"] },
|
|
105
|
+
timeout: { requestTimeoutMs: 5000 },
|
|
46
106
|
});
|
|
47
107
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
super(client, { responseSchema: UserSchema });
|
|
55
|
-
}
|
|
108
|
+
async function demo() {
|
|
109
|
+
const todos = await sdk.todos.list({});
|
|
110
|
+
console.log(todos);
|
|
111
|
+
|
|
112
|
+
const todo = await sdk.todos.get({ id: 1 });
|
|
113
|
+
console.log(todo);
|
|
56
114
|
}
|
|
57
115
|
|
|
58
|
-
|
|
59
|
-
const getUserEndpoint = new GetUserEndpoint(client);
|
|
60
|
-
const user = await getUserEndpoint.call({ id: 1 });
|
|
61
|
-
console.log(user); // Fully typed!
|
|
116
|
+
demo().catch(console.error);
|
|
62
117
|
```
|
|
63
118
|
|
|
64
119
|
## Core Concepts
|
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","k: string","err: any","init: RequestInit","timeoutId: any","client: HttpClient","z"],"sources":["../lib/types.ts","../lib/auth.ts","../lib/validation.ts","../lib/http/HttpClient.ts","../lib/endpoint/BaseEndpoint.ts","../lib/schemas/common.ts","../lib/index.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\n\nexport type Dictionary<T = unknown> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\nexport type BaseUrlMap = {\n default: string;\n [service: string]: string;\n};\n\nexport type RetryStrategy = {\n maxRetries: number;\n /** milliseconds */\n baseDelayMs: number;\n /** Jitter factor 0..1 */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** Which status codes are retriable */\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\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n beforeRequest?: BeforeRequestHook[];\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** ms */\n requestTimeoutMs?: number;\n}\n\nexport interface ClientOptions {\n baseUrls: BaseUrlMap;\n fetch?: FetchLike;\n headers?: Record<string, string>;\n retry?: RetryStrategy;\n interceptors?: Interceptors;\n timeout?: TimeoutOptions;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\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}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\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\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 */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n// Utility to build query strings\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\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 apply(req: { url: string; init: RequestInit; options?: ReqOpts }): Promise<void> | void;\n}\n\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {}\n apply({ url, init }: { url: string; init: RequestInit }) {\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 as any).__urlOverride = u.toString();\n }\n }\n}\n\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: { url: string; init: RequestInit }) {\n const token = await this.getToken();\n init.headers = { ...(init.headers as any), Authorization: `Bearer ${token}` };\n }\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\nexport function safeParse<T>(schema: z.ZodTypeAny, 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\nexport function parseOrThrow<T>(schema: z.ZodTypeAny, 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","import {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\nimport type { AuthProvider } from '../auth';\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\n constructor(opts: ClientOptions & { auth?: AuthProvider }) {\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 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 this.timeoutMs = opts.timeout?.requestTimeoutMs;\n this.auth = opts['auth'] ?? new (require('../auth').NoAuth)();\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) throw new Error(`Unknown baseUrl key: ${k}`);\n return url.replace(/\\/$/, '');\n }\n\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\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 // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n return await fn();\n } catch (err: any) {\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 private async runBeforeHooks(url: string, init: RequestInit) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\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 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 base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\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 = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : (body as any)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if ((init as any).__urlOverride) url = (init as any).__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: any;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(\n () => controller.abort(new ApiError('Request timeout', { status: 0 })),\n this.timeoutMs\n );\n }\n\n try {\n const req = new Request(url, init);\n console.log('HTTP Request:', req.method, req.url, req);\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 {}\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()) as any);\n await this.runAfterHooks(new Request(url, init), res, data);\n return { data: data as T, response: res };\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n response,\n error,\n }: {\n response?: Response;\n error?: any;\n attempt: number;\n }) => {\n // Retry on network errors or 5xx\n if (error instanceof ApiError && error.status && error.status >= 500) return true;\n if (error?.name === 'AbortError') return false;\n if (!error?.status && !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","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.\n */\nexport abstract class BaseEndpoint<ReqSchema extends z.ZodTypeAny, ResSchema extends z.ZodTypeAny> {\n protected abstract readonly method: keyof typeof HTTPMethod;\n protected abstract readonly path: string | ((params: any) => string);\n protected readonly requestSchema?: ReqSchema;\n protected readonly responseSchema: ResSchema;\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 */\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 const body = this.method === 'GET' || this.method === 'HEAD' ? undefined : args;\n\n const { data } = await this.client.request(this.method, path, body, {\n ...options,\n // For GET with query params, allow request schema to include { query: {...} }\n query: (this.method === 'GET' ? (args as any)?.query : undefined) ?? options?.query,\n });\n\n return parseOrThrow<z.infer<ResSchema>>(this.responseSchema, data);\n }\n}\n","import { z } from 'zod';\n\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type Id = z.infer<typeof Id>;\n\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\nexport const Envelope = <T extends z.ZodTypeAny>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n","// Core types and utilities\nexport * from './types';\nexport * from './auth';\nexport * from './validation';\n\n// HTTP client and endpoint base class\nexport { HttpClient } from './http/HttpClient';\nexport { BaseEndpoint } from './endpoint/BaseEndpoint';\n\n// Common schemas\nexport * from './schemas/common';\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","k: string","err: any","init: RequestInit","timeoutId: any","client: HttpClient","z"],"sources":["../lib/types.ts","../lib/auth.ts","../lib/validation.ts","../lib/http/HttpClient.ts","../lib/endpoint/BaseEndpoint.ts","../lib/schemas/common.ts","../lib/index.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\n\nexport type Dictionary<T = unknown> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\nexport type BaseUrlMap = {\n default: string;\n [service: string]: string;\n};\n\nexport type RetryStrategy = {\n maxRetries: number;\n /** milliseconds */\n baseDelayMs: number;\n /** Jitter factor 0..1 */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** Which status codes are retriable */\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\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n beforeRequest?: BeforeRequestHook[];\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** ms */\n requestTimeoutMs?: number;\n}\n\nexport interface ClientOptions {\n baseUrls: BaseUrlMap;\n fetch?: FetchLike;\n headers?: Record<string, string>;\n retry?: RetryStrategy;\n interceptors?: Interceptors;\n timeout?: TimeoutOptions;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\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}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\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\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 */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n// Utility to build query strings\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\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 apply(req: { url: string; init: RequestInit; options?: ReqOpts }): Promise<void> | void;\n}\n\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {}\n apply({ url, init }: { url: string; init: RequestInit }) {\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 as any).__urlOverride = u.toString();\n }\n }\n}\n\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: { url: string; init: RequestInit }) {\n const token = await this.getToken();\n init.headers = { ...(init.headers as any), Authorization: `Bearer ${token}` };\n }\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\nexport function safeParse<T>(schema: z.ZodTypeAny, 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\nexport function parseOrThrow<T>(schema: z.ZodTypeAny, 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","import {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\nimport type { AuthProvider } from '../auth';\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\n constructor(opts: ClientOptions & { auth?: AuthProvider }) {\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 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 this.timeoutMs = opts.timeout?.requestTimeoutMs;\n this.auth = opts['auth'] ?? new (require('../auth').NoAuth)();\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) throw new Error(`Unknown baseUrl key: ${k}`);\n return url.replace(/\\/$/, '');\n }\n\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\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 // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n return await fn();\n } catch (err: any) {\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 private async runBeforeHooks(url: string, init: RequestInit) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\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 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 base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\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 = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : (body as any)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if ((init as any).__urlOverride) url = (init as any).__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: any;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(\n () => controller.abort(new ApiError('Request timeout', { status: 0 })),\n this.timeoutMs\n );\n }\n\n try {\n const req = new Request(url, init);\n console.log('HTTP Request:', req.method, req.url, req);\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 { }\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()) as any);\n await this.runAfterHooks(new Request(url, init), res, data);\n return { data: data as T, response: res };\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n response,\n error,\n }: {\n response?: Response;\n error?: any;\n attempt: number;\n }) => {\n // Retry on network errors or 5xx\n if (error instanceof ApiError && error.status && error.status >= 500) return true;\n if (error?.name === 'AbortError') return false;\n if (!error?.status && !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","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.\n */\nexport abstract class BaseEndpoint<ReqSchema extends z.ZodTypeAny, ResSchema extends z.ZodTypeAny> {\n protected abstract readonly method: keyof typeof HTTPMethod;\n protected abstract readonly path: string | ((params: any) => string);\n protected readonly requestSchema?: ReqSchema;\n protected readonly responseSchema: ResSchema;\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 */\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 const body = this.method === 'GET' || this.method === 'HEAD' ? undefined : args;\n\n const { data } = await this.client.request(this.method, path, body, {\n ...options,\n // For GET with query params, allow request schema to include { query: {...} }\n query: (this.method === 'GET' ? (args as any)?.query : undefined) ?? options?.query,\n });\n\n return parseOrThrow<z.infer<ResSchema>>(this.responseSchema, data);\n }\n}\n","import { z } from 'zod';\n\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type Id = z.infer<typeof Id>;\n\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\nexport const Envelope = <T extends z.ZodTypeAny>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n","// Core types and utilities\nexport * from './types';\nexport * from './auth';\nexport * from './validation';\n\n// HTTP client and endpoint base class\nexport { HttpClient } from './http/HttpClient';\nexport { BaseEndpoint } from './endpoint/BaseEndpoint';\n\n// Common schemas\nexport * from './schemas/common';\n"],"mappings":"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"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["s","opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","k: string","err: any","init: RequestInit","timeoutId: any","client: HttpClient"],"sources":["../lib/types.ts","../lib/auth.ts","../lib/validation.ts","../lib/http/HttpClient.ts","../lib/endpoint/BaseEndpoint.ts","../lib/schemas/common.ts","../lib/index.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\n\nexport type Dictionary<T = unknown> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\nexport type BaseUrlMap = {\n default: string;\n [service: string]: string;\n};\n\nexport type RetryStrategy = {\n maxRetries: number;\n /** milliseconds */\n baseDelayMs: number;\n /** Jitter factor 0..1 */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** Which status codes are retriable */\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\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n beforeRequest?: BeforeRequestHook[];\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** ms */\n requestTimeoutMs?: number;\n}\n\nexport interface ClientOptions {\n baseUrls: BaseUrlMap;\n fetch?: FetchLike;\n headers?: Record<string, string>;\n retry?: RetryStrategy;\n interceptors?: Interceptors;\n timeout?: TimeoutOptions;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\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}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\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\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 */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n// Utility to build query strings\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\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 apply(req: { url: string; init: RequestInit; options?: ReqOpts }): Promise<void> | void;\n}\n\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {}\n apply({ url, init }: { url: string; init: RequestInit }) {\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 as any).__urlOverride = u.toString();\n }\n }\n}\n\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: { url: string; init: RequestInit }) {\n const token = await this.getToken();\n init.headers = { ...(init.headers as any), Authorization: `Bearer ${token}` };\n }\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\nexport function safeParse<T>(schema: z.ZodTypeAny, 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\nexport function parseOrThrow<T>(schema: z.ZodTypeAny, 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","import {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\nimport type { AuthProvider } from '../auth';\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\n constructor(opts: ClientOptions & { auth?: AuthProvider }) {\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 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 this.timeoutMs = opts.timeout?.requestTimeoutMs;\n this.auth = opts['auth'] ?? new (require('../auth').NoAuth)();\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) throw new Error(`Unknown baseUrl key: ${k}`);\n return url.replace(/\\/$/, '');\n }\n\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\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 // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n return await fn();\n } catch (err: any) {\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 private async runBeforeHooks(url: string, init: RequestInit) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\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 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 base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\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 = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : (body as any)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if ((init as any).__urlOverride) url = (init as any).__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: any;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(\n () => controller.abort(new ApiError('Request timeout', { status: 0 })),\n this.timeoutMs\n );\n }\n\n try {\n const req = new Request(url, init);\n console.log('HTTP Request:', req.method, req.url, req);\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 {}\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()) as any);\n await this.runAfterHooks(new Request(url, init), res, data);\n return { data: data as T, response: res };\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n response,\n error,\n }: {\n response?: Response;\n error?: any;\n attempt: number;\n }) => {\n // Retry on network errors or 5xx\n if (error instanceof ApiError && error.status && error.status >= 500) return true;\n if (error?.name === 'AbortError') return false;\n if (!error?.status && !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","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.\n */\nexport abstract class BaseEndpoint<ReqSchema extends z.ZodTypeAny, ResSchema extends z.ZodTypeAny> {\n protected abstract readonly method: keyof typeof HTTPMethod;\n protected abstract readonly path: string | ((params: any) => string);\n protected readonly requestSchema?: ReqSchema;\n protected readonly responseSchema: ResSchema;\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 */\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 const body = this.method === 'GET' || this.method === 'HEAD' ? undefined : args;\n\n const { data } = await this.client.request(this.method, path, body, {\n ...options,\n // For GET with query params, allow request schema to include { query: {...} }\n query: (this.method === 'GET' ? (args as any)?.query : undefined) ?? options?.query,\n });\n\n return parseOrThrow<z.infer<ResSchema>>(this.responseSchema, data);\n }\n}\n","import { z } from 'zod';\n\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type Id = z.infer<typeof Id>;\n\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\nexport const Envelope = <T extends z.ZodTypeAny>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n","// Core types and utilities\nexport * from './types';\nexport * from './auth';\nexport * from './validation';\n\n// HTTP client and endpoint base class\nexport { HttpClient } from './http/HttpClient';\nexport { BaseEndpoint } from './endpoint/BaseEndpoint';\n\n// Common schemas\nexport * from './schemas/common';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["s","opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","k: string","err: any","init: RequestInit","timeoutId: any","client: HttpClient"],"sources":["../lib/types.ts","../lib/auth.ts","../lib/validation.ts","../lib/http/HttpClient.ts","../lib/endpoint/BaseEndpoint.ts","../lib/schemas/common.ts","../lib/index.ts"],"sourcesContent":["import { z, ZodError } from 'zod';\n\nexport type Dictionary<T = unknown> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\nexport type BaseUrlMap = {\n default: string;\n [service: string]: string;\n};\n\nexport type RetryStrategy = {\n maxRetries: number;\n /** milliseconds */\n baseDelayMs: number;\n /** Jitter factor 0..1 */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** Which status codes are retriable */\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\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n beforeRequest?: BeforeRequestHook[];\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** ms */\n requestTimeoutMs?: number;\n}\n\nexport interface ClientOptions {\n baseUrls: BaseUrlMap;\n fetch?: FetchLike;\n headers?: Record<string, string>;\n retry?: RetryStrategy;\n interceptors?: Interceptors;\n timeout?: TimeoutOptions;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\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}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\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\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 */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n// Utility to build query strings\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\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 apply(req: { url: string; init: RequestInit; options?: ReqOpts }): Promise<void> | void;\n}\n\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {}\n apply({ url, init }: { url: string; init: RequestInit }) {\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 as any).__urlOverride = u.toString();\n }\n }\n}\n\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: { url: string; init: RequestInit }) {\n const token = await this.getToken();\n init.headers = { ...(init.headers as any), Authorization: `Bearer ${token}` };\n }\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\nexport function safeParse<T>(schema: z.ZodTypeAny, 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\nexport function parseOrThrow<T>(schema: z.ZodTypeAny, 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","import {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\nimport type { AuthProvider } from '../auth';\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\n constructor(opts: ClientOptions & { auth?: AuthProvider }) {\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 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 this.timeoutMs = opts.timeout?.requestTimeoutMs;\n this.auth = opts['auth'] ?? new (require('../auth').NoAuth)();\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) throw new Error(`Unknown baseUrl key: ${k}`);\n return url.replace(/\\/$/, '');\n }\n\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\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 // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n return await fn();\n } catch (err: any) {\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 private async runBeforeHooks(url: string, init: RequestInit) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\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 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 base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\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 = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : (body as any)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if ((init as any).__urlOverride) url = (init as any).__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: any;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(\n () => controller.abort(new ApiError('Request timeout', { status: 0 })),\n this.timeoutMs\n );\n }\n\n try {\n const req = new Request(url, init);\n console.log('HTTP Request:', req.method, req.url, req);\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 { }\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()) as any);\n await this.runAfterHooks(new Request(url, init), res, data);\n return { data: data as T, response: res };\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n response,\n error,\n }: {\n response?: Response;\n error?: any;\n attempt: number;\n }) => {\n // Retry on network errors or 5xx\n if (error instanceof ApiError && error.status && error.status >= 500) return true;\n if (error?.name === 'AbortError') return false;\n if (!error?.status && !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","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.\n */\nexport abstract class BaseEndpoint<ReqSchema extends z.ZodTypeAny, ResSchema extends z.ZodTypeAny> {\n protected abstract readonly method: keyof typeof HTTPMethod;\n protected abstract readonly path: string | ((params: any) => string);\n protected readonly requestSchema?: ReqSchema;\n protected readonly responseSchema: ResSchema;\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 */\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 const body = this.method === 'GET' || this.method === 'HEAD' ? undefined : args;\n\n const { data } = await this.client.request(this.method, path, body, {\n ...options,\n // For GET with query params, allow request schema to include { query: {...} }\n query: (this.method === 'GET' ? (args as any)?.query : undefined) ?? options?.query,\n });\n\n return parseOrThrow<z.infer<ResSchema>>(this.responseSchema, data);\n }\n}\n","import { z } from 'zod';\n\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type Id = z.infer<typeof Id>;\n\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\nexport const Envelope = <T extends z.ZodTypeAny>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n","// Core types and utilities\nexport * from './types';\nexport * from './auth';\nexport * from './validation';\n\n// HTTP client and endpoint base class\nexport { HttpClient } from './http/HttpClient';\nexport { BaseEndpoint } from './endpoint/BaseEndpoint';\n\n// Common schemas\nexport * from './schemas/common';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zlient",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A type-safe HTTP client framework with Zod validation for building robust API clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"prepublishOnly": "npm run build",
|
|
32
32
|
"lint": "eslint lib/**/*.ts",
|
|
33
33
|
"lint:fix": "eslint lib/**/*.ts --fix",
|
|
34
|
-
"format": "prettier --write \"lib/**/*.ts\"
|
|
35
|
-
"format:check": "prettier --check \"lib/**/*.ts\"
|
|
34
|
+
"format": "prettier --write \"lib/**/*.ts\"",
|
|
35
|
+
"format:check": "prettier --check \"lib/**/*.ts\"",
|
|
36
36
|
"typecheck": "tsc --noEmit",
|
|
37
37
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
38
38
|
},
|