zlient 2.0.0 → 2.0.1

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 CHANGED
@@ -1,430 +1,139 @@
1
1
  # zlient
2
2
 
3
- A type-safe HTTP client framework with Zod validation for building robust API clients.
3
+ **The Type-Safe HTTP Client for Perfectionists.**
4
+
5
+ ![NPM Version](https://img.shields.io/npm/v/zlient?style=flat-square)
6
+ ![License](https://img.shields.io/npm/l/zlient?style=flat-square)
7
+ ![Downloads](https://img.shields.io/npm/dm/zlient?style=flat-square)
8
+
9
+ Build robust, type-safe API clients with automatic Zod validation, retry logic, and zero boilerplate.
4
10
 
5
11
  ## Features
6
12
 
7
- - 🔒 **Type-safe**: Full TypeScript support with automatic type inference
8
- - **Runtime validation**: Zod schemas for request/response validation
9
- - 🔄 **Retry logic**: Built-in configurable retry strategies with exponential backoff
10
- - 🎯 **Authentication**: Multiple auth providers (API Key, Bearer Token, Custom)
11
- - 🪝 **Interceptors**: Before request and after response hooks
12
- - ⏱️ **Timeouts**: Configurable request timeouts
13
- - 📦 **Multiple endpoints**: Easy service separation with base URL mapping
14
- - 📊 **Observability**: Built-in logging and metrics collection
15
- - 🎨 **Developer Experience**: Comprehensive JSDoc, helper methods, great error messages
16
- - 🏢 **Enterprise-ready**: Production-grade logging, metrics, and monitoring support
13
+ - **Functional API**: Define endpoints with pure functions and automatic type inference.
14
+ - **Type-Safe**: Full TypeScript support. Arguments and responses are strictly typed.
15
+ - **Zod Validation**: Runtime validation for requests, responses, query params, and path params.
16
+ - **Resilience**: Built-in exponential backoff retries and timeouts.
17
+ - **Auth**: Logic-safe authentication providers (Bearer, API Key, Custom) that handle edge cases.
18
+ - **Observability**: Hooks for structured logging and metrics.
19
+
20
+ ---
17
21
 
18
22
  ## Installation
19
23
 
20
24
  ```bash
21
25
  npm install zlient zod
22
26
  # or
23
- yarn add zlient zod
24
- # or
25
- pnpm add zlient zod
26
- # or
27
27
  bun add zlient zod
28
28
  ```
29
29
 
30
- ## Quick Start
31
-
32
- ```typescript
33
- import { AuthProvider, BaseEndpoint, ClientOptions, HttpClient, HTTPMethod, RequestOptions } from "zlient";
34
- import z from "zod";
35
-
36
- /**
37
- * Schemas
38
- */
39
- const todoItem = z.object({
40
- userId: z.number(),
41
- id: z.number(),
42
- title: z.string(),
43
- completed: z.boolean(),
44
- });
45
-
46
- const ListTodosRequest = z.object({});
47
- const ListTodosResponse = z.array(todoItem);
30
+ > **Note**: `zod` is a peer dependency. You must install it alongside `zlient`.
48
31
 
49
- const GetTodoRequest = z.object({
50
- id: z.number(),
51
- });
52
- const GetTodoResponse = todoItem;
53
-
54
-
55
- /**
56
- * Endpoints
57
- */
58
- class ListTodos extends BaseEndpoint<typeof ListTodosRequest, typeof ListTodosResponse> {
59
- protected readonly method = HTTPMethod.GET;
60
- protected readonly path = "/todos";
61
- constructor(client: HttpClient) { super(client, { requestSchema: ListTodosRequest, responseSchema: ListTodosResponse }); }
62
- }
63
-
64
- class GetTodo extends BaseEndpoint<typeof GetTodoRequest, typeof GetTodoResponse> {
65
- protected readonly method = HTTPMethod.GET;
66
- protected readonly path = (args: z.infer<typeof GetTodoRequest>) => `/todos/${args.id}`;
67
- constructor(client: HttpClient) { super(client, { requestSchema: GetTodoRequest, responseSchema: GetTodoResponse }); }
68
- }
69
-
70
- /**
71
- * Service
72
- */
73
- class TodosService {
74
- constructor(private client: HttpClient) { }
75
- list(args: z.infer<typeof ListTodosRequest>, options?: RequestOptions) { return new ListTodos(this.client).call(args, options); }
76
- get(args: z.infer<typeof GetTodoRequest>, options?: RequestOptions) { return new GetTodo(this.client).call(args, options); }
77
- }
78
-
79
- /**
80
- * SDK class for initialization
81
- */
82
- export class SDK {
83
- readonly http: HttpClient;
84
- readonly todos: TodosService;
85
-
86
- constructor(opts: ClientOptions & { auth?: AuthProvider }) {
87
- this.http = new HttpClient(opts);
88
- if (opts.auth) this.http.setAuth(opts.auth);
89
-
90
- // Initialize services
91
- this.todos = new TodosService(this.http);
92
- }
93
- }
94
-
95
-
96
- /**
97
- * Usage example
98
- */
99
- const sdk = new SDK({
100
- baseUrls: {
101
- default: "https://jsonplaceholder.typicode.com",
102
- },
103
- headers: {
104
- "X-SDK-Name": "example-sdk",
105
- "X-SDK-Version": "1.0.0",
106
- },
107
- retry: { maxRetries: 2, baseDelayMs: 100, jitter: 0.2, retryMethods: ["GET"] },
108
- timeout: { requestTimeoutMs: 5000 },
109
- });
32
+ ---
110
33
 
111
- async function demo() {
112
- const todos = await sdk.todos.list({});
113
- console.log(todos);
114
-
115
- const todo = await sdk.todos.get({ id: 1 });
116
- console.log(todo);
117
- }
118
-
119
- demo().catch(console.error);
120
- ```
121
-
122
- ## Core Concepts
123
-
124
- ### HttpClient
34
+ ## Quick Start
125
35
 
126
- The main HTTP client that handles requests, retries, authentication, and interceptors.
36
+ ### 1. Initialize Client
127
37
 
128
38
  ```typescript
129
- import { HttpClient, NoAuth } from 'zlient';
39
+ import { HttpClient } from 'zlient';
130
40
 
131
41
  const client = new HttpClient({
132
42
  baseUrls: {
133
43
  default: 'https://api.example.com',
134
- v2: 'https://api-v2.example.com',
135
44
  },
136
- headers: {
137
- 'Content-Type': 'application/json',
138
- },
139
- retry: {
140
- maxRetries: 3,
141
- baseDelayMs: 1000,
142
- jitter: 0.2,
143
- },
144
- timeout: {
145
- requestTimeoutMs: 30000,
146
- },
147
- auth: new NoAuth(),
45
+ retry: { maxRetries: 3 },
148
46
  });
149
47
  ```
150
48
 
151
- ### Authentication
49
+ ### 2. Define Endpoint
152
50
 
153
- #### Bearer Token
51
+ Use `createEndpoint` to build a type-safe definition. No classes required.
154
52
 
155
53
  ```typescript
156
- import { BearerTokenAuth } from 'zlient';
157
-
158
- const auth = new BearerTokenAuth(async () => {
159
- // Fetch token from your auth service
160
- return await getAccessToken();
161
- });
162
-
163
- client.setAuth(auth);
164
- ```
165
-
166
- #### API Key
167
-
168
- ```typescript
169
- import { ApiKeyAuth } from 'zlient';
170
-
171
- // Header-based
172
- const auth = new ApiKeyAuth({
173
- header: 'X-API-Key',
174
- value: 'your-api-key',
175
- });
54
+ import { z } from 'zod';
176
55
 
177
- // Query parameter-based
178
- const auth = new ApiKeyAuth({
179
- query: 'apiKey',
180
- value: 'your-api-key',
56
+ const getUser = client.createEndpoint({
57
+ method: 'GET',
58
+ path: (params) => `/users/${params.id}`,
59
+ // Strict schemas for all inputs
60
+ pathParams: z.object({ id: z.string() }),
61
+ response: z.object({
62
+ id: z.string(),
63
+ name: z.string(),
64
+ email: z.string().email(),
65
+ }),
181
66
  });
182
67
  ```
183
68
 
184
- #### Custom Auth
185
-
186
- ```typescript
187
- import { AuthProvider } from 'zlient';
188
-
189
- class CustomAuth implements AuthProvider {
190
- async apply({ init }) {
191
- init.headers = {
192
- ...init.headers,
193
- 'X-Custom-Auth': 'custom-value',
194
- };
195
- }
196
- }
197
- ```
198
-
199
- ### BaseEndpoint
69
+ ### 3. Call It
200
70
 
201
- Create type-safe endpoints with automatic validation:
71
+ TypeScript will enforce inputs and infer the response type automatically.
202
72
 
203
73
  ```typescript
204
- import { BaseEndpoint, HttpClient } from 'zlient';
205
- import { z } from 'zod';
206
-
207
- const CreateUserSchema = z.object({
208
- name: z.string(),
209
- email: z.string().email(),
210
- });
211
-
212
- const UserResponseSchema = z.object({
213
- id: z.number(),
214
- name: z.string(),
215
- email: z.string().email(),
216
- createdAt: z.string().datetime(),
74
+ const user = await getUser.call({
75
+ pathParams: { id: '123' },
217
76
  });
218
77
 
219
- class CreateUserEndpoint extends BaseEndpoint<
220
- typeof CreateUserSchema,
221
- typeof UserResponseSchema
222
- > {
223
- protected method = 'POST' as const;
224
- protected path = '/users';
225
-
226
- constructor(client: HttpClient) {
227
- super(client, {
228
- requestSchema: CreateUserSchema,
229
- responseSchema: UserResponseSchema,
230
- });
231
- }
232
- }
233
-
234
- // Usage
235
- const endpoint = new CreateUserEndpoint(client);
236
- const user = await endpoint.call({
237
- name: 'John Doe',
238
- email: 'john@example.com',
239
- });
78
+ // `user` is typed as { id: string; name: string; email: string }
79
+ console.log(user.name);
240
80
  ```
241
81
 
242
- ### Interceptors
243
-
244
- Add hooks to inspect or modify requests and responses:
82
+ ---
245
83
 
246
- ```typescript
247
- const client = new HttpClient({
248
- baseUrls: { default: 'https://api.example.com' },
249
- interceptors: {
250
- beforeRequest: [
251
- async ({ url, init }) => {
252
- console.log('Making request to:', url);
253
- },
254
- ],
255
- afterResponse: [
256
- async ({ request, response, parsed }) => {
257
- console.log('Response received:', response.status);
258
- },
259
- ],
260
- },
261
- });
262
- ```
84
+ ## Advanced Usage
263
85
 
264
- ### Common Schemas
86
+ ### Authentication
265
87
 
266
- The package includes common reusable schemas:
88
+ Zlient provides built-in auth providers that safely handle headers.
267
89
 
268
90
  ```typescript
269
- import { Id, Timestamps, Meta, ApiErrorSchema, Envelope } from 'zlient';
91
+ import { BearerTokenAuth, ApiKeyAuth } from 'zlient';
270
92
 
271
- // Use in your schemas
272
- const MyEntitySchema = z.object({
273
- id: Id,
274
- name: z.string(),
275
- ...Timestamps.shape,
276
- });
93
+ // Bearer Token (Dynamic)
94
+ client.setAuth(new BearerTokenAuth(async () => {
95
+ return await getLatestToken(); // Auto-refresh logic supported
96
+ }));
277
97
 
278
- // Wrap responses in an envelope
279
- const MyResponseSchema = Envelope(MyEntitySchema);
98
+ // API Key (Header or Query)
99
+ client.setAuth(new ApiKeyAuth({ header: 'X-API-KEY', value: 'secret' }));
280
100
  ```
281
101
 
282
- ## Advanced Usage
102
+ ### Multiple Status Codes
283
103
 
284
- ### Multiple Base URLs
104
+ Handle different responses for different status codes.
285
105
 
286
106
  ```typescript
287
- const client = new HttpClient({
288
- baseUrls: {
289
- default: 'https://api.example.com',
290
- auth: 'https://auth.example.com',
291
- cdn: 'https://cdn.example.com',
107
+ const createPost = client.createEndpoint({
108
+ method: 'POST',
109
+ path: '/posts',
110
+ request: z.object({ title: z.string() }),
111
+ response: {
112
+ 201: z.object({ id: z.string(), status: z.literal('created') }),
113
+ 400: z.object({ error: z.string(), code: z.literal('validation_error') }),
292
114
  },
293
115
  });
294
116
 
295
- // Use specific base URL for a request
296
- await endpoint.call(data, { baseUrlKey: 'auth' });
117
+ const result = await createPost.call({ data: { title: 'Hello' } });
118
+ // `result` type is the union of the 201 and 400 schemas
297
119
  ```
298
120
 
299
- ### Request Options
121
+ ### Metrics & Logging
300
122
 
301
- ```typescript
302
- await endpoint.call(data, {
303
- headers: { 'X-Custom-Header': 'value' },
304
- baseUrlKey: 'v2',
305
- signal: abortController.signal,
306
- query: { filter: 'active', page: 1 },
307
- });
308
- ```
309
-
310
- ### Logging and Metrics
311
-
312
- #### Structured Logging
123
+ Integrate with any monitoring stack (Datadog, Prometheus, etc.).
313
124
 
314
125
  ```typescript
315
- import { HttpClient, ConsoleLogger, LogLevel } from 'zlient';
126
+ import { InMemoryMetricsCollector, ConsoleLogger } from 'zlient';
316
127
 
317
128
  const client = new HttpClient({
318
- baseUrls: { default: 'https://api.example.com' },
319
- logger: new ConsoleLogger(LogLevel.INFO),
129
+ baseUrls: { default: '...' },
130
+ logger: new ConsoleLogger(),
131
+ metrics: new InMemoryMetricsCollector(),
320
132
  });
321
-
322
- // All requests are automatically logged with duration, status, etc.
323
- ```
324
-
325
- #### Metrics Collection
326
-
327
- ```typescript
328
- import { HttpClient, InMemoryMetricsCollector } from 'zlient';
329
-
330
- const metrics = new InMemoryMetricsCollector();
331
- const client = new HttpClient({
332
- baseUrls: { default: 'https://api.example.com' },
333
- metrics,
334
- });
335
-
336
- // View metrics summary
337
- const summary = metrics.getSummary();
338
- console.log(`Success rate: ${(summary.successful / summary.total * 100).toFixed(2)}%`);
339
- console.log(`Avg duration: ${summary.avgDurationMs}ms`);
340
133
  ```
341
134
 
342
- #### Custom Logger/Metrics Integration
343
-
344
- ```typescript
345
- import { Logger, LogEntry, MetricsCollector, RequestMetrics } from 'zlient';
346
-
347
- // Integrate with your logging service (e.g., DataDog, CloudWatch)
348
- class CustomLogger implements Logger {
349
- log(entry: LogEntry) {
350
- // Send to your logging service
351
- myLoggingService.log(entry);
352
- }
353
- }
354
-
355
- class CustomMetrics implements MetricsCollector {
356
- collect(metrics: RequestMetrics) {
357
- // Send to your metrics service (e.g., Prometheus, DataDog)
358
- dogstatsd.histogram('http.request.duration', metrics.durationMs);
359
- }
360
- }
361
-
362
- const client = new HttpClient({
363
- baseUrls: { default: 'https://api.example.com' },
364
- logger: new CustomLogger(),
365
- metrics: new CustomMetrics(),
366
- });
367
- ```
368
-
369
- ### Convenience Methods
370
-
371
- ```typescript
372
- // Use shortcuts instead of full request() method
373
- const { data: users } = await client.get('/users', { query: { page: 1 } });
374
- const { data: user } = await client.post('/users', { name: 'John' });
375
- const { data: updated } = await client.put('/users/1', { name: 'Jane' });
376
- const { data: patched } = await client.patch('/users/1', { email: 'new@email.com' });
377
- await client.delete('/users/1');
378
- ```
379
-
380
- ### Error Handling
381
-
382
- ```typescript
383
- import { ApiError } from 'zlient';
384
-
385
- try {
386
- await endpoint.call(data);
387
- } catch (error) {
388
- if (error instanceof ApiError) {
389
- console.error('API Error:', error.message);
390
- console.error('Status:', error.status);
391
- console.error('Details:', error.details);
392
-
393
- // Check error type
394
- if (error.isValidationError()) {
395
- console.error('Validation errors:', error.zodError?.issues);
396
- }
397
- if (error.isClientError()) {
398
- console.error('Client error (4xx)');
399
- }
400
- if (error.isServerError()) {
401
- console.error('Server error (5xx)');
402
- }
403
-
404
- // Get full error details
405
- console.error(JSON.stringify(error.toJSON(), null, 2));
406
- }
407
- }
408
- ```
409
-
410
- ## Building from Source
411
-
412
- ```bash
413
- # Clone the repository
414
- git clone <your-repo-url>
415
- cd zlient
416
-
417
- # Install dependencies
418
- bun install
419
-
420
- # Build the package
421
- bun run build
422
- ```
135
+ ---
423
136
 
424
137
  ## License
425
138
 
426
- MIT
427
-
428
- ## Contributing
429
-
430
- Contributions are welcome! Please open an issue or submit a pull request.
139
+ MIT © [Emirhan Gumus](https://github.com/emirhangumus)
@@ -16,7 +16,7 @@ export type EndpointCallParams<ReqSchema extends z.ZodType | undefined, QuerySch
16
16
  query?: QuerySchema extends z.ZodType ? z.infer<QuerySchema> : never;
17
17
  pathParams?: PathSchema extends z.ZodType ? z.infer<PathSchema> : never;
18
18
  headers?: Record<string, string>;
19
- signal?: AbortSignal;
19
+ signal?: globalThis.AbortSignal;
20
20
  };
21
21
  type InferResponse<S> = S extends z.ZodType ? z.infer<S> : S extends Record<number, z.ZodType> ? z.infer<S[keyof S]> : never;
22
22
  export declare class Endpoint<ResSchema extends z.ZodType | Record<number, z.ZodType>, ReqSchema extends z.ZodType | undefined, QuerySchema extends z.ZodType | undefined, PathSchema extends z.ZodType | undefined> {
@@ -1 +1 @@
1
- {"version":3,"file":"base-endpoint.d.ts","sourceRoot":"","sources":["../../lib/endpoint/base-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAyB,MAAM,UAAU,CAAC;AAG7D,MAAM,MAAM,cAAc,CACxB,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EACvD,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,EACnD,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,EACrD,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,IAClD;IACF,MAAM,EAAE,MAAM,OAAO,UAAU,CAAC;IAChC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAC7E,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAC5B,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACvC,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACzC,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,IACtC;IACF,IAAI,CAAC,EAAE,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;IAChE,KAAK,CAAC,EAAE,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;IACrE,UAAU,CAAC,EAAE,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAGF,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,GACvC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,GACnC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GACnB,KAAK,CAAC;AAEV,qBAAa,QAAQ,CACnB,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EACvD,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACvC,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACzC,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS;IAGtC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;gBADN,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC;IAGzE,IAAI,CACR,MAAM,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,GAC7D,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAkErC"}
1
+ {"version":3,"file":"base-endpoint.d.ts","sourceRoot":"","sources":["../../lib/endpoint/base-endpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAyB,MAAM,UAAU,CAAC;AAG7D,MAAM,MAAM,cAAc,CACxB,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EACvD,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,EACnD,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,EACrD,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,SAAS,IAClD;IACF,MAAM,EAAE,MAAM,OAAO,UAAU,CAAC;IAChC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;IAC7E,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,kBAAkB,CAC5B,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACvC,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACzC,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,IACtC;IACF,IAAI,CAAC,EAAE,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;IAChE,KAAK,CAAC,EAAE,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;IACrE,UAAU,CAAC,EAAE,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,UAAU,CAAC,WAAW,CAAC;CACjC,CAAC;AAGF,KAAK,aAAa,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,GACvC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GACV,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,GACnC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GACnB,KAAK,CAAC;AAEV,qBAAa,QAAQ,CACnB,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EACvD,SAAS,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACvC,WAAW,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS,EACzC,UAAU,SAAS,CAAC,CAAC,OAAO,GAAG,SAAS;IAGtC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;gBADN,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC;IAGzE,IAAI,CACR,MAAM,EAAE,kBAAkB,CAAC,SAAS,EAAE,WAAW,EAAE,UAAU,CAAC,GAC7D,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAoErC"}
@@ -1 +1 @@
1
- {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../lib/http/http-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../lib/http/http-client.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","message: string","options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }","status: number","q?: RequestOptions['query']","s","schema: z.ZodType","data: unknown","client: HttpClient","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>","pathStr: string","z","minLevel: LogLevel","entry: LogEntry","_entry: LogEntry","logger: Logger","message: string","context?: Record<string, unknown>","error?: Error","_metrics: RequestMetrics","metrics: RequestMetrics","opts: ClientOptions","auth: AuthProvider","key?: keyof typeof this.baseUrls","k: string","ms: number","fn: () => Promise<T>","canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean","err: unknown","url: string","init: RequestInit & { __urlOverride?: string }","req: Request","res: Response","parsed?: unknown","key: string","method: keyof typeof HTTPMethod","path: string","body?: unknown","options?: RequestOptions","timeoutId: NodeJS.Timeout | number | undefined","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","inner: T"],"sources":["../lib/auth.ts","../lib/types.ts","../lib/validation.ts","../lib/endpoint/base-endpoint.ts","../lib/logger.ts","../lib/metrics.ts","../lib/http/http-client.ts","../lib/schemas/common.ts"],"sourcesContent":["import type { RequestOptions as ReqOpts } from './types';\n\n/**\n * Extended RequestInit with URL override capability for query-based auth.\n */\nexport interface AuthContext {\n url: string;\n init: RequestInit & { __urlOverride?: string };\n options?: ReqOpts;\n}\n\n/**\n * Interface for authentication providers.\n * Implement this to create custom authentication strategies.\n *\n * @example\n * ```ts\n * class CustomAuth implements AuthProvider {\n * async apply({ init }) {\n * init.headers = { ...init.headers, 'X-Custom-Auth': 'token' };\n * }\n * }\n * ```\n */\nexport interface AuthProvider {\n /**\n * Apply authentication to the outgoing request.\n * Called after SDK headers are assembled, but before request is sent.\n *\n * @param req - Request context including URL, init, and options\n */\n apply(req: AuthContext): Promise<void> | void;\n}\n\n/**\n * No-op authentication provider (no authentication applied).\n * Use this when you don't need authentication.\n */\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\n/**\n * API Key authentication provider.\n * Supports both header-based and query parameter-based authentication.\n *\n * @example\n * ```ts\n * // Header-based\n * const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });\n *\n * // Query parameter-based\n * const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });\n * ```\n */\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {\n if (!opts.header && !opts.query) {\n throw new Error('ApiKeyAuth requires either \"header\" or \"query\" option');\n }\n if (opts.header && opts.query) {\n throw new Error('ApiKeyAuth cannot use both \"header\" and \"query\" options');\n }\n }\n apply({ url, init }: AuthContext) {\n const value = this.opts.value;\n if (this.opts.header) {\n if (init.headers instanceof Headers) {\n init.headers.set(this.opts.header, value);\n } else if (Array.isArray(init.headers)) {\n init.headers.push([this.opts.header, value]);\n } else {\n init.headers = { ...init.headers, [this.opts.header]: value };\n }\n } else if (this.opts.query) {\n const u = new URL(url);\n u.searchParams.set(this.opts.query, value);\n init.__urlOverride = u.toString();\n }\n }\n}\n/**\n * Bearer token authentication provider.\n * Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).\n *\n * @example\n * ```ts\n * // Static token\n * const auth = new BearerTokenAuth(() => 'my-token');\n *\n * // Dynamic token with refresh\n * const auth = new BearerTokenAuth(async () => {\n * return await refreshAccessToken();\n * });\n * ```\n */\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) { }\n async apply({ init }: AuthContext) {\n const token = await this.getToken();\n if (!token) {\n throw new Error('BearerTokenAuth: token is empty or undefined');\n }\n const authHeader = `Bearer ${token}`;\n if (init.headers instanceof Headers) {\n init.headers.set('Authorization', authHeader);\n } else if (Array.isArray(init.headers)) {\n init.headers.push(['Authorization', authHeader]);\n } else {\n init.headers = { ...init.headers, Authorization: authHeader };\n }\n }\n}\n","import { z, ZodError } from 'zod';\nimport { AuthProvider } from './auth';\nimport { Logger } from './logger';\nimport { MetricsCollector } from './metrics';\n\nexport type Dictionary<T> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Map of base URLs for different services.\n * The 'default' key is required and used when no specific key is provided.\n *\n * @example\n * ```ts\n * {\n * default: 'https://api.example.com',\n * auth: 'https://auth.example.com',\n * cdn: 'https://cdn.example.com'\n * }\n * ```\n */\nexport type BaseUrlMap = {\n default: string;\n} & Record<string, string>;\n\n/**\n * Configuration for retry behavior on failed requests.\n * Implements exponential backoff with optional jitter.\n *\n * @example\n * ```ts\n * {\n * maxRetries: 3,\n * baseDelayMs: 1000,\n * jitter: 0.2,\n * retryMethods: ['GET', 'HEAD', 'PUT']\n * }\n * ```\n */\nexport type RetryStrategy = {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds (will be exponentially increased) */\n baseDelayMs: number;\n /** Jitter factor 0..1 to randomize delays and prevent thundering herd */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** HTTP status codes eligible for retry */\n retryStatusCodes?: (keyof typeof HTTPStatusCode)[];\n /** Custom function to determine if a request should be retried */\n shouldRetry?: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean;\n};\n\nexport const HTTPMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n HEAD: 'HEAD',\n OPTIONS: 'OPTIONS',\n} as const;\n\nexport type HttpMethod = keyof typeof HTTPMethod;\n\nexport const HTTPStatusCode = {\n // 1xx — Informational\n CONTINUE: 100,\n SWITCHING_PROTOCOLS: 101,\n PROCESSING: 102,\n EARLY_HINTS: 103,\n\n // 2xx — Success\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NON_AUTHORITATIVE_INFORMATION: 203,\n NO_CONTENT: 204,\n RESET_CONTENT: 205,\n PARTIAL_CONTENT: 206,\n MULTI_STATUS: 207,\n ALREADY_REPORTED: 208,\n IM_USED: 226,\n\n // 3xx — Redirection\n MULTIPLE_CHOICES: 300,\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n SEE_OTHER: 303,\n NOT_MODIFIED: 304,\n USE_PROXY: 305,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n\n // 4xx — Client Errors\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n LENGTH_REQUIRED: 411,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n URI_TOO_LONG: 414,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n EXPECTATION_FAILED: 417,\n IM_A_TEAPOT: 418,\n MISDIRECTED_REQUEST: 421,\n UNPROCESSABLE_ENTITY: 422,\n LOCKED: 423,\n FAILED_DEPENDENCY: 424,\n TOO_EARLY: 425,\n UPGRADE_REQUIRED: 426,\n PRECONDITION_REQUIRED: 428,\n TOO_MANY_REQUESTS: 429,\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n\n // 5xx — Server Errors\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n VARIANT_ALSO_NEGOTIATES: 506,\n INSUFFICIENT_STORAGE: 507,\n LOOP_DETECTED: 508,\n NOT_EXTENDED: 510,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n} as const;\n\nexport type HTTPStatusCode = keyof typeof HTTPStatusCode;\nexport type HTTPStatusCodeNumber = typeof HTTPStatusCode[HTTPStatusCode];\n\n/**\n * Hook called after a response is received and parsed.\n * Useful for logging, metrics, or global error handling.\n */\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\n/**\n * Hook called before a request is sent.\n * Useful for logging, adding headers, or modifying the request.\n */\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n /** Hooks executed before each request is sent */\n beforeRequest?: BeforeRequestHook[];\n /** Hooks executed after each response is received */\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** Request timeout in milliseconds */\n requestTimeoutMs?: number;\n}\n\n/**\n * Configuration options for the HTTP client.\n *\n * @example\n * ```ts\n * const options: ClientOptions = {\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'X-API-Version': '1.0' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * }\n * ```\n */\nexport interface ClientOptions {\n /** Map of base URLs for different services */\n baseUrls: BaseUrlMap;\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: FetchLike;\n /** Default headers applied to all requests */\n headers?: Record<string, string>;\n /** Retry strategy configuration */\n retry?: RetryStrategy;\n /** Request/response interceptors */\n interceptors?: Interceptors;\n /** Timeout configuration */\n timeout?: TimeoutOptions;\n /** Authentication provider */\n auth?: AuthProvider;\n /** Logger instance */\n logger?: Logger;\n /** Metrics collector */\n metrics?: MetricsCollector;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\n\n/**\n * Custom error class for API-related errors.\n * Includes HTTP status codes, response details, and validation errors.\n *\n * @example\n * ```ts\n * throw new ApiError('Invalid request', {\n * status: 400,\n * details: { field: 'email', message: 'Invalid format' }\n * });\n * ```\n */\nexport class ApiError extends Error {\n public status?: number;\n public details?: unknown;\n public zodError?: ZodError;\n\n constructor(\n message: string,\n options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = options?.status;\n this.details = options?.details;\n this.cause = options?.cause;\n this.zodError = options?.zodError;\n\n // Maintains proper stack trace for where error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n\n /**\n * Check if this is a validation error (has zodError)\n */\n isValidationError(): boolean {\n return !!this.zodError;\n }\n\n /**\n * Check if this is a client error (4xx status)\n */\n isClientError(): boolean {\n return !!this.status && this.status >= 400 && this.status < 500;\n }\n\n /**\n * Check if this is a server error (5xx status)\n */\n isServerError(): boolean {\n return !!this.status && this.status >= 500;\n }\n\n /**\n * Get a formatted error message with all available details\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details,\n zodError: this.zodError?.issues,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Error thrown when an endpoint receives a response with a status code\n * that has no defined schema in the endpoint configuration.\n */\nexport class SchemaDefinitionError extends Error {\n constructor(public status: number) {\n super(`No schema defined for status code ${status}`);\n this.name = 'SchemaDefinitionError';\n\n // Maintains proper stack trace\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaDefinitionError);\n }\n }\n}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\n\n/**\n * Schema for paginated responses\n */\nexport const PaginationSchema = z.object({\n items: z.array(z.unknown()),\n total: z.number().int().nonnegative(),\n page: z.number().int().nonnegative(),\n pageSize: z.number().int().positive(),\n});\n\n/**\n * Options that can be passed to individual requests to override defaults.\n *\n * @example\n * ```ts\n * await endpoint.call(data, {\n * baseUrlKey: 'v2',\n * headers: { 'X-Custom': 'value' },\n * query: { filter: 'active' }\n * });\n * ```\n */\nexport type RequestOptions = {\n /** Override base URL for a single call */\n baseUrlKey?: keyof BaseUrlMap;\n /** Additional headers for this call only */\n headers?: Record<string, string>;\n /** Abort controller signal for cancellation */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n/**\n * Converts query parameters to a URL query string.\n * Filters out undefined values automatically.\n *\n * @param q - Query parameters as URLSearchParams or object\n * @returns Query string with leading '?' or empty string\n *\n * @example\n * ```ts\n * toQueryString({ page: 1, filter: 'active' }) // \"?page=1&filter=active\"\n * toQueryString({ optional: undefined }) // \"\"\n * ```\n */\nexport function toQueryString(q?: RequestOptions['query']): string {\n if (!q) return '';\n if (q instanceof URLSearchParams) {\n const s = q.toString();\n return s ? `?${s}` : '';\n }\n const params = new URLSearchParams();\n Object.entries(q).forEach(([k, v]) => {\n if (v !== undefined) {\n params.append(k, String(v));\n }\n });\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\n/**\n * Safely parse data with a Zod schema without throwing.\n * Returns a result object with success status and data or error.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Result object with success flag and data/error\n *\n * @example\n * ```ts\n * const result = safeParse(UserSchema, userData);\n * if (result.success) {\n * console.log(result.data);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport function safeParse<T>(schema: z.ZodType, data: unknown): SafeParseResult<T> {\n const res = schema.safeParse(data);\n if (res.success) return { success: true, data: res.data as T };\n return { success: false, error: res.error };\n}\n\n/**\n * Parse data with a Zod schema, throwing an ApiError on validation failure.\n * Use this when you want to fail fast on invalid data.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {ApiError} If validation fails\n *\n * @example\n * ```ts\n * try {\n * const user = parseOrThrow(UserSchema, userData);\n * console.log(user);\n * } catch (error) {\n * if (error instanceof ApiError && error.zodError) {\n * console.error('Validation failed:', error.zodError.issues);\n * }\n * }\n * ```\n */\nexport function parseOrThrow<T>(schema: z.ZodType, data: unknown): T {\n const res = schema.safeParse(data);\n if (!res.success) {\n throw new ApiError('Response validation failed', { zodError: res.error });\n }\n return res.data as T;\n}\n","import { z } from 'zod';\nimport { HttpClient } from '../http/http-client';\nimport { HTTPMethod, SchemaDefinitionError } from '../types';\nimport { parseOrThrow } from '../validation';\n\nexport type EndpointConfig<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n> = {\n method: keyof typeof HTTPMethod;\n path: string | ((params: z.infer<Exclude<PathSchema, undefined>>) => string);\n response: ResSchema;\n request?: ReqSchema;\n query?: QuerySchema;\n pathParams?: PathSchema;\n baseUrlKey?: string;\n description?: string;\n};\n\nexport type EndpointCallParams<\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> = {\n data?: ReqSchema extends z.ZodType ? z.infer<ReqSchema> : never;\n query?: QuerySchema extends z.ZodType ? z.infer<QuerySchema> : never;\n pathParams?: PathSchema extends z.ZodType ? z.infer<PathSchema> : never;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n};\n\n// Helper to extract the response type from a schema which might be a single ZodType or a status map\ntype InferResponse<S> = S extends z.ZodType\n ? z.infer<S>\n : S extends Record<number, z.ZodType>\n ? z.infer<S[keyof S]>\n : never;\n\nexport class Endpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> {\n constructor(\n private client: HttpClient,\n private config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ) { }\n\n async call(\n params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>\n ): Promise<InferResponse<ResSchema>> {\n const { data, query, pathParams, headers, signal } = params;\n\n // Validate Request Body\n if (this.config.request && data !== undefined) {\n const parsed = this.config.request.safeParse(data);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Query Params\n if (this.config.query && query !== undefined) {\n const parsed = this.config.query.safeParse(query);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Path Params\n if (this.config.pathParams && pathParams !== undefined) {\n const parsed = this.config.pathParams.safeParse(pathParams);\n if (!parsed.success) throw parsed.error;\n }\n\n // Check for missing required params\n if (this.config.request && data === undefined) {\n throw new Error('Missing required request body (data)');\n }\n if (this.config.pathParams && pathParams === undefined) {\n throw new Error('Missing required path parameters (pathParams)');\n }\n\n // Resolve Path\n let pathStr: string;\n if (typeof this.config.path === 'function') {\n if (!pathParams) throw new Error('Path function requires pathParams');\n pathStr = this.config.path(pathParams as any);\n } else {\n pathStr = this.config.path;\n }\n\n const { data: responseData, status } = await this.client.request(\n this.config.method,\n pathStr,\n data,\n {\n query: query as any,\n headers,\n baseUrlKey: this.config.baseUrlKey,\n signal,\n }\n );\n\n // Handle Response Validation\n const schema = this.config.response;\n if (schema instanceof z.ZodType) {\n // Single schema for all success codes\n return parseOrThrow(schema, responseData) as InferResponse<ResSchema>;\n }\n\n // Map of status codes\n const specificSchema = (schema as Record<number, z.ZodType>)[status];\n if (!specificSchema) {\n // Fallback or error? For now, rigorous error.\n throw new SchemaDefinitionError(status);\n }\n\n return parseOrThrow(specificSchema, responseData) as InferResponse<ResSchema>;\n }\n}\n","/**\n * Log levels for structured logging.\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Structured log entry with metadata.\n */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/**\n * Logger interface for custom logger implementations.\n * Implement this to integrate with your logging infrastructure.\n *\n * @example\n * ```ts\n * class ConsoleLogger implements Logger {\n * log(entry: LogEntry) {\n * console.log(JSON.stringify(entry));\n * }\n * }\n * ```\n */\nexport interface Logger {\n log(entry: LogEntry): void;\n}\n\n/**\n * Default console logger implementation.\n * Formats log entries as JSON for easy parsing.\n */\nexport class ConsoleLogger implements Logger {\n constructor(private minLevel: LogLevel = LogLevel.INFO) {}\n\n log(entry: LogEntry): void {\n const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];\n const entryLevelIndex = levels.indexOf(entry.level);\n const minLevelIndex = levels.indexOf(this.minLevel);\n\n if (entryLevelIndex < minLevelIndex) return;\n\n const output = {\n ...entry,\n error: entry.error\n ? {\n message: entry.error.message,\n stack: entry.error.stack,\n name: entry.error.name,\n }\n : undefined,\n };\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(JSON.stringify(output));\n break;\n case LogLevel.INFO:\n console.info(JSON.stringify(output));\n break;\n case LogLevel.WARN:\n console.warn(JSON.stringify(output));\n break;\n case LogLevel.ERROR:\n console.error(JSON.stringify(output));\n break;\n }\n }\n}\n\n/**\n * No-op logger that discards all log entries.\n * Use this in production if you don't want any logging.\n */\nexport class NoOpLogger implements Logger {\n log(_entry: LogEntry): void {\n // no-op\n }\n}\n\n/**\n * Utility class for creating structured log entries.\n */\nexport class LoggerUtil {\n constructor(private logger: Logger) {}\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.DEBUG,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.INFO,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.WARN,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n error(message: string, error?: Error, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.ERROR,\n message,\n timestamp: new Date().toISOString(),\n context,\n error,\n });\n }\n}\n","/**\n * Metrics data for HTTP requests.\n */\nexport interface RequestMetrics {\n method: string;\n path: string;\n status?: number;\n durationMs: number;\n timestamp: string;\n success: boolean;\n error?: string;\n}\n\n/**\n * Interface for metrics collectors.\n * Implement this to integrate with your monitoring infrastructure (DataDog, Prometheus, etc.).\n *\n * @example\n * ```ts\n * class DataDogMetrics implements MetricsCollector {\n * collect(metrics: RequestMetrics) {\n * dogstatsd.histogram('http.request.duration', metrics.durationMs, {\n * method: metrics.method,\n * status: String(metrics.status)\n * });\n * }\n * }\n * ```\n */\nexport interface MetricsCollector {\n collect(metrics: RequestMetrics): void;\n}\n\n/**\n * No-op metrics collector that discards all metrics.\n */\nexport class NoOpMetricsCollector implements MetricsCollector {\n collect(_metrics: RequestMetrics): void {\n // no-op\n }\n}\n\n/**\n * In-memory metrics collector for testing and development.\n * Stores metrics in memory with configurable retention.\n */\nexport class InMemoryMetricsCollector implements MetricsCollector {\n private metrics: RequestMetrics[] = [];\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n collect(metrics: RequestMetrics): void {\n this.metrics.push(metrics);\n if (this.metrics.length > this.maxEntries) {\n this.metrics.shift();\n }\n }\n\n /**\n * Get all collected metrics.\n */\n getMetrics(): RequestMetrics[] {\n return [...this.metrics];\n }\n\n /**\n * Get metrics summary statistics.\n */\n getSummary(): {\n total: number;\n successful: number;\n failed: number;\n avgDurationMs: number;\n minDurationMs: number;\n maxDurationMs: number;\n } {\n if (this.metrics.length === 0) {\n return {\n total: 0,\n successful: 0,\n failed: 0,\n avgDurationMs: 0,\n minDurationMs: 0,\n maxDurationMs: 0,\n };\n }\n\n const successful = this.metrics.filter((m) => m.success).length;\n\n // Calculate stats in a single pass to avoid stack overflow with spread operator\n let sum = 0;\n let min = Infinity;\n let max = -Infinity;\n\n for (const m of this.metrics) {\n const d = m.durationMs;\n sum += d;\n if (d < min) min = d;\n if (d > max) max = d;\n }\n\n return {\n total: this.metrics.length,\n successful,\n failed: this.metrics.length - successful,\n avgDurationMs: sum / this.metrics.length,\n minDurationMs: min === Infinity ? 0 : min,\n maxDurationMs: max === -Infinity ? 0 : max,\n };\n }\n\n /**\n * Clear all collected metrics.\n */\n clear(): void {\n this.metrics = [];\n }\n}\n\n/**\n * Console-based metrics collector for debugging.\n */\nexport class ConsoleMetricsCollector implements MetricsCollector {\n collect(metrics: RequestMetrics): void {\n console.log('[METRICS]', JSON.stringify(metrics));\n }\n}\n","import { z } from 'zod';\nimport type { AuthProvider } from '../auth';\nimport { NoAuth } from '../auth';\nimport { Endpoint, EndpointConfig } from '../endpoint/base-endpoint';\nimport { LoggerUtil, NoOpLogger } from '../logger';\nimport { MetricsCollector, NoOpMetricsCollector } from '../metrics';\nimport {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n HTTPStatusCode,\n HTTPStatusCodeNumber,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\n\n/**\n * HTTP client with built-in retry logic, authentication, and interceptors.\n * Supports multiple base URLs, type-safe requests, and comprehensive error handling.\n *\n * @example\n * ```ts\n * const client = new HttpClient({\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'Content-Type': 'application/json' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * });\n *\n * const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });\n * ```\n */\nexport class HttpClient {\n private fetchImpl: FetchLike;\n private baseUrls: ClientOptions['baseUrls'];\n private headers: Record<string, string>;\n private interceptors: Interceptors;\n private retry: RetryStrategy;\n private timeoutMs?: number;\n private auth: AuthProvider;\n private logger: LoggerUtil;\n private metrics: MetricsCollector;\n\n /**\n * Creates a new HTTP client instance.\n *\n * @param opts - Client configuration options\n * @throws {Error} If no fetch implementation is available\n */\n constructor(opts: ClientOptions) {\n this.fetchImpl = opts.fetch ?? (globalThis.fetch?.bind(globalThis) as FetchLike);\n if (!this.fetchImpl)\n throw new Error('No fetch implementation found. Pass one via options.fetch.');\n\n // Validate baseUrls configuration\n if (!opts.baseUrls || typeof opts.baseUrls !== 'object') {\n throw new Error('baseUrls must be provided and must be an object');\n }\n if (!opts.baseUrls.default) {\n throw new Error('baseUrls must include a \"default\" key');\n }\n\n this.baseUrls = opts.baseUrls;\n this.headers = opts.headers ?? { 'Content-Type': 'application/json' };\n this.interceptors = opts.interceptors ?? {};\n this.retry = opts.retry ?? {\n maxRetries: 2,\n baseDelayMs: 250,\n jitter: 0.2,\n retryMethods: ['GET', 'HEAD'],\n };\n\n // Default retryStatusCodes if not provided\n if (!this.retry.retryStatusCodes) {\n this.retry.retryStatusCodes = (Object.keys(HTTPStatusCode) as (keyof typeof HTTPStatusCode)[])\n .filter(key => {\n const code = HTTPStatusCode[key];\n return typeof code === 'number' && code >= 500;\n });\n }\n\n // Validate retry configuration\n if (this.retry.maxRetries < 0) {\n throw new Error('retry.maxRetries must be non-negative');\n }\n if (this.retry.baseDelayMs < 0) {\n throw new Error('retry.baseDelayMs must be non-negative');\n }\n if (this.retry.jitter !== undefined && (this.retry.jitter < 0 || this.retry.jitter > 1)) {\n throw new Error('retry.jitter must be between 0 and 1');\n }\n\n this.timeoutMs = opts.timeout?.requestTimeoutMs;\n if (this.timeoutMs !== undefined && this.timeoutMs < 0) {\n throw new Error('timeout.requestTimeoutMs must be non-negative');\n }\n\n this.auth = opts['auth'] ?? new NoAuth();\n this.logger = new LoggerUtil(opts.logger ?? new NoOpLogger());\n this.metrics = opts.metrics ?? new NoOpMetricsCollector();\n }\n\n /**\n * Set or update the authentication provider.\n *\n * @param auth - Authentication provider instance\n * @example\n * ```ts\n * client.setAuth(new BearerTokenAuth(() => getToken()));\n * ```\n */\n setAuth(auth: AuthProvider) {\n this.auth = auth;\n }\n\n private resolveBaseUrl(key?: keyof typeof this.baseUrls) {\n const k: string = (key as string) || 'default';\n const url = this.baseUrls[k];\n if (!url) {\n const availableKeys = Object.keys(this.baseUrls).join(', ');\n throw new Error(`Unknown baseUrl key: \"${k}\". Available keys: ${availableKeys}`);\n }\n return url.replace(/\\/$/, '');\n }\n\n /**\n * Sleep for a specified duration (used for retry backoff).\n * @private\n */\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\n\n /**\n * Execute a function with retry logic and exponential backoff.\n * @private\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean\n ): Promise<T> {\n let attempt = 0;\n const { maxRetries, baseDelayMs, jitter = 0.2 } = this.retry;\n while (true) {\n try {\n return await fn();\n } catch (err: unknown) {\n if (attempt >= maxRetries || !canRetry({ attempt, error: err })) throw err;\n const backoff = baseDelayMs * 2 ** attempt;\n const j = 1 + (Math.random() * 2 - 1) * jitter;\n await this.sleep(backoff * j);\n attempt++;\n }\n }\n }\n\n /**\n * Run all registered before-request hooks.\n * @private\n */\n private async runBeforeHooks(url: string, init: RequestInit & { __urlOverride?: string }) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\n\n /**\n * Run all registered after-response hooks.\n * @private\n */\n private async runAfterHooks(req: Request, res: Response, parsed?: unknown) {\n for (const h of this.interceptors.afterResponse ?? []) {\n await h({ request: req, response: res, parsed });\n }\n }\n\n /**\n * Get all configured base URLs.\n *\n * @returns Object mapping base URL keys to their resolved URLs\n */\n public getBaseUrls() {\n return this.baseUrls;\n }\n\n /**\n * Get the resolved base URL for a given key.\n *\n * @param key - Base URL key (defaults to 'default' if not provided)\n * @returns Resolved base URL string\n */\n public getBaseUrl(key: string) {\n return this.resolveBaseUrl(key);\n }\n\n /**\n * Make an HTTP request with automatic retry, authentication, and validation.\n *\n * @param method - HTTP method (GET, POST, PUT, etc.)\n * @param path - Request path (will be appended to base URL)\n * @param body - Request body (will be JSON.stringify'd if Content-Type is json)\n * @param options - Additional request options (headers, query params, etc.)\n * @returns Promise resolving to response data and Response object\n * @throws {ApiError} If request fails or response validation fails\n *\n * @example\n * ```ts\n * const { data, response } = await client.request('GET', '/users', undefined, {\n * query: { page: 1, limit: 10 },\n * headers: { 'X-Custom': 'value' }\n * });\n * ```\n */\n async request<T = unknown>(\n method: keyof typeof HTTPMethod,\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n const startTime = Date.now();\n const base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\n\n this.logger.debug('HTTP request initiated', {\n method,\n path,\n baseUrlKey: options?.baseUrlKey,\n hasBody: body !== undefined,\n });\n\n const headers = { ...this.headers, ...(options?.headers ?? {}) };\n\n const controller = new AbortController();\n const signal = options?.signal ?? controller.signal;\n const init: RequestInit & { __urlOverride?: string } = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : String(body)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if (init.__urlOverride) url = init.__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: NodeJS.Timeout | number | undefined;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(() => {\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n controller.abort(timeoutError);\n }, this.timeoutMs);\n }\n\n try {\n const req = new Request(url, init);\n\n const res = await this.fetchImpl(req);\n const status = res.status as HTTPStatusCodeNumber;\n const contentType = res.headers.get('content-type') || '';\n const data = contentType.includes('json') ? await res.json() : await res.text();\n await this.runAfterHooks(new Request(url, init), res, data);\n\n const duration = Date.now() - startTime;\n this.logger.info('HTTP request successful', {\n method,\n url,\n status: res.status,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: res.status,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: true,\n });\n\n return { data: data as T, status: status };\n } catch (error) {\n const duration = Date.now() - startTime;\n this.logger.error('HTTP request failed', error as Error, {\n method,\n url,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: error instanceof ApiError ? error.status : undefined,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n error,\n }: {\n error?: unknown;\n }) => {\n // Don't retry timeouts or aborts\n if (error && typeof error === 'object' && 'name' in error) {\n const errorName = (error as { name?: string }).name;\n if (errorName === 'AbortError' || errorName === 'TimeoutError') return false;\n }\n // Retry on network errors or configured status codes\n if (error instanceof ApiError && error.status) {\n const retryCodes = this.retry.retryStatusCodes;\n if (retryCodes?.some(codeKey => HTTPStatusCode[codeKey] === error.status)) {\n return true;\n }\n }\n return false;\n };\n\n if (!this.retry.retryMethods?.includes(method)) {\n return doFetch();\n }\n\n return this.withRetry(doFetch, canRetry);\n }\n\n /**\n * Convenience method for GET requests.\n *\n * @example\n * ```ts\n * const { data } = await client.get('/users', { query: { page: 1 } });\n * ```\n */\n async get<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n /**\n * Convenience method for POST requests.\n *\n * @example\n * ```ts\n * const { data } = await client.post('/users', { name: 'John' });\n * ```\n */\n async post<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('POST', path, body, options);\n }\n\n /**\n * Convenience method for PUT requests.\n *\n * @example\n * ```ts\n * const { data } = await client.put('/users/1', { name: 'John Updated' });\n * ```\n */\n async put<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PUT', path, body, options);\n }\n\n /**\n * Convenience method for PATCH requests.\n *\n * @example\n * ```ts\n * const { data } = await client.patch('/users/1', { name: 'John' });\n * ```\n */\n async patch<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PATCH', path, body, options);\n }\n\n /**\n * Convenience method for DELETE requests.\n *\n * @example\n * ```ts\n * const { data } = await client.delete('/users/1');\n * ```\n */\n async delete<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n\n /**\n * Create a strongly-typed endpoint builder.\n *\n * @param config - Endpoint configuration\n * @returns Endpoint instance\n */\n createEndpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n >(\n config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ): Endpoint<ResSchema, ReqSchema, QuerySchema, PathSchema> {\n return new Endpoint(this, config);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Common ID type that supports strings, numbers, or UUIDs.\n * Use this for entity identifiers in your schemas.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ id: Id, name: z.string() });\n * ```\n */\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type IdType = z.infer<typeof Id>;\n\n/**\n * Common timestamp fields for entities.\n * Use this for database models with creation/update tracking.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({\n * id: Id,\n * name: z.string(),\n * ...Timestamps.shape\n * });\n * ```\n */\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\n/**\n * Metadata information typically included in API responses.\n * Contains request tracking and debugging information.\n */\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\n/**\n * Detailed error information for a specific field or path.\n */\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\n/**\n * Standard API error response schema.\n * Use this for consistent error handling across your API.\n */\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\n/**\n * Generic envelope wrapper for API responses.\n * Provides consistent structure with success flag, data, error, and metadata.\n *\n * @param inner - Zod schema for the response data\n * @returns Envelope schema wrapping the inner schema\n *\n * @example\n * ```ts\n * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));\n *\n * // Response structure:\n * // {\n * // success: true,\n * // data: { id: 1, name: 'John' },\n * // meta: { requestId: '...' }\n * // }\n * ```\n */\nexport const Envelope = <T extends z.ZodType>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional().nullable(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","message: string","options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }","status: number","q?: RequestOptions['query']","s","schema: z.ZodType","data: unknown","client: HttpClient","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>","pathStr: string","z","minLevel: LogLevel","entry: LogEntry","_entry: LogEntry","logger: Logger","message: string","context?: Record<string, unknown>","error?: Error","_metrics: RequestMetrics","metrics: RequestMetrics","opts: ClientOptions","auth: AuthProvider","key?: keyof typeof this.baseUrls","k: string","ms: number","fn: () => Promise<T>","canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean","err: unknown","url: string","init: RequestInit & { __urlOverride?: string }","req: Request","res: Response","parsed?: unknown","key: string","method: keyof typeof HTTPMethod","path: string","body?: unknown","options?: RequestOptions","timeoutId: NodeJS.Timeout | number | undefined","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","inner: T"],"sources":["../lib/auth.ts","../lib/types.ts","../lib/validation.ts","../lib/endpoint/base-endpoint.ts","../lib/logger.ts","../lib/metrics.ts","../lib/http/http-client.ts","../lib/schemas/common.ts"],"sourcesContent":["import type { RequestOptions as ReqOpts } from './types';\n\n/**\n * Extended RequestInit with URL override capability for query-based auth.\n */\nexport interface AuthContext {\n url: string;\n init: RequestInit & { __urlOverride?: string };\n options?: ReqOpts;\n}\n\n/**\n * Interface for authentication providers.\n * Implement this to create custom authentication strategies.\n *\n * @example\n * ```ts\n * class CustomAuth implements AuthProvider {\n * async apply({ init }) {\n * init.headers = { ...init.headers, 'X-Custom-Auth': 'token' };\n * }\n * }\n * ```\n */\nexport interface AuthProvider {\n /**\n * Apply authentication to the outgoing request.\n * Called after SDK headers are assembled, but before request is sent.\n *\n * @param req - Request context including URL, init, and options\n */\n apply(req: AuthContext): Promise<void> | void;\n}\n\n/**\n * No-op authentication provider (no authentication applied).\n * Use this when you don't need authentication.\n */\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\n/**\n * API Key authentication provider.\n * Supports both header-based and query parameter-based authentication.\n *\n * @example\n * ```ts\n * // Header-based\n * const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });\n *\n * // Query parameter-based\n * const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });\n * ```\n */\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {\n if (!opts.header && !opts.query) {\n throw new Error('ApiKeyAuth requires either \"header\" or \"query\" option');\n }\n if (opts.header && opts.query) {\n throw new Error('ApiKeyAuth cannot use both \"header\" and \"query\" options');\n }\n }\n apply({ url, init }: AuthContext) {\n const value = this.opts.value;\n if (this.opts.header) {\n if (init.headers instanceof Headers) {\n init.headers.set(this.opts.header, value);\n } else if (Array.isArray(init.headers)) {\n init.headers.push([this.opts.header, value]);\n } else {\n init.headers = { ...init.headers, [this.opts.header]: value };\n }\n } else if (this.opts.query) {\n const u = new URL(url);\n u.searchParams.set(this.opts.query, value);\n init.__urlOverride = u.toString();\n }\n }\n}\n/**\n * Bearer token authentication provider.\n * Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).\n *\n * @example\n * ```ts\n * // Static token\n * const auth = new BearerTokenAuth(() => 'my-token');\n *\n * // Dynamic token with refresh\n * const auth = new BearerTokenAuth(async () => {\n * return await refreshAccessToken();\n * });\n * ```\n */\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: AuthContext) {\n const token = await this.getToken();\n if (!token) {\n throw new Error('BearerTokenAuth: token is empty or undefined');\n }\n const authHeader = `Bearer ${token}`;\n if (init.headers instanceof Headers) {\n init.headers.set('Authorization', authHeader);\n } else if (Array.isArray(init.headers)) {\n init.headers.push(['Authorization', authHeader]);\n } else {\n init.headers = { ...init.headers, Authorization: authHeader };\n }\n }\n}\n","import { z, ZodError } from 'zod';\nimport { AuthProvider } from './auth';\nimport { Logger } from './logger';\nimport { MetricsCollector } from './metrics';\n\nexport type Dictionary<T> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Map of base URLs for different services.\n * The 'default' key is required and used when no specific key is provided.\n *\n * @example\n * ```ts\n * {\n * default: 'https://api.example.com',\n * auth: 'https://auth.example.com',\n * cdn: 'https://cdn.example.com'\n * }\n * ```\n */\nexport type BaseUrlMap = {\n default: string;\n} & Record<string, string>;\n\n/**\n * Configuration for retry behavior on failed requests.\n * Implements exponential backoff with optional jitter.\n *\n * @example\n * ```ts\n * {\n * maxRetries: 3,\n * baseDelayMs: 1000,\n * jitter: 0.2,\n * retryMethods: ['GET', 'HEAD', 'PUT']\n * }\n * ```\n */\nexport type RetryStrategy = {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds (will be exponentially increased) */\n baseDelayMs: number;\n /** Jitter factor 0..1 to randomize delays and prevent thundering herd */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** HTTP status codes eligible for retry */\n retryStatusCodes?: (keyof typeof HTTPStatusCode)[];\n /** Custom function to determine if a request should be retried */\n shouldRetry?: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean;\n};\n\nexport const HTTPMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n HEAD: 'HEAD',\n OPTIONS: 'OPTIONS',\n} as const;\n\nexport type HttpMethod = keyof typeof HTTPMethod;\n\nexport const HTTPStatusCode = {\n // 1xx — Informational\n CONTINUE: 100,\n SWITCHING_PROTOCOLS: 101,\n PROCESSING: 102,\n EARLY_HINTS: 103,\n\n // 2xx — Success\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NON_AUTHORITATIVE_INFORMATION: 203,\n NO_CONTENT: 204,\n RESET_CONTENT: 205,\n PARTIAL_CONTENT: 206,\n MULTI_STATUS: 207,\n ALREADY_REPORTED: 208,\n IM_USED: 226,\n\n // 3xx — Redirection\n MULTIPLE_CHOICES: 300,\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n SEE_OTHER: 303,\n NOT_MODIFIED: 304,\n USE_PROXY: 305,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n\n // 4xx — Client Errors\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n LENGTH_REQUIRED: 411,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n URI_TOO_LONG: 414,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n EXPECTATION_FAILED: 417,\n IM_A_TEAPOT: 418,\n MISDIRECTED_REQUEST: 421,\n UNPROCESSABLE_ENTITY: 422,\n LOCKED: 423,\n FAILED_DEPENDENCY: 424,\n TOO_EARLY: 425,\n UPGRADE_REQUIRED: 426,\n PRECONDITION_REQUIRED: 428,\n TOO_MANY_REQUESTS: 429,\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n\n // 5xx — Server Errors\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n VARIANT_ALSO_NEGOTIATES: 506,\n INSUFFICIENT_STORAGE: 507,\n LOOP_DETECTED: 508,\n NOT_EXTENDED: 510,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n} as const;\n\nexport type HTTPStatusCode = keyof typeof HTTPStatusCode;\nexport type HTTPStatusCodeNumber = (typeof HTTPStatusCode)[HTTPStatusCode];\n\n/**\n * Hook called after a response is received and parsed.\n * Useful for logging, metrics, or global error handling.\n */\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\n/**\n * Hook called before a request is sent.\n * Useful for logging, adding headers, or modifying the request.\n */\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n /** Hooks executed before each request is sent */\n beforeRequest?: BeforeRequestHook[];\n /** Hooks executed after each response is received */\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** Request timeout in milliseconds */\n requestTimeoutMs?: number;\n}\n\n/**\n * Configuration options for the HTTP client.\n *\n * @example\n * ```ts\n * const options: ClientOptions = {\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'X-API-Version': '1.0' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * }\n * ```\n */\nexport interface ClientOptions {\n /** Map of base URLs for different services */\n baseUrls: BaseUrlMap;\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: FetchLike;\n /** Default headers applied to all requests */\n headers?: Record<string, string>;\n /** Retry strategy configuration */\n retry?: RetryStrategy;\n /** Request/response interceptors */\n interceptors?: Interceptors;\n /** Timeout configuration */\n timeout?: TimeoutOptions;\n /** Authentication provider */\n auth?: AuthProvider;\n /** Logger instance */\n logger?: Logger;\n /** Metrics collector */\n metrics?: MetricsCollector;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\n\n/**\n * Custom error class for API-related errors.\n * Includes HTTP status codes, response details, and validation errors.\n *\n * @example\n * ```ts\n * throw new ApiError('Invalid request', {\n * status: 400,\n * details: { field: 'email', message: 'Invalid format' }\n * });\n * ```\n */\nexport class ApiError extends Error {\n public status?: number;\n public details?: unknown;\n public zodError?: ZodError;\n\n constructor(\n message: string,\n options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = options?.status;\n this.details = options?.details;\n this.cause = options?.cause;\n this.zodError = options?.zodError;\n\n // Maintains proper stack trace for where error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n\n /**\n * Check if this is a validation error (has zodError)\n */\n isValidationError(): boolean {\n return !!this.zodError;\n }\n\n /**\n * Check if this is a client error (4xx status)\n */\n isClientError(): boolean {\n return !!this.status && this.status >= 400 && this.status < 500;\n }\n\n /**\n * Check if this is a server error (5xx status)\n */\n isServerError(): boolean {\n return !!this.status && this.status >= 500;\n }\n\n /**\n * Get a formatted error message with all available details\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details,\n zodError: this.zodError?.issues,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Error thrown when an endpoint receives a response with a status code\n * that has no defined schema in the endpoint configuration.\n */\nexport class SchemaDefinitionError extends Error {\n constructor(public status: number) {\n super(`No schema defined for status code ${status}`);\n this.name = 'SchemaDefinitionError';\n\n // Maintains proper stack trace\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaDefinitionError);\n }\n }\n}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\n\n/**\n * Schema for paginated responses\n */\nexport const PaginationSchema = z.object({\n items: z.array(z.unknown()),\n total: z.number().int().nonnegative(),\n page: z.number().int().nonnegative(),\n pageSize: z.number().int().positive(),\n});\n\n/**\n * Options that can be passed to individual requests to override defaults.\n *\n * @example\n * ```ts\n * await endpoint.call(data, {\n * baseUrlKey: 'v2',\n * headers: { 'X-Custom': 'value' },\n * query: { filter: 'active' }\n * });\n * ```\n */\nexport type RequestOptions = {\n /** Override base URL for a single call */\n baseUrlKey?: keyof BaseUrlMap;\n /** Additional headers for this call only */\n headers?: Record<string, string>;\n /** Abort controller signal for cancellation */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n/**\n * Converts query parameters to a URL query string.\n * Filters out undefined values automatically.\n *\n * @param q - Query parameters as URLSearchParams or object\n * @returns Query string with leading '?' or empty string\n *\n * @example\n * ```ts\n * toQueryString({ page: 1, filter: 'active' }) // \"?page=1&filter=active\"\n * toQueryString({ optional: undefined }) // \"\"\n * ```\n */\nexport function toQueryString(q?: RequestOptions['query']): string {\n if (!q) return '';\n if (q instanceof URLSearchParams) {\n const s = q.toString();\n return s ? `?${s}` : '';\n }\n const params = new URLSearchParams();\n Object.entries(q).forEach(([k, v]) => {\n if (v !== undefined) {\n params.append(k, String(v));\n }\n });\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\n/**\n * Safely parse data with a Zod schema without throwing.\n * Returns a result object with success status and data or error.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Result object with success flag and data/error\n *\n * @example\n * ```ts\n * const result = safeParse(UserSchema, userData);\n * if (result.success) {\n * console.log(result.data);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport function safeParse<T>(schema: z.ZodType, data: unknown): SafeParseResult<T> {\n const res = schema.safeParse(data);\n if (res.success) return { success: true, data: res.data as T };\n return { success: false, error: res.error };\n}\n\n/**\n * Parse data with a Zod schema, throwing an ApiError on validation failure.\n * Use this when you want to fail fast on invalid data.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {ApiError} If validation fails\n *\n * @example\n * ```ts\n * try {\n * const user = parseOrThrow(UserSchema, userData);\n * console.log(user);\n * } catch (error) {\n * if (error instanceof ApiError && error.zodError) {\n * console.error('Validation failed:', error.zodError.issues);\n * }\n * }\n * ```\n */\nexport function parseOrThrow<T>(schema: z.ZodType, data: unknown): T {\n const res = schema.safeParse(data);\n if (!res.success) {\n throw new ApiError('Response validation failed', { zodError: res.error });\n }\n return res.data as T;\n}\n","import { z } from 'zod';\nimport { HttpClient } from '../http/http-client';\nimport { HTTPMethod, SchemaDefinitionError } from '../types';\nimport { parseOrThrow } from '../validation';\n\nexport type EndpointConfig<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n> = {\n method: keyof typeof HTTPMethod;\n path: string | ((params: z.infer<Exclude<PathSchema, undefined>>) => string);\n response: ResSchema;\n request?: ReqSchema;\n query?: QuerySchema;\n pathParams?: PathSchema;\n baseUrlKey?: string;\n description?: string;\n};\n\nexport type EndpointCallParams<\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> = {\n data?: ReqSchema extends z.ZodType ? z.infer<ReqSchema> : never;\n query?: QuerySchema extends z.ZodType ? z.infer<QuerySchema> : never;\n pathParams?: PathSchema extends z.ZodType ? z.infer<PathSchema> : never;\n headers?: Record<string, string>;\n signal?: globalThis.AbortSignal;\n};\n\n// Helper to extract the response type from a schema which might be a single ZodType or a status map\ntype InferResponse<S> = S extends z.ZodType\n ? z.infer<S>\n : S extends Record<number, z.ZodType>\n ? z.infer<S[keyof S]>\n : never;\n\nexport class Endpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> {\n constructor(\n private client: HttpClient,\n private config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ) { }\n\n async call(\n params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>\n ): Promise<InferResponse<ResSchema>> {\n const { data, query, pathParams, headers, signal } = params;\n\n // Validate Request Body\n if (this.config.request && data !== undefined) {\n const parsed = this.config.request.safeParse(data);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Query Params\n if (this.config.query && query !== undefined) {\n const parsed = this.config.query.safeParse(query);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Path Params\n if (this.config.pathParams && pathParams !== undefined) {\n const parsed = this.config.pathParams.safeParse(pathParams);\n if (!parsed.success) throw parsed.error;\n }\n\n // Check for missing required params\n if (this.config.request && data === undefined) {\n throw new Error('Missing required request body (data)');\n }\n if (this.config.pathParams && pathParams === undefined) {\n throw new Error('Missing required path parameters (pathParams)');\n }\n\n // Resolve Path\n let pathStr: string;\n if (typeof this.config.path === 'function') {\n if (!pathParams) throw new Error('Path function requires pathParams');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n pathStr = this.config.path(pathParams as any);\n } else {\n pathStr = this.config.path;\n }\n\n const { data: responseData, status } = await this.client.request(\n this.config.method,\n pathStr,\n data,\n {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n query: query as any,\n headers,\n baseUrlKey: this.config.baseUrlKey,\n signal,\n }\n );\n\n // Handle Response Validation\n const schema = this.config.response;\n if (schema instanceof z.ZodType) {\n // Single schema for all success codes\n return parseOrThrow(schema, responseData) as InferResponse<ResSchema>;\n }\n\n // Map of status codes\n const specificSchema = (schema as Record<number, z.ZodType>)[status];\n if (!specificSchema) {\n // Fallback or error? For now, rigorous error.\n throw new SchemaDefinitionError(status);\n }\n\n return parseOrThrow(specificSchema, responseData) as InferResponse<ResSchema>;\n }\n}\n","/**\n * Log levels for structured logging.\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Structured log entry with metadata.\n */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/**\n * Logger interface for custom logger implementations.\n * Implement this to integrate with your logging infrastructure.\n *\n * @example\n * ```ts\n * class ConsoleLogger implements Logger {\n * log(entry: LogEntry) {\n * console.log(JSON.stringify(entry));\n * }\n * }\n * ```\n */\nexport interface Logger {\n log(entry: LogEntry): void;\n}\n\n/**\n * Default console logger implementation.\n * Formats log entries as JSON for easy parsing.\n */\nexport class ConsoleLogger implements Logger {\n constructor(private minLevel: LogLevel = LogLevel.INFO) {}\n\n log(entry: LogEntry): void {\n const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];\n const entryLevelIndex = levels.indexOf(entry.level);\n const minLevelIndex = levels.indexOf(this.minLevel);\n\n if (entryLevelIndex < minLevelIndex) return;\n\n const output = {\n ...entry,\n error: entry.error\n ? {\n message: entry.error.message,\n stack: entry.error.stack,\n name: entry.error.name,\n }\n : undefined,\n };\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(JSON.stringify(output));\n break;\n case LogLevel.INFO:\n console.info(JSON.stringify(output));\n break;\n case LogLevel.WARN:\n console.warn(JSON.stringify(output));\n break;\n case LogLevel.ERROR:\n console.error(JSON.stringify(output));\n break;\n }\n }\n}\n\n/**\n * No-op logger that discards all log entries.\n * Use this in production if you don't want any logging.\n */\nexport class NoOpLogger implements Logger {\n log(_entry: LogEntry): void {\n // no-op\n }\n}\n\n/**\n * Utility class for creating structured log entries.\n */\nexport class LoggerUtil {\n constructor(private logger: Logger) {}\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.DEBUG,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.INFO,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.WARN,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n error(message: string, error?: Error, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.ERROR,\n message,\n timestamp: new Date().toISOString(),\n context,\n error,\n });\n }\n}\n","/**\n * Metrics data for HTTP requests.\n */\nexport interface RequestMetrics {\n method: string;\n path: string;\n status?: number;\n durationMs: number;\n timestamp: string;\n success: boolean;\n error?: string;\n}\n\n/**\n * Interface for metrics collectors.\n * Implement this to integrate with your monitoring infrastructure (DataDog, Prometheus, etc.).\n *\n * @example\n * ```ts\n * class DataDogMetrics implements MetricsCollector {\n * collect(metrics: RequestMetrics) {\n * dogstatsd.histogram('http.request.duration', metrics.durationMs, {\n * method: metrics.method,\n * status: String(metrics.status)\n * });\n * }\n * }\n * ```\n */\nexport interface MetricsCollector {\n collect(metrics: RequestMetrics): void;\n}\n\n/**\n * No-op metrics collector that discards all metrics.\n */\nexport class NoOpMetricsCollector implements MetricsCollector {\n collect(_metrics: RequestMetrics): void {\n // no-op\n }\n}\n\n/**\n * In-memory metrics collector for testing and development.\n * Stores metrics in memory with configurable retention.\n */\nexport class InMemoryMetricsCollector implements MetricsCollector {\n private metrics: RequestMetrics[] = [];\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n collect(metrics: RequestMetrics): void {\n this.metrics.push(metrics);\n if (this.metrics.length > this.maxEntries) {\n this.metrics.shift();\n }\n }\n\n /**\n * Get all collected metrics.\n */\n getMetrics(): RequestMetrics[] {\n return [...this.metrics];\n }\n\n /**\n * Get metrics summary statistics.\n */\n getSummary(): {\n total: number;\n successful: number;\n failed: number;\n avgDurationMs: number;\n minDurationMs: number;\n maxDurationMs: number;\n } {\n if (this.metrics.length === 0) {\n return {\n total: 0,\n successful: 0,\n failed: 0,\n avgDurationMs: 0,\n minDurationMs: 0,\n maxDurationMs: 0,\n };\n }\n\n const successful = this.metrics.filter((m) => m.success).length;\n\n // Calculate stats in a single pass to avoid stack overflow with spread operator\n let sum = 0;\n let min = Infinity;\n let max = -Infinity;\n\n for (const m of this.metrics) {\n const d = m.durationMs;\n sum += d;\n if (d < min) min = d;\n if (d > max) max = d;\n }\n\n return {\n total: this.metrics.length,\n successful,\n failed: this.metrics.length - successful,\n avgDurationMs: sum / this.metrics.length,\n minDurationMs: min === Infinity ? 0 : min,\n maxDurationMs: max === -Infinity ? 0 : max,\n };\n }\n\n /**\n * Clear all collected metrics.\n */\n clear(): void {\n this.metrics = [];\n }\n}\n\n/**\n * Console-based metrics collector for debugging.\n */\nexport class ConsoleMetricsCollector implements MetricsCollector {\n collect(metrics: RequestMetrics): void {\n console.log('[METRICS]', JSON.stringify(metrics));\n }\n}\n","import { z } from 'zod';\nimport type { AuthProvider } from '../auth';\nimport { NoAuth } from '../auth';\nimport { Endpoint, EndpointConfig } from '../endpoint/base-endpoint';\nimport { LoggerUtil, NoOpLogger } from '../logger';\nimport { MetricsCollector, NoOpMetricsCollector } from '../metrics';\nimport {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n HTTPStatusCode,\n HTTPStatusCodeNumber,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\n\n/**\n * HTTP client with built-in retry logic, authentication, and interceptors.\n * Supports multiple base URLs, type-safe requests, and comprehensive error handling.\n *\n * @example\n * ```ts\n * const client = new HttpClient({\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'Content-Type': 'application/json' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * });\n *\n * const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });\n * ```\n */\nexport class HttpClient {\n private fetchImpl: FetchLike;\n private baseUrls: ClientOptions['baseUrls'];\n private headers: Record<string, string>;\n private interceptors: Interceptors;\n private retry: RetryStrategy;\n private timeoutMs?: number;\n private auth: AuthProvider;\n private logger: LoggerUtil;\n private metrics: MetricsCollector;\n\n /**\n * Creates a new HTTP client instance.\n *\n * @param opts - Client configuration options\n * @throws {Error} If no fetch implementation is available\n */\n constructor(opts: ClientOptions) {\n this.fetchImpl = opts.fetch ?? (globalThis.fetch?.bind(globalThis) as FetchLike);\n if (!this.fetchImpl)\n throw new Error('No fetch implementation found. Pass one via options.fetch.');\n\n // Validate baseUrls configuration\n if (!opts.baseUrls || typeof opts.baseUrls !== 'object') {\n throw new Error('baseUrls must be provided and must be an object');\n }\n if (!opts.baseUrls.default) {\n throw new Error('baseUrls must include a \"default\" key');\n }\n\n this.baseUrls = opts.baseUrls;\n this.headers = opts.headers ?? { 'Content-Type': 'application/json' };\n this.interceptors = opts.interceptors ?? {};\n this.retry = opts.retry ?? {\n maxRetries: 2,\n baseDelayMs: 250,\n jitter: 0.2,\n retryMethods: ['GET', 'HEAD'],\n };\n\n // Default retryStatusCodes if not provided\n if (!this.retry.retryStatusCodes) {\n this.retry.retryStatusCodes = (\n Object.keys(HTTPStatusCode) as (keyof typeof HTTPStatusCode)[]\n ).filter((key) => {\n const code = HTTPStatusCode[key];\n return typeof code === 'number' && code >= 500;\n });\n }\n\n // Validate retry configuration\n if (this.retry.maxRetries < 0) {\n throw new Error('retry.maxRetries must be non-negative');\n }\n if (this.retry.baseDelayMs < 0) {\n throw new Error('retry.baseDelayMs must be non-negative');\n }\n if (this.retry.jitter !== undefined && (this.retry.jitter < 0 || this.retry.jitter > 1)) {\n throw new Error('retry.jitter must be between 0 and 1');\n }\n\n this.timeoutMs = opts.timeout?.requestTimeoutMs;\n if (this.timeoutMs !== undefined && this.timeoutMs < 0) {\n throw new Error('timeout.requestTimeoutMs must be non-negative');\n }\n\n this.auth = opts['auth'] ?? new NoAuth();\n this.logger = new LoggerUtil(opts.logger ?? new NoOpLogger());\n this.metrics = opts.metrics ?? new NoOpMetricsCollector();\n }\n\n /**\n * Set or update the authentication provider.\n *\n * @param auth - Authentication provider instance\n * @example\n * ```ts\n * client.setAuth(new BearerTokenAuth(() => getToken()));\n * ```\n */\n setAuth(auth: AuthProvider) {\n this.auth = auth;\n }\n\n private resolveBaseUrl(key?: keyof typeof this.baseUrls) {\n const k: string = (key as string) || 'default';\n const url = this.baseUrls[k];\n if (!url) {\n const availableKeys = Object.keys(this.baseUrls).join(', ');\n throw new Error(`Unknown baseUrl key: \"${k}\". Available keys: ${availableKeys}`);\n }\n return url.replace(/\\/$/, '');\n }\n\n /**\n * Sleep for a specified duration (used for retry backoff).\n * @private\n */\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\n\n /**\n * Execute a function with retry logic and exponential backoff.\n * @private\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean\n ): Promise<T> {\n let attempt = 0;\n const { maxRetries, baseDelayMs, jitter = 0.2 } = this.retry;\n while (true) {\n try {\n return await fn();\n } catch (err: unknown) {\n if (attempt >= maxRetries || !canRetry({ attempt, error: err })) throw err;\n const backoff = baseDelayMs * 2 ** attempt;\n const j = 1 + (Math.random() * 2 - 1) * jitter;\n await this.sleep(backoff * j);\n attempt++;\n }\n }\n }\n\n /**\n * Run all registered before-request hooks.\n * @private\n */\n private async runBeforeHooks(url: string, init: RequestInit & { __urlOverride?: string }) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\n\n /**\n * Run all registered after-response hooks.\n * @private\n */\n private async runAfterHooks(req: Request, res: Response, parsed?: unknown) {\n for (const h of this.interceptors.afterResponse ?? []) {\n await h({ request: req, response: res, parsed });\n }\n }\n\n /**\n * Get all configured base URLs.\n *\n * @returns Object mapping base URL keys to their resolved URLs\n */\n public getBaseUrls() {\n return this.baseUrls;\n }\n\n /**\n * Get the resolved base URL for a given key.\n *\n * @param key - Base URL key (defaults to 'default' if not provided)\n * @returns Resolved base URL string\n */\n public getBaseUrl(key: string) {\n return this.resolveBaseUrl(key);\n }\n\n /**\n * Make an HTTP request with automatic retry, authentication, and validation.\n *\n * @param method - HTTP method (GET, POST, PUT, etc.)\n * @param path - Request path (will be appended to base URL)\n * @param body - Request body (will be JSON.stringify'd if Content-Type is json)\n * @param options - Additional request options (headers, query params, etc.)\n * @returns Promise resolving to response data and Response object\n * @throws {ApiError} If request fails or response validation fails\n *\n * @example\n * ```ts\n * const { data, response } = await client.request('GET', '/users', undefined, {\n * query: { page: 1, limit: 10 },\n * headers: { 'X-Custom': 'value' }\n * });\n * ```\n */\n async request<T = unknown>(\n method: keyof typeof HTTPMethod,\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n const startTime = Date.now();\n const base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\n\n this.logger.debug('HTTP request initiated', {\n method,\n path,\n baseUrlKey: options?.baseUrlKey,\n hasBody: body !== undefined,\n });\n\n const headers = { ...this.headers, ...(options?.headers ?? {}) };\n\n const controller = new AbortController();\n const signal = options?.signal ?? controller.signal;\n const init: RequestInit & { __urlOverride?: string } = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : String(body)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if (init.__urlOverride) url = init.__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: NodeJS.Timeout | number | undefined;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(() => {\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n controller.abort(timeoutError);\n }, this.timeoutMs);\n }\n\n try {\n const req = new Request(url, init);\n\n const res = await this.fetchImpl(req);\n const status = res.status as HTTPStatusCodeNumber;\n const contentType = res.headers.get('content-type') || '';\n const data = contentType.includes('json') ? await res.json() : await res.text();\n await this.runAfterHooks(new Request(url, init), res, data);\n\n const duration = Date.now() - startTime;\n this.logger.info('HTTP request successful', {\n method,\n url,\n status: res.status,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: res.status,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: true,\n });\n\n return { data: data as T, status: status };\n } catch (error) {\n const duration = Date.now() - startTime;\n this.logger.error('HTTP request failed', error as Error, {\n method,\n url,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: error instanceof ApiError ? error.status : undefined,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({ error }: { error?: unknown }) => {\n // Don't retry timeouts or aborts\n if (error && typeof error === 'object' && 'name' in error) {\n const errorName = (error as { name?: string }).name;\n if (errorName === 'AbortError' || errorName === 'TimeoutError') return false;\n }\n // Retry on network errors or configured status codes\n if (error instanceof ApiError && error.status) {\n const retryCodes = this.retry.retryStatusCodes;\n if (retryCodes?.some((codeKey) => HTTPStatusCode[codeKey] === error.status)) {\n return true;\n }\n }\n return false;\n };\n\n if (!this.retry.retryMethods?.includes(method)) {\n return doFetch();\n }\n\n return this.withRetry(doFetch, canRetry);\n }\n\n /**\n * Convenience method for GET requests.\n *\n * @example\n * ```ts\n * const { data } = await client.get('/users', { query: { page: 1 } });\n * ```\n */\n async get<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n /**\n * Convenience method for POST requests.\n *\n * @example\n * ```ts\n * const { data } = await client.post('/users', { name: 'John' });\n * ```\n */\n async post<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('POST', path, body, options);\n }\n\n /**\n * Convenience method for PUT requests.\n *\n * @example\n * ```ts\n * const { data } = await client.put('/users/1', { name: 'John Updated' });\n * ```\n */\n async put<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PUT', path, body, options);\n }\n\n /**\n * Convenience method for PATCH requests.\n *\n * @example\n * ```ts\n * const { data } = await client.patch('/users/1', { name: 'John' });\n * ```\n */\n async patch<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PATCH', path, body, options);\n }\n\n /**\n * Convenience method for DELETE requests.\n *\n * @example\n * ```ts\n * const { data } = await client.delete('/users/1');\n * ```\n */\n async delete<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n\n /**\n * Create a strongly-typed endpoint builder.\n *\n * @param config - Endpoint configuration\n * @returns Endpoint instance\n */\n createEndpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n >(\n config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ): Endpoint<ResSchema, ReqSchema, QuerySchema, PathSchema> {\n return new Endpoint(this, config);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Common ID type that supports strings, numbers, or UUIDs.\n * Use this for entity identifiers in your schemas.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ id: Id, name: z.string() });\n * ```\n */\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type IdType = z.infer<typeof Id>;\n\n/**\n * Common timestamp fields for entities.\n * Use this for database models with creation/update tracking.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({\n * id: Id,\n * name: z.string(),\n * ...Timestamps.shape\n * });\n * ```\n */\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\n/**\n * Metadata information typically included in API responses.\n * Contains request tracking and debugging information.\n */\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\n/**\n * Detailed error information for a specific field or path.\n */\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\n/**\n * Standard API error response schema.\n * Use this for consistent error handling across your API.\n */\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\n/**\n * Generic envelope wrapper for API responses.\n * Provides consistent structure with success flag, data, error, and metadata.\n *\n * @param inner - Zod schema for the response data\n * @returns Envelope schema wrapping the inner schema\n *\n * @example\n * ```ts\n * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));\n *\n * // Response structure:\n * // {\n * // success: true,\n * // data: { id: 1, name: 'John' },\n * // meta: { requestId: '...' }\n * // }\n * ```\n */\nexport const Envelope = <T extends z.ZodType>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional().nullable(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AACA,cAAc,QAAQ,CAAC;AACvB,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AAKxB,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AACA,cAAc,QAAQ,CAAC;AACvB,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AAGxB,cAAc,kBAAkB,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","message: string","options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }","status: number","q?: RequestOptions['query']","s","schema: z.ZodType","data: unknown","client: HttpClient","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>","pathStr: string","minLevel: LogLevel","entry: LogEntry","_entry: LogEntry","logger: Logger","message: string","context?: Record<string, unknown>","error?: Error","_metrics: RequestMetrics","metrics: RequestMetrics","opts: ClientOptions","auth: AuthProvider","key?: keyof typeof this.baseUrls","k: string","ms: number","fn: () => Promise<T>","canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean","err: unknown","url: string","init: RequestInit & { __urlOverride?: string }","req: Request","res: Response","parsed?: unknown","key: string","method: keyof typeof HTTPMethod","path: string","body?: unknown","options?: RequestOptions","timeoutId: NodeJS.Timeout | number | undefined","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","inner: T"],"sources":["../lib/auth.ts","../lib/types.ts","../lib/validation.ts","../lib/endpoint/base-endpoint.ts","../lib/logger.ts","../lib/metrics.ts","../lib/http/http-client.ts","../lib/schemas/common.ts"],"sourcesContent":["import type { RequestOptions as ReqOpts } from './types';\n\n/**\n * Extended RequestInit with URL override capability for query-based auth.\n */\nexport interface AuthContext {\n url: string;\n init: RequestInit & { __urlOverride?: string };\n options?: ReqOpts;\n}\n\n/**\n * Interface for authentication providers.\n * Implement this to create custom authentication strategies.\n *\n * @example\n * ```ts\n * class CustomAuth implements AuthProvider {\n * async apply({ init }) {\n * init.headers = { ...init.headers, 'X-Custom-Auth': 'token' };\n * }\n * }\n * ```\n */\nexport interface AuthProvider {\n /**\n * Apply authentication to the outgoing request.\n * Called after SDK headers are assembled, but before request is sent.\n *\n * @param req - Request context including URL, init, and options\n */\n apply(req: AuthContext): Promise<void> | void;\n}\n\n/**\n * No-op authentication provider (no authentication applied).\n * Use this when you don't need authentication.\n */\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\n/**\n * API Key authentication provider.\n * Supports both header-based and query parameter-based authentication.\n *\n * @example\n * ```ts\n * // Header-based\n * const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });\n *\n * // Query parameter-based\n * const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });\n * ```\n */\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {\n if (!opts.header && !opts.query) {\n throw new Error('ApiKeyAuth requires either \"header\" or \"query\" option');\n }\n if (opts.header && opts.query) {\n throw new Error('ApiKeyAuth cannot use both \"header\" and \"query\" options');\n }\n }\n apply({ url, init }: AuthContext) {\n const value = this.opts.value;\n if (this.opts.header) {\n if (init.headers instanceof Headers) {\n init.headers.set(this.opts.header, value);\n } else if (Array.isArray(init.headers)) {\n init.headers.push([this.opts.header, value]);\n } else {\n init.headers = { ...init.headers, [this.opts.header]: value };\n }\n } else if (this.opts.query) {\n const u = new URL(url);\n u.searchParams.set(this.opts.query, value);\n init.__urlOverride = u.toString();\n }\n }\n}\n/**\n * Bearer token authentication provider.\n * Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).\n *\n * @example\n * ```ts\n * // Static token\n * const auth = new BearerTokenAuth(() => 'my-token');\n *\n * // Dynamic token with refresh\n * const auth = new BearerTokenAuth(async () => {\n * return await refreshAccessToken();\n * });\n * ```\n */\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) { }\n async apply({ init }: AuthContext) {\n const token = await this.getToken();\n if (!token) {\n throw new Error('BearerTokenAuth: token is empty or undefined');\n }\n const authHeader = `Bearer ${token}`;\n if (init.headers instanceof Headers) {\n init.headers.set('Authorization', authHeader);\n } else if (Array.isArray(init.headers)) {\n init.headers.push(['Authorization', authHeader]);\n } else {\n init.headers = { ...init.headers, Authorization: authHeader };\n }\n }\n}\n","import { z, ZodError } from 'zod';\nimport { AuthProvider } from './auth';\nimport { Logger } from './logger';\nimport { MetricsCollector } from './metrics';\n\nexport type Dictionary<T> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Map of base URLs for different services.\n * The 'default' key is required and used when no specific key is provided.\n *\n * @example\n * ```ts\n * {\n * default: 'https://api.example.com',\n * auth: 'https://auth.example.com',\n * cdn: 'https://cdn.example.com'\n * }\n * ```\n */\nexport type BaseUrlMap = {\n default: string;\n} & Record<string, string>;\n\n/**\n * Configuration for retry behavior on failed requests.\n * Implements exponential backoff with optional jitter.\n *\n * @example\n * ```ts\n * {\n * maxRetries: 3,\n * baseDelayMs: 1000,\n * jitter: 0.2,\n * retryMethods: ['GET', 'HEAD', 'PUT']\n * }\n * ```\n */\nexport type RetryStrategy = {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds (will be exponentially increased) */\n baseDelayMs: number;\n /** Jitter factor 0..1 to randomize delays and prevent thundering herd */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** HTTP status codes eligible for retry */\n retryStatusCodes?: (keyof typeof HTTPStatusCode)[];\n /** Custom function to determine if a request should be retried */\n shouldRetry?: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean;\n};\n\nexport const HTTPMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n HEAD: 'HEAD',\n OPTIONS: 'OPTIONS',\n} as const;\n\nexport type HttpMethod = keyof typeof HTTPMethod;\n\nexport const HTTPStatusCode = {\n // 1xx — Informational\n CONTINUE: 100,\n SWITCHING_PROTOCOLS: 101,\n PROCESSING: 102,\n EARLY_HINTS: 103,\n\n // 2xx — Success\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NON_AUTHORITATIVE_INFORMATION: 203,\n NO_CONTENT: 204,\n RESET_CONTENT: 205,\n PARTIAL_CONTENT: 206,\n MULTI_STATUS: 207,\n ALREADY_REPORTED: 208,\n IM_USED: 226,\n\n // 3xx — Redirection\n MULTIPLE_CHOICES: 300,\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n SEE_OTHER: 303,\n NOT_MODIFIED: 304,\n USE_PROXY: 305,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n\n // 4xx — Client Errors\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n LENGTH_REQUIRED: 411,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n URI_TOO_LONG: 414,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n EXPECTATION_FAILED: 417,\n IM_A_TEAPOT: 418,\n MISDIRECTED_REQUEST: 421,\n UNPROCESSABLE_ENTITY: 422,\n LOCKED: 423,\n FAILED_DEPENDENCY: 424,\n TOO_EARLY: 425,\n UPGRADE_REQUIRED: 426,\n PRECONDITION_REQUIRED: 428,\n TOO_MANY_REQUESTS: 429,\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n\n // 5xx — Server Errors\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n VARIANT_ALSO_NEGOTIATES: 506,\n INSUFFICIENT_STORAGE: 507,\n LOOP_DETECTED: 508,\n NOT_EXTENDED: 510,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n} as const;\n\nexport type HTTPStatusCode = keyof typeof HTTPStatusCode;\nexport type HTTPStatusCodeNumber = typeof HTTPStatusCode[HTTPStatusCode];\n\n/**\n * Hook called after a response is received and parsed.\n * Useful for logging, metrics, or global error handling.\n */\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\n/**\n * Hook called before a request is sent.\n * Useful for logging, adding headers, or modifying the request.\n */\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n /** Hooks executed before each request is sent */\n beforeRequest?: BeforeRequestHook[];\n /** Hooks executed after each response is received */\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** Request timeout in milliseconds */\n requestTimeoutMs?: number;\n}\n\n/**\n * Configuration options for the HTTP client.\n *\n * @example\n * ```ts\n * const options: ClientOptions = {\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'X-API-Version': '1.0' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * }\n * ```\n */\nexport interface ClientOptions {\n /** Map of base URLs for different services */\n baseUrls: BaseUrlMap;\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: FetchLike;\n /** Default headers applied to all requests */\n headers?: Record<string, string>;\n /** Retry strategy configuration */\n retry?: RetryStrategy;\n /** Request/response interceptors */\n interceptors?: Interceptors;\n /** Timeout configuration */\n timeout?: TimeoutOptions;\n /** Authentication provider */\n auth?: AuthProvider;\n /** Logger instance */\n logger?: Logger;\n /** Metrics collector */\n metrics?: MetricsCollector;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\n\n/**\n * Custom error class for API-related errors.\n * Includes HTTP status codes, response details, and validation errors.\n *\n * @example\n * ```ts\n * throw new ApiError('Invalid request', {\n * status: 400,\n * details: { field: 'email', message: 'Invalid format' }\n * });\n * ```\n */\nexport class ApiError extends Error {\n public status?: number;\n public details?: unknown;\n public zodError?: ZodError;\n\n constructor(\n message: string,\n options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = options?.status;\n this.details = options?.details;\n this.cause = options?.cause;\n this.zodError = options?.zodError;\n\n // Maintains proper stack trace for where error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n\n /**\n * Check if this is a validation error (has zodError)\n */\n isValidationError(): boolean {\n return !!this.zodError;\n }\n\n /**\n * Check if this is a client error (4xx status)\n */\n isClientError(): boolean {\n return !!this.status && this.status >= 400 && this.status < 500;\n }\n\n /**\n * Check if this is a server error (5xx status)\n */\n isServerError(): boolean {\n return !!this.status && this.status >= 500;\n }\n\n /**\n * Get a formatted error message with all available details\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details,\n zodError: this.zodError?.issues,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Error thrown when an endpoint receives a response with a status code\n * that has no defined schema in the endpoint configuration.\n */\nexport class SchemaDefinitionError extends Error {\n constructor(public status: number) {\n super(`No schema defined for status code ${status}`);\n this.name = 'SchemaDefinitionError';\n\n // Maintains proper stack trace\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaDefinitionError);\n }\n }\n}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\n\n/**\n * Schema for paginated responses\n */\nexport const PaginationSchema = z.object({\n items: z.array(z.unknown()),\n total: z.number().int().nonnegative(),\n page: z.number().int().nonnegative(),\n pageSize: z.number().int().positive(),\n});\n\n/**\n * Options that can be passed to individual requests to override defaults.\n *\n * @example\n * ```ts\n * await endpoint.call(data, {\n * baseUrlKey: 'v2',\n * headers: { 'X-Custom': 'value' },\n * query: { filter: 'active' }\n * });\n * ```\n */\nexport type RequestOptions = {\n /** Override base URL for a single call */\n baseUrlKey?: keyof BaseUrlMap;\n /** Additional headers for this call only */\n headers?: Record<string, string>;\n /** Abort controller signal for cancellation */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n/**\n * Converts query parameters to a URL query string.\n * Filters out undefined values automatically.\n *\n * @param q - Query parameters as URLSearchParams or object\n * @returns Query string with leading '?' or empty string\n *\n * @example\n * ```ts\n * toQueryString({ page: 1, filter: 'active' }) // \"?page=1&filter=active\"\n * toQueryString({ optional: undefined }) // \"\"\n * ```\n */\nexport function toQueryString(q?: RequestOptions['query']): string {\n if (!q) return '';\n if (q instanceof URLSearchParams) {\n const s = q.toString();\n return s ? `?${s}` : '';\n }\n const params = new URLSearchParams();\n Object.entries(q).forEach(([k, v]) => {\n if (v !== undefined) {\n params.append(k, String(v));\n }\n });\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\n/**\n * Safely parse data with a Zod schema without throwing.\n * Returns a result object with success status and data or error.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Result object with success flag and data/error\n *\n * @example\n * ```ts\n * const result = safeParse(UserSchema, userData);\n * if (result.success) {\n * console.log(result.data);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport function safeParse<T>(schema: z.ZodType, data: unknown): SafeParseResult<T> {\n const res = schema.safeParse(data);\n if (res.success) return { success: true, data: res.data as T };\n return { success: false, error: res.error };\n}\n\n/**\n * Parse data with a Zod schema, throwing an ApiError on validation failure.\n * Use this when you want to fail fast on invalid data.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {ApiError} If validation fails\n *\n * @example\n * ```ts\n * try {\n * const user = parseOrThrow(UserSchema, userData);\n * console.log(user);\n * } catch (error) {\n * if (error instanceof ApiError && error.zodError) {\n * console.error('Validation failed:', error.zodError.issues);\n * }\n * }\n * ```\n */\nexport function parseOrThrow<T>(schema: z.ZodType, data: unknown): T {\n const res = schema.safeParse(data);\n if (!res.success) {\n throw new ApiError('Response validation failed', { zodError: res.error });\n }\n return res.data as T;\n}\n","import { z } from 'zod';\nimport { HttpClient } from '../http/http-client';\nimport { HTTPMethod, SchemaDefinitionError } from '../types';\nimport { parseOrThrow } from '../validation';\n\nexport type EndpointConfig<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n> = {\n method: keyof typeof HTTPMethod;\n path: string | ((params: z.infer<Exclude<PathSchema, undefined>>) => string);\n response: ResSchema;\n request?: ReqSchema;\n query?: QuerySchema;\n pathParams?: PathSchema;\n baseUrlKey?: string;\n description?: string;\n};\n\nexport type EndpointCallParams<\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> = {\n data?: ReqSchema extends z.ZodType ? z.infer<ReqSchema> : never;\n query?: QuerySchema extends z.ZodType ? z.infer<QuerySchema> : never;\n pathParams?: PathSchema extends z.ZodType ? z.infer<PathSchema> : never;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n};\n\n// Helper to extract the response type from a schema which might be a single ZodType or a status map\ntype InferResponse<S> = S extends z.ZodType\n ? z.infer<S>\n : S extends Record<number, z.ZodType>\n ? z.infer<S[keyof S]>\n : never;\n\nexport class Endpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> {\n constructor(\n private client: HttpClient,\n private config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ) { }\n\n async call(\n params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>\n ): Promise<InferResponse<ResSchema>> {\n const { data, query, pathParams, headers, signal } = params;\n\n // Validate Request Body\n if (this.config.request && data !== undefined) {\n const parsed = this.config.request.safeParse(data);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Query Params\n if (this.config.query && query !== undefined) {\n const parsed = this.config.query.safeParse(query);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Path Params\n if (this.config.pathParams && pathParams !== undefined) {\n const parsed = this.config.pathParams.safeParse(pathParams);\n if (!parsed.success) throw parsed.error;\n }\n\n // Check for missing required params\n if (this.config.request && data === undefined) {\n throw new Error('Missing required request body (data)');\n }\n if (this.config.pathParams && pathParams === undefined) {\n throw new Error('Missing required path parameters (pathParams)');\n }\n\n // Resolve Path\n let pathStr: string;\n if (typeof this.config.path === 'function') {\n if (!pathParams) throw new Error('Path function requires pathParams');\n pathStr = this.config.path(pathParams as any);\n } else {\n pathStr = this.config.path;\n }\n\n const { data: responseData, status } = await this.client.request(\n this.config.method,\n pathStr,\n data,\n {\n query: query as any,\n headers,\n baseUrlKey: this.config.baseUrlKey,\n signal,\n }\n );\n\n // Handle Response Validation\n const schema = this.config.response;\n if (schema instanceof z.ZodType) {\n // Single schema for all success codes\n return parseOrThrow(schema, responseData) as InferResponse<ResSchema>;\n }\n\n // Map of status codes\n const specificSchema = (schema as Record<number, z.ZodType>)[status];\n if (!specificSchema) {\n // Fallback or error? For now, rigorous error.\n throw new SchemaDefinitionError(status);\n }\n\n return parseOrThrow(specificSchema, responseData) as InferResponse<ResSchema>;\n }\n}\n","/**\n * Log levels for structured logging.\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Structured log entry with metadata.\n */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/**\n * Logger interface for custom logger implementations.\n * Implement this to integrate with your logging infrastructure.\n *\n * @example\n * ```ts\n * class ConsoleLogger implements Logger {\n * log(entry: LogEntry) {\n * console.log(JSON.stringify(entry));\n * }\n * }\n * ```\n */\nexport interface Logger {\n log(entry: LogEntry): void;\n}\n\n/**\n * Default console logger implementation.\n * Formats log entries as JSON for easy parsing.\n */\nexport class ConsoleLogger implements Logger {\n constructor(private minLevel: LogLevel = LogLevel.INFO) {}\n\n log(entry: LogEntry): void {\n const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];\n const entryLevelIndex = levels.indexOf(entry.level);\n const minLevelIndex = levels.indexOf(this.minLevel);\n\n if (entryLevelIndex < minLevelIndex) return;\n\n const output = {\n ...entry,\n error: entry.error\n ? {\n message: entry.error.message,\n stack: entry.error.stack,\n name: entry.error.name,\n }\n : undefined,\n };\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(JSON.stringify(output));\n break;\n case LogLevel.INFO:\n console.info(JSON.stringify(output));\n break;\n case LogLevel.WARN:\n console.warn(JSON.stringify(output));\n break;\n case LogLevel.ERROR:\n console.error(JSON.stringify(output));\n break;\n }\n }\n}\n\n/**\n * No-op logger that discards all log entries.\n * Use this in production if you don't want any logging.\n */\nexport class NoOpLogger implements Logger {\n log(_entry: LogEntry): void {\n // no-op\n }\n}\n\n/**\n * Utility class for creating structured log entries.\n */\nexport class LoggerUtil {\n constructor(private logger: Logger) {}\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.DEBUG,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.INFO,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.WARN,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n error(message: string, error?: Error, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.ERROR,\n message,\n timestamp: new Date().toISOString(),\n context,\n error,\n });\n }\n}\n","/**\n * Metrics data for HTTP requests.\n */\nexport interface RequestMetrics {\n method: string;\n path: string;\n status?: number;\n durationMs: number;\n timestamp: string;\n success: boolean;\n error?: string;\n}\n\n/**\n * Interface for metrics collectors.\n * Implement this to integrate with your monitoring infrastructure (DataDog, Prometheus, etc.).\n *\n * @example\n * ```ts\n * class DataDogMetrics implements MetricsCollector {\n * collect(metrics: RequestMetrics) {\n * dogstatsd.histogram('http.request.duration', metrics.durationMs, {\n * method: metrics.method,\n * status: String(metrics.status)\n * });\n * }\n * }\n * ```\n */\nexport interface MetricsCollector {\n collect(metrics: RequestMetrics): void;\n}\n\n/**\n * No-op metrics collector that discards all metrics.\n */\nexport class NoOpMetricsCollector implements MetricsCollector {\n collect(_metrics: RequestMetrics): void {\n // no-op\n }\n}\n\n/**\n * In-memory metrics collector for testing and development.\n * Stores metrics in memory with configurable retention.\n */\nexport class InMemoryMetricsCollector implements MetricsCollector {\n private metrics: RequestMetrics[] = [];\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n collect(metrics: RequestMetrics): void {\n this.metrics.push(metrics);\n if (this.metrics.length > this.maxEntries) {\n this.metrics.shift();\n }\n }\n\n /**\n * Get all collected metrics.\n */\n getMetrics(): RequestMetrics[] {\n return [...this.metrics];\n }\n\n /**\n * Get metrics summary statistics.\n */\n getSummary(): {\n total: number;\n successful: number;\n failed: number;\n avgDurationMs: number;\n minDurationMs: number;\n maxDurationMs: number;\n } {\n if (this.metrics.length === 0) {\n return {\n total: 0,\n successful: 0,\n failed: 0,\n avgDurationMs: 0,\n minDurationMs: 0,\n maxDurationMs: 0,\n };\n }\n\n const successful = this.metrics.filter((m) => m.success).length;\n\n // Calculate stats in a single pass to avoid stack overflow with spread operator\n let sum = 0;\n let min = Infinity;\n let max = -Infinity;\n\n for (const m of this.metrics) {\n const d = m.durationMs;\n sum += d;\n if (d < min) min = d;\n if (d > max) max = d;\n }\n\n return {\n total: this.metrics.length,\n successful,\n failed: this.metrics.length - successful,\n avgDurationMs: sum / this.metrics.length,\n minDurationMs: min === Infinity ? 0 : min,\n maxDurationMs: max === -Infinity ? 0 : max,\n };\n }\n\n /**\n * Clear all collected metrics.\n */\n clear(): void {\n this.metrics = [];\n }\n}\n\n/**\n * Console-based metrics collector for debugging.\n */\nexport class ConsoleMetricsCollector implements MetricsCollector {\n collect(metrics: RequestMetrics): void {\n console.log('[METRICS]', JSON.stringify(metrics));\n }\n}\n","import { z } from 'zod';\nimport type { AuthProvider } from '../auth';\nimport { NoAuth } from '../auth';\nimport { Endpoint, EndpointConfig } from '../endpoint/base-endpoint';\nimport { LoggerUtil, NoOpLogger } from '../logger';\nimport { MetricsCollector, NoOpMetricsCollector } from '../metrics';\nimport {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n HTTPStatusCode,\n HTTPStatusCodeNumber,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\n\n/**\n * HTTP client with built-in retry logic, authentication, and interceptors.\n * Supports multiple base URLs, type-safe requests, and comprehensive error handling.\n *\n * @example\n * ```ts\n * const client = new HttpClient({\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'Content-Type': 'application/json' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * });\n *\n * const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });\n * ```\n */\nexport class HttpClient {\n private fetchImpl: FetchLike;\n private baseUrls: ClientOptions['baseUrls'];\n private headers: Record<string, string>;\n private interceptors: Interceptors;\n private retry: RetryStrategy;\n private timeoutMs?: number;\n private auth: AuthProvider;\n private logger: LoggerUtil;\n private metrics: MetricsCollector;\n\n /**\n * Creates a new HTTP client instance.\n *\n * @param opts - Client configuration options\n * @throws {Error} If no fetch implementation is available\n */\n constructor(opts: ClientOptions) {\n this.fetchImpl = opts.fetch ?? (globalThis.fetch?.bind(globalThis) as FetchLike);\n if (!this.fetchImpl)\n throw new Error('No fetch implementation found. Pass one via options.fetch.');\n\n // Validate baseUrls configuration\n if (!opts.baseUrls || typeof opts.baseUrls !== 'object') {\n throw new Error('baseUrls must be provided and must be an object');\n }\n if (!opts.baseUrls.default) {\n throw new Error('baseUrls must include a \"default\" key');\n }\n\n this.baseUrls = opts.baseUrls;\n this.headers = opts.headers ?? { 'Content-Type': 'application/json' };\n this.interceptors = opts.interceptors ?? {};\n this.retry = opts.retry ?? {\n maxRetries: 2,\n baseDelayMs: 250,\n jitter: 0.2,\n retryMethods: ['GET', 'HEAD'],\n };\n\n // Default retryStatusCodes if not provided\n if (!this.retry.retryStatusCodes) {\n this.retry.retryStatusCodes = (Object.keys(HTTPStatusCode) as (keyof typeof HTTPStatusCode)[])\n .filter(key => {\n const code = HTTPStatusCode[key];\n return typeof code === 'number' && code >= 500;\n });\n }\n\n // Validate retry configuration\n if (this.retry.maxRetries < 0) {\n throw new Error('retry.maxRetries must be non-negative');\n }\n if (this.retry.baseDelayMs < 0) {\n throw new Error('retry.baseDelayMs must be non-negative');\n }\n if (this.retry.jitter !== undefined && (this.retry.jitter < 0 || this.retry.jitter > 1)) {\n throw new Error('retry.jitter must be between 0 and 1');\n }\n\n this.timeoutMs = opts.timeout?.requestTimeoutMs;\n if (this.timeoutMs !== undefined && this.timeoutMs < 0) {\n throw new Error('timeout.requestTimeoutMs must be non-negative');\n }\n\n this.auth = opts['auth'] ?? new NoAuth();\n this.logger = new LoggerUtil(opts.logger ?? new NoOpLogger());\n this.metrics = opts.metrics ?? new NoOpMetricsCollector();\n }\n\n /**\n * Set or update the authentication provider.\n *\n * @param auth - Authentication provider instance\n * @example\n * ```ts\n * client.setAuth(new BearerTokenAuth(() => getToken()));\n * ```\n */\n setAuth(auth: AuthProvider) {\n this.auth = auth;\n }\n\n private resolveBaseUrl(key?: keyof typeof this.baseUrls) {\n const k: string = (key as string) || 'default';\n const url = this.baseUrls[k];\n if (!url) {\n const availableKeys = Object.keys(this.baseUrls).join(', ');\n throw new Error(`Unknown baseUrl key: \"${k}\". Available keys: ${availableKeys}`);\n }\n return url.replace(/\\/$/, '');\n }\n\n /**\n * Sleep for a specified duration (used for retry backoff).\n * @private\n */\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\n\n /**\n * Execute a function with retry logic and exponential backoff.\n * @private\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean\n ): Promise<T> {\n let attempt = 0;\n const { maxRetries, baseDelayMs, jitter = 0.2 } = this.retry;\n while (true) {\n try {\n return await fn();\n } catch (err: unknown) {\n if (attempt >= maxRetries || !canRetry({ attempt, error: err })) throw err;\n const backoff = baseDelayMs * 2 ** attempt;\n const j = 1 + (Math.random() * 2 - 1) * jitter;\n await this.sleep(backoff * j);\n attempt++;\n }\n }\n }\n\n /**\n * Run all registered before-request hooks.\n * @private\n */\n private async runBeforeHooks(url: string, init: RequestInit & { __urlOverride?: string }) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\n\n /**\n * Run all registered after-response hooks.\n * @private\n */\n private async runAfterHooks(req: Request, res: Response, parsed?: unknown) {\n for (const h of this.interceptors.afterResponse ?? []) {\n await h({ request: req, response: res, parsed });\n }\n }\n\n /**\n * Get all configured base URLs.\n *\n * @returns Object mapping base URL keys to their resolved URLs\n */\n public getBaseUrls() {\n return this.baseUrls;\n }\n\n /**\n * Get the resolved base URL for a given key.\n *\n * @param key - Base URL key (defaults to 'default' if not provided)\n * @returns Resolved base URL string\n */\n public getBaseUrl(key: string) {\n return this.resolveBaseUrl(key);\n }\n\n /**\n * Make an HTTP request with automatic retry, authentication, and validation.\n *\n * @param method - HTTP method (GET, POST, PUT, etc.)\n * @param path - Request path (will be appended to base URL)\n * @param body - Request body (will be JSON.stringify'd if Content-Type is json)\n * @param options - Additional request options (headers, query params, etc.)\n * @returns Promise resolving to response data and Response object\n * @throws {ApiError} If request fails or response validation fails\n *\n * @example\n * ```ts\n * const { data, response } = await client.request('GET', '/users', undefined, {\n * query: { page: 1, limit: 10 },\n * headers: { 'X-Custom': 'value' }\n * });\n * ```\n */\n async request<T = unknown>(\n method: keyof typeof HTTPMethod,\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n const startTime = Date.now();\n const base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\n\n this.logger.debug('HTTP request initiated', {\n method,\n path,\n baseUrlKey: options?.baseUrlKey,\n hasBody: body !== undefined,\n });\n\n const headers = { ...this.headers, ...(options?.headers ?? {}) };\n\n const controller = new AbortController();\n const signal = options?.signal ?? controller.signal;\n const init: RequestInit & { __urlOverride?: string } = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : String(body)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if (init.__urlOverride) url = init.__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: NodeJS.Timeout | number | undefined;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(() => {\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n controller.abort(timeoutError);\n }, this.timeoutMs);\n }\n\n try {\n const req = new Request(url, init);\n\n const res = await this.fetchImpl(req);\n const status = res.status as HTTPStatusCodeNumber;\n const contentType = res.headers.get('content-type') || '';\n const data = contentType.includes('json') ? await res.json() : await res.text();\n await this.runAfterHooks(new Request(url, init), res, data);\n\n const duration = Date.now() - startTime;\n this.logger.info('HTTP request successful', {\n method,\n url,\n status: res.status,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: res.status,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: true,\n });\n\n return { data: data as T, status: status };\n } catch (error) {\n const duration = Date.now() - startTime;\n this.logger.error('HTTP request failed', error as Error, {\n method,\n url,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: error instanceof ApiError ? error.status : undefined,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({\n error,\n }: {\n error?: unknown;\n }) => {\n // Don't retry timeouts or aborts\n if (error && typeof error === 'object' && 'name' in error) {\n const errorName = (error as { name?: string }).name;\n if (errorName === 'AbortError' || errorName === 'TimeoutError') return false;\n }\n // Retry on network errors or configured status codes\n if (error instanceof ApiError && error.status) {\n const retryCodes = this.retry.retryStatusCodes;\n if (retryCodes?.some(codeKey => HTTPStatusCode[codeKey] === error.status)) {\n return true;\n }\n }\n return false;\n };\n\n if (!this.retry.retryMethods?.includes(method)) {\n return doFetch();\n }\n\n return this.withRetry(doFetch, canRetry);\n }\n\n /**\n * Convenience method for GET requests.\n *\n * @example\n * ```ts\n * const { data } = await client.get('/users', { query: { page: 1 } });\n * ```\n */\n async get<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n /**\n * Convenience method for POST requests.\n *\n * @example\n * ```ts\n * const { data } = await client.post('/users', { name: 'John' });\n * ```\n */\n async post<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('POST', path, body, options);\n }\n\n /**\n * Convenience method for PUT requests.\n *\n * @example\n * ```ts\n * const { data } = await client.put('/users/1', { name: 'John Updated' });\n * ```\n */\n async put<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PUT', path, body, options);\n }\n\n /**\n * Convenience method for PATCH requests.\n *\n * @example\n * ```ts\n * const { data } = await client.patch('/users/1', { name: 'John' });\n * ```\n */\n async patch<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PATCH', path, body, options);\n }\n\n /**\n * Convenience method for DELETE requests.\n *\n * @example\n * ```ts\n * const { data } = await client.delete('/users/1');\n * ```\n */\n async delete<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n\n /**\n * Create a strongly-typed endpoint builder.\n *\n * @param config - Endpoint configuration\n * @returns Endpoint instance\n */\n createEndpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n >(\n config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ): Endpoint<ResSchema, ReqSchema, QuerySchema, PathSchema> {\n return new Endpoint(this, config);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Common ID type that supports strings, numbers, or UUIDs.\n * Use this for entity identifiers in your schemas.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ id: Id, name: z.string() });\n * ```\n */\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type IdType = z.infer<typeof Id>;\n\n/**\n * Common timestamp fields for entities.\n * Use this for database models with creation/update tracking.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({\n * id: Id,\n * name: z.string(),\n * ...Timestamps.shape\n * });\n * ```\n */\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\n/**\n * Metadata information typically included in API responses.\n * Contains request tracking and debugging information.\n */\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\n/**\n * Detailed error information for a specific field or path.\n */\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\n/**\n * Standard API error response schema.\n * Use this for consistent error handling across your API.\n */\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\n/**\n * Generic envelope wrapper for API responses.\n * Provides consistent structure with success flag, data, error, and metadata.\n *\n * @param inner - Zod schema for the response data\n * @returns Envelope schema wrapping the inner schema\n *\n * @example\n * ```ts\n * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));\n *\n * // Response structure:\n * // {\n * // success: true,\n * // data: { id: 1, name: 'John' },\n * // meta: { requestId: '...' }\n * // }\n * ```\n */\nexport const Envelope = <T extends z.ZodType>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional().nullable(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["opts: { header?: string; query?: string; value: string }","getToken: () => Promise<string> | string","message: string","options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }","status: number","q?: RequestOptions['query']","s","schema: z.ZodType","data: unknown","client: HttpClient","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>","pathStr: string","minLevel: LogLevel","entry: LogEntry","_entry: LogEntry","logger: Logger","message: string","context?: Record<string, unknown>","error?: Error","_metrics: RequestMetrics","metrics: RequestMetrics","opts: ClientOptions","auth: AuthProvider","key?: keyof typeof this.baseUrls","k: string","ms: number","fn: () => Promise<T>","canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean","err: unknown","url: string","init: RequestInit & { __urlOverride?: string }","req: Request","res: Response","parsed?: unknown","key: string","method: keyof typeof HTTPMethod","path: string","body?: unknown","options?: RequestOptions","timeoutId: NodeJS.Timeout | number | undefined","config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>","inner: T"],"sources":["../lib/auth.ts","../lib/types.ts","../lib/validation.ts","../lib/endpoint/base-endpoint.ts","../lib/logger.ts","../lib/metrics.ts","../lib/http/http-client.ts","../lib/schemas/common.ts"],"sourcesContent":["import type { RequestOptions as ReqOpts } from './types';\n\n/**\n * Extended RequestInit with URL override capability for query-based auth.\n */\nexport interface AuthContext {\n url: string;\n init: RequestInit & { __urlOverride?: string };\n options?: ReqOpts;\n}\n\n/**\n * Interface for authentication providers.\n * Implement this to create custom authentication strategies.\n *\n * @example\n * ```ts\n * class CustomAuth implements AuthProvider {\n * async apply({ init }) {\n * init.headers = { ...init.headers, 'X-Custom-Auth': 'token' };\n * }\n * }\n * ```\n */\nexport interface AuthProvider {\n /**\n * Apply authentication to the outgoing request.\n * Called after SDK headers are assembled, but before request is sent.\n *\n * @param req - Request context including URL, init, and options\n */\n apply(req: AuthContext): Promise<void> | void;\n}\n\n/**\n * No-op authentication provider (no authentication applied).\n * Use this when you don't need authentication.\n */\nexport class NoAuth implements AuthProvider {\n async apply() {\n /* no-op */\n }\n}\n\n/**\n * API Key authentication provider.\n * Supports both header-based and query parameter-based authentication.\n *\n * @example\n * ```ts\n * // Header-based\n * const auth = new ApiKeyAuth({ header: 'X-API-Key', value: 'secret' });\n *\n * // Query parameter-based\n * const auth = new ApiKeyAuth({ query: 'apiKey', value: 'secret' });\n * ```\n */\nexport class ApiKeyAuth implements AuthProvider {\n constructor(private opts: { header?: string; query?: string; value: string }) {\n if (!opts.header && !opts.query) {\n throw new Error('ApiKeyAuth requires either \"header\" or \"query\" option');\n }\n if (opts.header && opts.query) {\n throw new Error('ApiKeyAuth cannot use both \"header\" and \"query\" options');\n }\n }\n apply({ url, init }: AuthContext) {\n const value = this.opts.value;\n if (this.opts.header) {\n if (init.headers instanceof Headers) {\n init.headers.set(this.opts.header, value);\n } else if (Array.isArray(init.headers)) {\n init.headers.push([this.opts.header, value]);\n } else {\n init.headers = { ...init.headers, [this.opts.header]: value };\n }\n } else if (this.opts.query) {\n const u = new URL(url);\n u.searchParams.set(this.opts.query, value);\n init.__urlOverride = u.toString();\n }\n }\n}\n/**\n * Bearer token authentication provider.\n * Supports both static tokens and dynamic token fetching (e.g., for OAuth2 refresh).\n *\n * @example\n * ```ts\n * // Static token\n * const auth = new BearerTokenAuth(() => 'my-token');\n *\n * // Dynamic token with refresh\n * const auth = new BearerTokenAuth(async () => {\n * return await refreshAccessToken();\n * });\n * ```\n */\nexport class BearerTokenAuth implements AuthProvider {\n constructor(private getToken: () => Promise<string> | string) {}\n async apply({ init }: AuthContext) {\n const token = await this.getToken();\n if (!token) {\n throw new Error('BearerTokenAuth: token is empty or undefined');\n }\n const authHeader = `Bearer ${token}`;\n if (init.headers instanceof Headers) {\n init.headers.set('Authorization', authHeader);\n } else if (Array.isArray(init.headers)) {\n init.headers.push(['Authorization', authHeader]);\n } else {\n init.headers = { ...init.headers, Authorization: authHeader };\n }\n }\n}\n","import { z, ZodError } from 'zod';\nimport { AuthProvider } from './auth';\nimport { Logger } from './logger';\nimport { MetricsCollector } from './metrics';\n\nexport type Dictionary<T> = Record<string, T>;\n\nexport type FetchLike = (input: string | Request | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Map of base URLs for different services.\n * The 'default' key is required and used when no specific key is provided.\n *\n * @example\n * ```ts\n * {\n * default: 'https://api.example.com',\n * auth: 'https://auth.example.com',\n * cdn: 'https://cdn.example.com'\n * }\n * ```\n */\nexport type BaseUrlMap = {\n default: string;\n} & Record<string, string>;\n\n/**\n * Configuration for retry behavior on failed requests.\n * Implements exponential backoff with optional jitter.\n *\n * @example\n * ```ts\n * {\n * maxRetries: 3,\n * baseDelayMs: 1000,\n * jitter: 0.2,\n * retryMethods: ['GET', 'HEAD', 'PUT']\n * }\n * ```\n */\nexport type RetryStrategy = {\n /** Maximum number of retry attempts */\n maxRetries: number;\n /** Base delay in milliseconds (will be exponentially increased) */\n baseDelayMs: number;\n /** Jitter factor 0..1 to randomize delays and prevent thundering herd */\n jitter?: number;\n /** HTTP methods eligible for retry */\n retryMethods?: (keyof typeof HTTPMethod)[];\n /** HTTP status codes eligible for retry */\n retryStatusCodes?: (keyof typeof HTTPStatusCode)[];\n /** Custom function to determine if a request should be retried */\n shouldRetry?: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean;\n};\n\nexport const HTTPMethod = {\n GET: 'GET',\n POST: 'POST',\n PUT: 'PUT',\n PATCH: 'PATCH',\n DELETE: 'DELETE',\n HEAD: 'HEAD',\n OPTIONS: 'OPTIONS',\n} as const;\n\nexport type HttpMethod = keyof typeof HTTPMethod;\n\nexport const HTTPStatusCode = {\n // 1xx — Informational\n CONTINUE: 100,\n SWITCHING_PROTOCOLS: 101,\n PROCESSING: 102,\n EARLY_HINTS: 103,\n\n // 2xx — Success\n OK: 200,\n CREATED: 201,\n ACCEPTED: 202,\n NON_AUTHORITATIVE_INFORMATION: 203,\n NO_CONTENT: 204,\n RESET_CONTENT: 205,\n PARTIAL_CONTENT: 206,\n MULTI_STATUS: 207,\n ALREADY_REPORTED: 208,\n IM_USED: 226,\n\n // 3xx — Redirection\n MULTIPLE_CHOICES: 300,\n MOVED_PERMANENTLY: 301,\n FOUND: 302,\n SEE_OTHER: 303,\n NOT_MODIFIED: 304,\n USE_PROXY: 305,\n TEMPORARY_REDIRECT: 307,\n PERMANENT_REDIRECT: 308,\n\n // 4xx — Client Errors\n BAD_REQUEST: 400,\n UNAUTHORIZED: 401,\n PAYMENT_REQUIRED: 402,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n METHOD_NOT_ALLOWED: 405,\n NOT_ACCEPTABLE: 406,\n PROXY_AUTHENTICATION_REQUIRED: 407,\n REQUEST_TIMEOUT: 408,\n CONFLICT: 409,\n GONE: 410,\n LENGTH_REQUIRED: 411,\n PRECONDITION_FAILED: 412,\n PAYLOAD_TOO_LARGE: 413,\n URI_TOO_LONG: 414,\n UNSUPPORTED_MEDIA_TYPE: 415,\n RANGE_NOT_SATISFIABLE: 416,\n EXPECTATION_FAILED: 417,\n IM_A_TEAPOT: 418,\n MISDIRECTED_REQUEST: 421,\n UNPROCESSABLE_ENTITY: 422,\n LOCKED: 423,\n FAILED_DEPENDENCY: 424,\n TOO_EARLY: 425,\n UPGRADE_REQUIRED: 426,\n PRECONDITION_REQUIRED: 428,\n TOO_MANY_REQUESTS: 429,\n REQUEST_HEADER_FIELDS_TOO_LARGE: 431,\n UNAVAILABLE_FOR_LEGAL_REASONS: 451,\n\n // 5xx — Server Errors\n INTERNAL_SERVER_ERROR: 500,\n NOT_IMPLEMENTED: 501,\n BAD_GATEWAY: 502,\n SERVICE_UNAVAILABLE: 503,\n GATEWAY_TIMEOUT: 504,\n HTTP_VERSION_NOT_SUPPORTED: 505,\n VARIANT_ALSO_NEGOTIATES: 506,\n INSUFFICIENT_STORAGE: 507,\n LOOP_DETECTED: 508,\n NOT_EXTENDED: 510,\n NETWORK_AUTHENTICATION_REQUIRED: 511,\n} as const;\n\nexport type HTTPStatusCode = keyof typeof HTTPStatusCode;\nexport type HTTPStatusCodeNumber = (typeof HTTPStatusCode)[HTTPStatusCode];\n\n/**\n * Hook called after a response is received and parsed.\n * Useful for logging, metrics, or global error handling.\n */\nexport type AfterResponseHook = (ctx: {\n request: Request;\n response: Response;\n parsed?: unknown;\n}) => Promise<void> | void;\n\n/**\n * Hook called before a request is sent.\n * Useful for logging, adding headers, or modifying the request.\n */\nexport type BeforeRequestHook = (ctx: { url: string; init: RequestInit }) => Promise<void> | void;\n\nexport interface Interceptors {\n /** Hooks executed before each request is sent */\n beforeRequest?: BeforeRequestHook[];\n /** Hooks executed after each response is received */\n afterResponse?: AfterResponseHook[];\n}\n\nexport interface TimeoutOptions {\n /** Request timeout in milliseconds */\n requestTimeoutMs?: number;\n}\n\n/**\n * Configuration options for the HTTP client.\n *\n * @example\n * ```ts\n * const options: ClientOptions = {\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'X-API-Version': '1.0' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * }\n * ```\n */\nexport interface ClientOptions {\n /** Map of base URLs for different services */\n baseUrls: BaseUrlMap;\n /** Custom fetch implementation (defaults to globalThis.fetch) */\n fetch?: FetchLike;\n /** Default headers applied to all requests */\n headers?: Record<string, string>;\n /** Retry strategy configuration */\n retry?: RetryStrategy;\n /** Request/response interceptors */\n interceptors?: Interceptors;\n /** Timeout configuration */\n timeout?: TimeoutOptions;\n /** Authentication provider */\n auth?: AuthProvider;\n /** Logger instance */\n logger?: Logger;\n /** Metrics collector */\n metrics?: MetricsCollector;\n}\n\nexport type SafeParseResult<T> = { success: true; data: T } | { success: false; error: ZodError };\n\n/**\n * Custom error class for API-related errors.\n * Includes HTTP status codes, response details, and validation errors.\n *\n * @example\n * ```ts\n * throw new ApiError('Invalid request', {\n * status: 400,\n * details: { field: 'email', message: 'Invalid format' }\n * });\n * ```\n */\nexport class ApiError extends Error {\n public status?: number;\n public details?: unknown;\n public zodError?: ZodError;\n\n constructor(\n message: string,\n options?: { status?: number; cause?: unknown; details?: unknown; zodError?: ZodError }\n ) {\n super(message);\n this.name = 'ApiError';\n this.status = options?.status;\n this.details = options?.details;\n this.cause = options?.cause;\n this.zodError = options?.zodError;\n\n // Maintains proper stack trace for where error was thrown\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ApiError);\n }\n }\n\n /**\n * Check if this is a validation error (has zodError)\n */\n isValidationError(): boolean {\n return !!this.zodError;\n }\n\n /**\n * Check if this is a client error (4xx status)\n */\n isClientError(): boolean {\n return !!this.status && this.status >= 400 && this.status < 500;\n }\n\n /**\n * Check if this is a server error (5xx status)\n */\n isServerError(): boolean {\n return !!this.status && this.status >= 500;\n }\n\n /**\n * Get a formatted error message with all available details\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n status: this.status,\n details: this.details,\n zodError: this.zodError?.issues,\n stack: this.stack,\n };\n }\n}\n\n/**\n * Error thrown when an endpoint receives a response with a status code\n * that has no defined schema in the endpoint configuration.\n */\nexport class SchemaDefinitionError extends Error {\n constructor(public status: number) {\n super(`No schema defined for status code ${status}`);\n this.name = 'SchemaDefinitionError';\n\n // Maintains proper stack trace\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaDefinitionError);\n }\n }\n}\n\nexport type Paginated<T> = {\n items: T[];\n total: number;\n page: number;\n pageSize: number;\n};\n\n/**\n * Schema for paginated responses\n */\nexport const PaginationSchema = z.object({\n items: z.array(z.unknown()),\n total: z.number().int().nonnegative(),\n page: z.number().int().nonnegative(),\n pageSize: z.number().int().positive(),\n});\n\n/**\n * Options that can be passed to individual requests to override defaults.\n *\n * @example\n * ```ts\n * await endpoint.call(data, {\n * baseUrlKey: 'v2',\n * headers: { 'X-Custom': 'value' },\n * query: { filter: 'active' }\n * });\n * ```\n */\nexport type RequestOptions = {\n /** Override base URL for a single call */\n baseUrlKey?: keyof BaseUrlMap;\n /** Additional headers for this call only */\n headers?: Record<string, string>;\n /** Abort controller signal for cancellation */\n signal?: AbortSignal;\n /** Custom query params */\n query?: URLSearchParams | Record<string, string | number | boolean | undefined>;\n};\n\n/**\n * Converts query parameters to a URL query string.\n * Filters out undefined values automatically.\n *\n * @param q - Query parameters as URLSearchParams or object\n * @returns Query string with leading '?' or empty string\n *\n * @example\n * ```ts\n * toQueryString({ page: 1, filter: 'active' }) // \"?page=1&filter=active\"\n * toQueryString({ optional: undefined }) // \"\"\n * ```\n */\nexport function toQueryString(q?: RequestOptions['query']): string {\n if (!q) return '';\n if (q instanceof URLSearchParams) {\n const s = q.toString();\n return s ? `?${s}` : '';\n }\n const params = new URLSearchParams();\n Object.entries(q).forEach(([k, v]) => {\n if (v !== undefined) {\n params.append(k, String(v));\n }\n });\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n","import { z } from 'zod';\nimport { ApiError, SafeParseResult } from './types';\n\n/**\n * Safely parse data with a Zod schema without throwing.\n * Returns a result object with success status and data or error.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Result object with success flag and data/error\n *\n * @example\n * ```ts\n * const result = safeParse(UserSchema, userData);\n * if (result.success) {\n * console.log(result.data);\n * } else {\n * console.error(result.error);\n * }\n * ```\n */\nexport function safeParse<T>(schema: z.ZodType, data: unknown): SafeParseResult<T> {\n const res = schema.safeParse(data);\n if (res.success) return { success: true, data: res.data as T };\n return { success: false, error: res.error };\n}\n\n/**\n * Parse data with a Zod schema, throwing an ApiError on validation failure.\n * Use this when you want to fail fast on invalid data.\n *\n * @param schema - Zod schema to validate against\n * @param data - Data to validate\n * @returns Validated and typed data\n * @throws {ApiError} If validation fails\n *\n * @example\n * ```ts\n * try {\n * const user = parseOrThrow(UserSchema, userData);\n * console.log(user);\n * } catch (error) {\n * if (error instanceof ApiError && error.zodError) {\n * console.error('Validation failed:', error.zodError.issues);\n * }\n * }\n * ```\n */\nexport function parseOrThrow<T>(schema: z.ZodType, data: unknown): T {\n const res = schema.safeParse(data);\n if (!res.success) {\n throw new ApiError('Response validation failed', { zodError: res.error });\n }\n return res.data as T;\n}\n","import { z } from 'zod';\nimport { HttpClient } from '../http/http-client';\nimport { HTTPMethod, SchemaDefinitionError } from '../types';\nimport { parseOrThrow } from '../validation';\n\nexport type EndpointConfig<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n> = {\n method: keyof typeof HTTPMethod;\n path: string | ((params: z.infer<Exclude<PathSchema, undefined>>) => string);\n response: ResSchema;\n request?: ReqSchema;\n query?: QuerySchema;\n pathParams?: PathSchema;\n baseUrlKey?: string;\n description?: string;\n};\n\nexport type EndpointCallParams<\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> = {\n data?: ReqSchema extends z.ZodType ? z.infer<ReqSchema> : never;\n query?: QuerySchema extends z.ZodType ? z.infer<QuerySchema> : never;\n pathParams?: PathSchema extends z.ZodType ? z.infer<PathSchema> : never;\n headers?: Record<string, string>;\n signal?: globalThis.AbortSignal;\n};\n\n// Helper to extract the response type from a schema which might be a single ZodType or a status map\ntype InferResponse<S> = S extends z.ZodType\n ? z.infer<S>\n : S extends Record<number, z.ZodType>\n ? z.infer<S[keyof S]>\n : never;\n\nexport class Endpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined,\n QuerySchema extends z.ZodType | undefined,\n PathSchema extends z.ZodType | undefined,\n> {\n constructor(\n private client: HttpClient,\n private config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ) { }\n\n async call(\n params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>\n ): Promise<InferResponse<ResSchema>> {\n const { data, query, pathParams, headers, signal } = params;\n\n // Validate Request Body\n if (this.config.request && data !== undefined) {\n const parsed = this.config.request.safeParse(data);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Query Params\n if (this.config.query && query !== undefined) {\n const parsed = this.config.query.safeParse(query);\n if (!parsed.success) throw parsed.error;\n }\n\n // Validate Path Params\n if (this.config.pathParams && pathParams !== undefined) {\n const parsed = this.config.pathParams.safeParse(pathParams);\n if (!parsed.success) throw parsed.error;\n }\n\n // Check for missing required params\n if (this.config.request && data === undefined) {\n throw new Error('Missing required request body (data)');\n }\n if (this.config.pathParams && pathParams === undefined) {\n throw new Error('Missing required path parameters (pathParams)');\n }\n\n // Resolve Path\n let pathStr: string;\n if (typeof this.config.path === 'function') {\n if (!pathParams) throw new Error('Path function requires pathParams');\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n pathStr = this.config.path(pathParams as any);\n } else {\n pathStr = this.config.path;\n }\n\n const { data: responseData, status } = await this.client.request(\n this.config.method,\n pathStr,\n data,\n {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n query: query as any,\n headers,\n baseUrlKey: this.config.baseUrlKey,\n signal,\n }\n );\n\n // Handle Response Validation\n const schema = this.config.response;\n if (schema instanceof z.ZodType) {\n // Single schema for all success codes\n return parseOrThrow(schema, responseData) as InferResponse<ResSchema>;\n }\n\n // Map of status codes\n const specificSchema = (schema as Record<number, z.ZodType>)[status];\n if (!specificSchema) {\n // Fallback or error? For now, rigorous error.\n throw new SchemaDefinitionError(status);\n }\n\n return parseOrThrow(specificSchema, responseData) as InferResponse<ResSchema>;\n }\n}\n","/**\n * Log levels for structured logging.\n */\nexport enum LogLevel {\n DEBUG = 'debug',\n INFO = 'info',\n WARN = 'warn',\n ERROR = 'error',\n}\n\n/**\n * Structured log entry with metadata.\n */\nexport interface LogEntry {\n level: LogLevel;\n message: string;\n timestamp: string;\n context?: Record<string, unknown>;\n error?: Error;\n}\n\n/**\n * Logger interface for custom logger implementations.\n * Implement this to integrate with your logging infrastructure.\n *\n * @example\n * ```ts\n * class ConsoleLogger implements Logger {\n * log(entry: LogEntry) {\n * console.log(JSON.stringify(entry));\n * }\n * }\n * ```\n */\nexport interface Logger {\n log(entry: LogEntry): void;\n}\n\n/**\n * Default console logger implementation.\n * Formats log entries as JSON for easy parsing.\n */\nexport class ConsoleLogger implements Logger {\n constructor(private minLevel: LogLevel = LogLevel.INFO) {}\n\n log(entry: LogEntry): void {\n const levels = [LogLevel.DEBUG, LogLevel.INFO, LogLevel.WARN, LogLevel.ERROR];\n const entryLevelIndex = levels.indexOf(entry.level);\n const minLevelIndex = levels.indexOf(this.minLevel);\n\n if (entryLevelIndex < minLevelIndex) return;\n\n const output = {\n ...entry,\n error: entry.error\n ? {\n message: entry.error.message,\n stack: entry.error.stack,\n name: entry.error.name,\n }\n : undefined,\n };\n\n switch (entry.level) {\n case LogLevel.DEBUG:\n console.debug(JSON.stringify(output));\n break;\n case LogLevel.INFO:\n console.info(JSON.stringify(output));\n break;\n case LogLevel.WARN:\n console.warn(JSON.stringify(output));\n break;\n case LogLevel.ERROR:\n console.error(JSON.stringify(output));\n break;\n }\n }\n}\n\n/**\n * No-op logger that discards all log entries.\n * Use this in production if you don't want any logging.\n */\nexport class NoOpLogger implements Logger {\n log(_entry: LogEntry): void {\n // no-op\n }\n}\n\n/**\n * Utility class for creating structured log entries.\n */\nexport class LoggerUtil {\n constructor(private logger: Logger) {}\n\n debug(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.DEBUG,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n info(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.INFO,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n warn(message: string, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.WARN,\n message,\n timestamp: new Date().toISOString(),\n context,\n });\n }\n\n error(message: string, error?: Error, context?: Record<string, unknown>): void {\n this.logger.log({\n level: LogLevel.ERROR,\n message,\n timestamp: new Date().toISOString(),\n context,\n error,\n });\n }\n}\n","/**\n * Metrics data for HTTP requests.\n */\nexport interface RequestMetrics {\n method: string;\n path: string;\n status?: number;\n durationMs: number;\n timestamp: string;\n success: boolean;\n error?: string;\n}\n\n/**\n * Interface for metrics collectors.\n * Implement this to integrate with your monitoring infrastructure (DataDog, Prometheus, etc.).\n *\n * @example\n * ```ts\n * class DataDogMetrics implements MetricsCollector {\n * collect(metrics: RequestMetrics) {\n * dogstatsd.histogram('http.request.duration', metrics.durationMs, {\n * method: metrics.method,\n * status: String(metrics.status)\n * });\n * }\n * }\n * ```\n */\nexport interface MetricsCollector {\n collect(metrics: RequestMetrics): void;\n}\n\n/**\n * No-op metrics collector that discards all metrics.\n */\nexport class NoOpMetricsCollector implements MetricsCollector {\n collect(_metrics: RequestMetrics): void {\n // no-op\n }\n}\n\n/**\n * In-memory metrics collector for testing and development.\n * Stores metrics in memory with configurable retention.\n */\nexport class InMemoryMetricsCollector implements MetricsCollector {\n private metrics: RequestMetrics[] = [];\n private readonly maxEntries: number;\n\n constructor(maxEntries = 1000) {\n this.maxEntries = maxEntries;\n }\n\n collect(metrics: RequestMetrics): void {\n this.metrics.push(metrics);\n if (this.metrics.length > this.maxEntries) {\n this.metrics.shift();\n }\n }\n\n /**\n * Get all collected metrics.\n */\n getMetrics(): RequestMetrics[] {\n return [...this.metrics];\n }\n\n /**\n * Get metrics summary statistics.\n */\n getSummary(): {\n total: number;\n successful: number;\n failed: number;\n avgDurationMs: number;\n minDurationMs: number;\n maxDurationMs: number;\n } {\n if (this.metrics.length === 0) {\n return {\n total: 0,\n successful: 0,\n failed: 0,\n avgDurationMs: 0,\n minDurationMs: 0,\n maxDurationMs: 0,\n };\n }\n\n const successful = this.metrics.filter((m) => m.success).length;\n\n // Calculate stats in a single pass to avoid stack overflow with spread operator\n let sum = 0;\n let min = Infinity;\n let max = -Infinity;\n\n for (const m of this.metrics) {\n const d = m.durationMs;\n sum += d;\n if (d < min) min = d;\n if (d > max) max = d;\n }\n\n return {\n total: this.metrics.length,\n successful,\n failed: this.metrics.length - successful,\n avgDurationMs: sum / this.metrics.length,\n minDurationMs: min === Infinity ? 0 : min,\n maxDurationMs: max === -Infinity ? 0 : max,\n };\n }\n\n /**\n * Clear all collected metrics.\n */\n clear(): void {\n this.metrics = [];\n }\n}\n\n/**\n * Console-based metrics collector for debugging.\n */\nexport class ConsoleMetricsCollector implements MetricsCollector {\n collect(metrics: RequestMetrics): void {\n console.log('[METRICS]', JSON.stringify(metrics));\n }\n}\n","import { z } from 'zod';\nimport type { AuthProvider } from '../auth';\nimport { NoAuth } from '../auth';\nimport { Endpoint, EndpointConfig } from '../endpoint/base-endpoint';\nimport { LoggerUtil, NoOpLogger } from '../logger';\nimport { MetricsCollector, NoOpMetricsCollector } from '../metrics';\nimport {\n ApiError,\n ClientOptions,\n FetchLike,\n HTTPMethod,\n HTTPStatusCode,\n HTTPStatusCodeNumber,\n Interceptors,\n RequestOptions,\n RetryStrategy,\n toQueryString,\n} from '../types';\n\n/**\n * HTTP client with built-in retry logic, authentication, and interceptors.\n * Supports multiple base URLs, type-safe requests, and comprehensive error handling.\n *\n * @example\n * ```ts\n * const client = new HttpClient({\n * baseUrls: { default: 'https://api.example.com' },\n * headers: { 'Content-Type': 'application/json' },\n * retry: { maxRetries: 3, baseDelayMs: 1000 },\n * timeout: { requestTimeoutMs: 30000 }\n * });\n *\n * const { data } = await client.request('GET', '/users', undefined, { query: { page: 1 } });\n * ```\n */\nexport class HttpClient {\n private fetchImpl: FetchLike;\n private baseUrls: ClientOptions['baseUrls'];\n private headers: Record<string, string>;\n private interceptors: Interceptors;\n private retry: RetryStrategy;\n private timeoutMs?: number;\n private auth: AuthProvider;\n private logger: LoggerUtil;\n private metrics: MetricsCollector;\n\n /**\n * Creates a new HTTP client instance.\n *\n * @param opts - Client configuration options\n * @throws {Error} If no fetch implementation is available\n */\n constructor(opts: ClientOptions) {\n this.fetchImpl = opts.fetch ?? (globalThis.fetch?.bind(globalThis) as FetchLike);\n if (!this.fetchImpl)\n throw new Error('No fetch implementation found. Pass one via options.fetch.');\n\n // Validate baseUrls configuration\n if (!opts.baseUrls || typeof opts.baseUrls !== 'object') {\n throw new Error('baseUrls must be provided and must be an object');\n }\n if (!opts.baseUrls.default) {\n throw new Error('baseUrls must include a \"default\" key');\n }\n\n this.baseUrls = opts.baseUrls;\n this.headers = opts.headers ?? { 'Content-Type': 'application/json' };\n this.interceptors = opts.interceptors ?? {};\n this.retry = opts.retry ?? {\n maxRetries: 2,\n baseDelayMs: 250,\n jitter: 0.2,\n retryMethods: ['GET', 'HEAD'],\n };\n\n // Default retryStatusCodes if not provided\n if (!this.retry.retryStatusCodes) {\n this.retry.retryStatusCodes = (\n Object.keys(HTTPStatusCode) as (keyof typeof HTTPStatusCode)[]\n ).filter((key) => {\n const code = HTTPStatusCode[key];\n return typeof code === 'number' && code >= 500;\n });\n }\n\n // Validate retry configuration\n if (this.retry.maxRetries < 0) {\n throw new Error('retry.maxRetries must be non-negative');\n }\n if (this.retry.baseDelayMs < 0) {\n throw new Error('retry.baseDelayMs must be non-negative');\n }\n if (this.retry.jitter !== undefined && (this.retry.jitter < 0 || this.retry.jitter > 1)) {\n throw new Error('retry.jitter must be between 0 and 1');\n }\n\n this.timeoutMs = opts.timeout?.requestTimeoutMs;\n if (this.timeoutMs !== undefined && this.timeoutMs < 0) {\n throw new Error('timeout.requestTimeoutMs must be non-negative');\n }\n\n this.auth = opts['auth'] ?? new NoAuth();\n this.logger = new LoggerUtil(opts.logger ?? new NoOpLogger());\n this.metrics = opts.metrics ?? new NoOpMetricsCollector();\n }\n\n /**\n * Set or update the authentication provider.\n *\n * @param auth - Authentication provider instance\n * @example\n * ```ts\n * client.setAuth(new BearerTokenAuth(() => getToken()));\n * ```\n */\n setAuth(auth: AuthProvider) {\n this.auth = auth;\n }\n\n private resolveBaseUrl(key?: keyof typeof this.baseUrls) {\n const k: string = (key as string) || 'default';\n const url = this.baseUrls[k];\n if (!url) {\n const availableKeys = Object.keys(this.baseUrls).join(', ');\n throw new Error(`Unknown baseUrl key: \"${k}\". Available keys: ${availableKeys}`);\n }\n return url.replace(/\\/$/, '');\n }\n\n /**\n * Sleep for a specified duration (used for retry backoff).\n * @private\n */\n private sleep(ms: number) {\n return new Promise((res) => setTimeout(res, ms));\n }\n\n /**\n * Execute a function with retry logic and exponential backoff.\n * @private\n */\n private async withRetry<T>(\n fn: () => Promise<T>,\n canRetry: (ctx: { attempt: number; error?: unknown; response?: Response }) => boolean\n ): Promise<T> {\n let attempt = 0;\n const { maxRetries, baseDelayMs, jitter = 0.2 } = this.retry;\n while (true) {\n try {\n return await fn();\n } catch (err: unknown) {\n if (attempt >= maxRetries || !canRetry({ attempt, error: err })) throw err;\n const backoff = baseDelayMs * 2 ** attempt;\n const j = 1 + (Math.random() * 2 - 1) * jitter;\n await this.sleep(backoff * j);\n attempt++;\n }\n }\n }\n\n /**\n * Run all registered before-request hooks.\n * @private\n */\n private async runBeforeHooks(url: string, init: RequestInit & { __urlOverride?: string }) {\n for (const h of this.interceptors.beforeRequest ?? []) {\n await h({ url, init });\n }\n }\n\n /**\n * Run all registered after-response hooks.\n * @private\n */\n private async runAfterHooks(req: Request, res: Response, parsed?: unknown) {\n for (const h of this.interceptors.afterResponse ?? []) {\n await h({ request: req, response: res, parsed });\n }\n }\n\n /**\n * Get all configured base URLs.\n *\n * @returns Object mapping base URL keys to their resolved URLs\n */\n public getBaseUrls() {\n return this.baseUrls;\n }\n\n /**\n * Get the resolved base URL for a given key.\n *\n * @param key - Base URL key (defaults to 'default' if not provided)\n * @returns Resolved base URL string\n */\n public getBaseUrl(key: string) {\n return this.resolveBaseUrl(key);\n }\n\n /**\n * Make an HTTP request with automatic retry, authentication, and validation.\n *\n * @param method - HTTP method (GET, POST, PUT, etc.)\n * @param path - Request path (will be appended to base URL)\n * @param body - Request body (will be JSON.stringify'd if Content-Type is json)\n * @param options - Additional request options (headers, query params, etc.)\n * @returns Promise resolving to response data and Response object\n * @throws {ApiError} If request fails or response validation fails\n *\n * @example\n * ```ts\n * const { data, response } = await client.request('GET', '/users', undefined, {\n * query: { page: 1, limit: 10 },\n * headers: { 'X-Custom': 'value' }\n * });\n * ```\n */\n async request<T = unknown>(\n method: keyof typeof HTTPMethod,\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n const startTime = Date.now();\n const base = this.resolveBaseUrl(options?.baseUrlKey);\n let url = `${base}${path}${toQueryString(options?.query)}`;\n\n this.logger.debug('HTTP request initiated', {\n method,\n path,\n baseUrlKey: options?.baseUrlKey,\n hasBody: body !== undefined,\n });\n\n const headers = { ...this.headers, ...(options?.headers ?? {}) };\n\n const controller = new AbortController();\n const signal = options?.signal ?? controller.signal;\n const init: RequestInit & { __urlOverride?: string } = {\n method,\n headers,\n body:\n body != null\n ? headers['Content-Type']?.includes('json')\n ? JSON.stringify(body)\n : String(body)\n : undefined,\n signal,\n };\n\n await this.auth.apply({ url, init, options });\n if (init.__urlOverride) url = init.__urlOverride;\n await this.runBeforeHooks(url, init);\n\n const doFetch = async () => {\n // Apply timeout if configured\n let timeoutId: NodeJS.Timeout | number | undefined;\n if (this.timeoutMs && !options?.signal) {\n timeoutId = setTimeout(() => {\n const timeoutError = new Error('Request timeout');\n timeoutError.name = 'TimeoutError';\n controller.abort(timeoutError);\n }, this.timeoutMs);\n }\n\n try {\n const req = new Request(url, init);\n\n const res = await this.fetchImpl(req);\n const status = res.status as HTTPStatusCodeNumber;\n const contentType = res.headers.get('content-type') || '';\n const data = contentType.includes('json') ? await res.json() : await res.text();\n await this.runAfterHooks(new Request(url, init), res, data);\n\n const duration = Date.now() - startTime;\n this.logger.info('HTTP request successful', {\n method,\n url,\n status: res.status,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: res.status,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: true,\n });\n\n return { data: data as T, status: status };\n } catch (error) {\n const duration = Date.now() - startTime;\n this.logger.error('HTTP request failed', error as Error, {\n method,\n url,\n durationMs: duration,\n });\n\n this.metrics.collect({\n method,\n path,\n status: error instanceof ApiError ? error.status : undefined,\n durationMs: duration,\n timestamp: new Date().toISOString(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n\n throw error;\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n }\n };\n\n const canRetry = ({ error }: { error?: unknown }) => {\n // Don't retry timeouts or aborts\n if (error && typeof error === 'object' && 'name' in error) {\n const errorName = (error as { name?: string }).name;\n if (errorName === 'AbortError' || errorName === 'TimeoutError') return false;\n }\n // Retry on network errors or configured status codes\n if (error instanceof ApiError && error.status) {\n const retryCodes = this.retry.retryStatusCodes;\n if (retryCodes?.some((codeKey) => HTTPStatusCode[codeKey] === error.status)) {\n return true;\n }\n }\n return false;\n };\n\n if (!this.retry.retryMethods?.includes(method)) {\n return doFetch();\n }\n\n return this.withRetry(doFetch, canRetry);\n }\n\n /**\n * Convenience method for GET requests.\n *\n * @example\n * ```ts\n * const { data } = await client.get('/users', { query: { page: 1 } });\n * ```\n */\n async get<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('GET', path, undefined, options);\n }\n\n /**\n * Convenience method for POST requests.\n *\n * @example\n * ```ts\n * const { data } = await client.post('/users', { name: 'John' });\n * ```\n */\n async post<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('POST', path, body, options);\n }\n\n /**\n * Convenience method for PUT requests.\n *\n * @example\n * ```ts\n * const { data } = await client.put('/users/1', { name: 'John Updated' });\n * ```\n */\n async put<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PUT', path, body, options);\n }\n\n /**\n * Convenience method for PATCH requests.\n *\n * @example\n * ```ts\n * const { data } = await client.patch('/users/1', { name: 'John' });\n * ```\n */\n async patch<T = unknown>(\n path: string,\n body?: unknown,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('PATCH', path, body, options);\n }\n\n /**\n * Convenience method for DELETE requests.\n *\n * @example\n * ```ts\n * const { data } = await client.delete('/users/1');\n * ```\n */\n async delete<T = unknown>(\n path: string,\n options?: RequestOptions\n ): Promise<{ data: T; status: HTTPStatusCodeNumber }> {\n return this.request<T>('DELETE', path, undefined, options);\n }\n\n /**\n * Create a strongly-typed endpoint builder.\n *\n * @param config - Endpoint configuration\n * @returns Endpoint instance\n */\n createEndpoint<\n ResSchema extends z.ZodType | Record<number, z.ZodType>,\n ReqSchema extends z.ZodType | undefined = undefined,\n QuerySchema extends z.ZodType | undefined = undefined,\n PathSchema extends z.ZodType | undefined = undefined,\n >(\n config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>\n ): Endpoint<ResSchema, ReqSchema, QuerySchema, PathSchema> {\n return new Endpoint(this, config);\n }\n}\n","import { z } from 'zod';\n\n/**\n * Common ID type that supports strings, numbers, or UUIDs.\n * Use this for entity identifiers in your schemas.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({ id: Id, name: z.string() });\n * ```\n */\nexport const Id = z.union([\n z.string().min(1),\n z.number(),\n z.uuid({\n version: 'v4',\n }),\n]);\nexport type IdType = z.infer<typeof Id>;\n\n/**\n * Common timestamp fields for entities.\n * Use this for database models with creation/update tracking.\n *\n * @example\n * ```ts\n * const UserSchema = z.object({\n * id: Id,\n * name: z.string(),\n * ...Timestamps.shape\n * });\n * ```\n */\nexport const Timestamps = z.object({\n createdAt: z.iso.datetime(),\n updatedAt: z.iso.datetime(),\n});\n\n/**\n * Metadata information typically included in API responses.\n * Contains request tracking and debugging information.\n */\nexport const Meta = z.object({\n requestId: z.string().optional(),\n timestamp: z.iso.datetime().optional(),\n traceId: z.string().optional(),\n});\n\n/**\n * Detailed error information for a specific field or path.\n */\nexport const ErrorDetail = z.object({\n path: z.string().optional(),\n message: z.string(),\n});\n\n/**\n * Standard API error response schema.\n * Use this for consistent error handling across your API.\n */\nexport const ApiErrorSchema = z.object({\n code: z.string(),\n message: z.string(),\n details: z.array(ErrorDetail).optional(),\n});\n\n/**\n * Generic envelope wrapper for API responses.\n * Provides consistent structure with success flag, data, error, and metadata.\n *\n * @param inner - Zod schema for the response data\n * @returns Envelope schema wrapping the inner schema\n *\n * @example\n * ```ts\n * const UserResponseSchema = Envelope(z.object({ id: Id, name: z.string() }));\n *\n * // Response structure:\n * // {\n * // success: true,\n * // data: { id: 1, name: 'John' },\n * // meta: { requestId: '...' }\n * // }\n * ```\n */\nexport const Envelope = <T extends z.ZodType>(inner: T) =>\n z.object({\n success: z.boolean(),\n data: inner.optional().nullable(),\n error: ApiErrorSchema.optional(),\n meta: Meta.optional(),\n });\n"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -127,7 +127,7 @@ export declare const HTTPStatusCode: {
127
127
  readonly NETWORK_AUTHENTICATION_REQUIRED: 511;
128
128
  };
129
129
  export type HTTPStatusCode = keyof typeof HTTPStatusCode;
130
- export type HTTPStatusCodeNumber = typeof HTTPStatusCode[HTTPStatusCode];
130
+ export type HTTPStatusCodeNumber = (typeof HTTPStatusCode)[HTTPStatusCode];
131
131
  /**
132
132
  * Hook called after a response is received and parsed.
133
133
  * Useful for logging, metrics, or global error handling.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../lib/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zlient",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "author": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -72,5 +72,4 @@
72
72
  "test": "bun test"
73
73
  },
74
74
  "type": "module"
75
-
76
75
  }