zlient 1.0.11 → 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 +70 -361
- package/dist/auth.d.ts.map +1 -1
- package/dist/endpoint/base-endpoint.d.ts +21 -109
- package/dist/endpoint/base-endpoint.d.ts.map +1 -1
- package/dist/http/http-client.d.ts +16 -7
- package/dist/http/http-client.d.ts.map +1 -1
- package/dist/index.cjs +238 -233
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +235 -229
- package/dist/index.js.map +1 -1
- package/dist/metrics.d.ts.map +1 -1
- package/dist/types.d.ts +78 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +40 -44
package/README.md
CHANGED
|
@@ -1,430 +1,139 @@
|
|
|
1
1
|
# zlient
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**The Type-Safe HTTP Client for Perfectionists.**
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
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
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
36
|
+
### 1. Initialize Client
|
|
127
37
|
|
|
128
38
|
```typescript
|
|
129
|
-
import { HttpClient
|
|
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
|
-
|
|
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
|
-
###
|
|
49
|
+
### 2. Define Endpoint
|
|
152
50
|
|
|
153
|
-
|
|
51
|
+
Use `createEndpoint` to build a type-safe definition. No classes required.
|
|
154
52
|
|
|
155
53
|
```typescript
|
|
156
|
-
import {
|
|
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
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
+
TypeScript will enforce inputs and infer the response type automatically.
|
|
202
72
|
|
|
203
73
|
```typescript
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
220
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
Add hooks to inspect or modify requests and responses:
|
|
82
|
+
---
|
|
245
83
|
|
|
246
|
-
|
|
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
|
-
###
|
|
86
|
+
### Authentication
|
|
265
87
|
|
|
266
|
-
|
|
88
|
+
Zlient provides built-in auth providers that safely handle headers.
|
|
267
89
|
|
|
268
90
|
```typescript
|
|
269
|
-
import {
|
|
91
|
+
import { BearerTokenAuth, ApiKeyAuth } from 'zlient';
|
|
270
92
|
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
//
|
|
279
|
-
|
|
98
|
+
// API Key (Header or Query)
|
|
99
|
+
client.setAuth(new ApiKeyAuth({ header: 'X-API-KEY', value: 'secret' }));
|
|
280
100
|
```
|
|
281
101
|
|
|
282
|
-
|
|
102
|
+
### Multiple Status Codes
|
|
283
103
|
|
|
284
|
-
|
|
104
|
+
Handle different responses for different status codes.
|
|
285
105
|
|
|
286
106
|
```typescript
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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
|
-
|
|
296
|
-
|
|
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
|
-
###
|
|
121
|
+
### Metrics & Logging
|
|
300
122
|
|
|
301
|
-
|
|
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 {
|
|
126
|
+
import { InMemoryMetricsCollector, ConsoleLogger } from 'zlient';
|
|
316
127
|
|
|
317
128
|
const client = new HttpClient({
|
|
318
|
-
baseUrls: { default: '
|
|
319
|
-
logger: new ConsoleLogger(
|
|
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
|
-
|
|
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)
|
package/dist/auth.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC/C;AAED;;;GAGG;AACH,qBAAa,MAAO,YAAW,YAAY;IACnC,KAAK;CAGZ;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAW,YAAW,YAAY;IACjC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAQ5E,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,GAAG;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC/C;AAED;;;GAGG;AACH,qBAAa,MAAO,YAAW,YAAY;IACnC,KAAK;CAGZ;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,UAAW,YAAW,YAAY;IACjC,OAAO,CAAC,IAAI;gBAAJ,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;IAQ5E,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,WAAW;CAgBjC;AACD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,YAAY;IACtC,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM;IACtD,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,WAAW;CAclC"}
|
|
@@ -1,117 +1,29 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { HttpClient } from '../http/http-client';
|
|
3
3
|
import { HTTPMethod } from '../types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
export type EndpointCallConfig<ReqSchema extends z.ZodType, PathParams = never, QueryParams = never> = {
|
|
13
|
-
/** Request body data (for POST, PUT, PATCH, etc.) or request args */
|
|
14
|
-
data?: z.infer<ReqSchema>;
|
|
15
|
-
/** Path parameters for dynamic path construction */
|
|
16
|
-
pathParams?: PathParams;
|
|
17
|
-
/** Query string parameters */
|
|
18
|
-
query?: QueryParams;
|
|
19
|
-
/** Request headers */
|
|
20
|
-
headers?: Record<string, string>;
|
|
21
|
-
/** Override base URL for this call */
|
|
4
|
+
export type EndpointConfig<ResSchema extends z.ZodType | Record<number, z.ZodType>, ReqSchema extends z.ZodType | undefined = undefined, QuerySchema extends z.ZodType | undefined = undefined, PathSchema extends z.ZodType | undefined = undefined> = {
|
|
5
|
+
method: keyof typeof HTTPMethod;
|
|
6
|
+
path: string | ((params: z.infer<Exclude<PathSchema, undefined>>) => string);
|
|
7
|
+
response: ResSchema;
|
|
8
|
+
request?: ReqSchema;
|
|
9
|
+
query?: QuerySchema;
|
|
10
|
+
pathParams?: PathSchema;
|
|
22
11
|
baseUrlKey?: string;
|
|
23
|
-
|
|
12
|
+
description?: string;
|
|
13
|
+
};
|
|
14
|
+
export type EndpointCallParams<ReqSchema extends z.ZodType | undefined, QuerySchema extends z.ZodType | undefined, PathSchema extends z.ZodType | undefined> = {
|
|
15
|
+
data?: ReqSchema extends z.ZodType ? z.infer<ReqSchema> : never;
|
|
16
|
+
query?: QuerySchema extends z.ZodType ? z.infer<QuerySchema> : never;
|
|
17
|
+
pathParams?: PathSchema extends z.ZodType ? z.infer<PathSchema> : never;
|
|
18
|
+
headers?: Record<string, string>;
|
|
24
19
|
signal?: globalThis.AbortSignal;
|
|
25
20
|
};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* @template PathParams - Type for path parameters (optional)
|
|
33
|
-
* @template QueryParams - Type for query parameters (optional)
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* const UserSchema = z.object({ id: z.number(), name: z.string() });
|
|
38
|
-
* const CreateUserSchema = z.object({ name: z.string() });
|
|
39
|
-
*
|
|
40
|
-
* type UserPathParams = { id: string };
|
|
41
|
-
* type UserQueryParams = { include?: string; limit?: number };
|
|
42
|
-
*
|
|
43
|
-
* class GetUser extends BaseEndpoint<
|
|
44
|
-
* typeof CreateUserSchema,
|
|
45
|
-
* typeof UserSchema,
|
|
46
|
-
* UserPathParams,
|
|
47
|
-
* UserQueryParams
|
|
48
|
-
* > {
|
|
49
|
-
* protected method = 'GET' as const;
|
|
50
|
-
* protected path = (params: UserPathParams) => `/users/${params.id}`;
|
|
51
|
-
*
|
|
52
|
-
* constructor(client: HttpClient) {
|
|
53
|
-
* super(client, {
|
|
54
|
-
* requestSchema: CreateUserSchema,
|
|
55
|
-
* responseSchema: UserSchema
|
|
56
|
-
* });
|
|
57
|
-
* }
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* // Usage:
|
|
61
|
-
* const user = await endpoint.call({
|
|
62
|
-
* pathParams: { id: '123' },
|
|
63
|
-
* query: { include: 'posts', limit: 10 }
|
|
64
|
-
* });
|
|
65
|
-
* ```
|
|
66
|
-
*/
|
|
67
|
-
export declare abstract class BaseEndpoint<ReqSchema extends z.ZodType, ResSchema extends z.ZodType, PathParams = never, QueryParams = never> {
|
|
68
|
-
protected client: HttpClient;
|
|
69
|
-
/** HTTP method for this endpoint */
|
|
70
|
-
protected abstract readonly method: keyof typeof HTTPMethod;
|
|
71
|
-
/** URL path (can be a function for dynamic paths) */
|
|
72
|
-
protected abstract readonly path: string | ((params: PathParams) => string);
|
|
73
|
-
/** Additional options for the request */
|
|
74
|
-
protected readonly options?: {
|
|
75
|
-
/** Override base URL for this call */
|
|
76
|
-
baseUrlKey?: string;
|
|
77
|
-
};
|
|
78
|
-
/** Optional request schema for validation */
|
|
79
|
-
protected readonly requestSchema?: ReqSchema;
|
|
80
|
-
/** Response schema for validation */
|
|
81
|
-
protected readonly responseSchema: ResSchema;
|
|
82
|
-
/**
|
|
83
|
-
* @param client - HttpClient instance
|
|
84
|
-
* @param cfg - Configuration with request and response schemas
|
|
85
|
-
*/
|
|
86
|
-
constructor(client: HttpClient, cfg: {
|
|
87
|
-
requestSchema?: ReqSchema;
|
|
88
|
-
responseSchema: ResSchema;
|
|
89
|
-
});
|
|
90
|
-
/**
|
|
91
|
-
* Call the endpoint with strong typing derived from schemas.
|
|
92
|
-
* Validates request data before sending and response data after receiving.
|
|
93
|
-
*
|
|
94
|
-
* @param config - Request configuration object containing all parameters
|
|
95
|
-
* @returns Promise resolving to validated response data (typed by ResSchema)
|
|
96
|
-
* @throws {ZodError} If request validation fails
|
|
97
|
-
* @throws {ApiError} If response validation fails or request fails
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* ```ts
|
|
101
|
-
* const endpoint = new GetUser(client);
|
|
102
|
-
* const user = await endpoint.call({
|
|
103
|
-
* pathParams: { id: '123' },
|
|
104
|
-
* query: { include: 'posts' }
|
|
105
|
-
* });
|
|
106
|
-
* // With additional options:
|
|
107
|
-
* const user = await endpoint.call({
|
|
108
|
-
* data: { name: 'John' },
|
|
109
|
-
* pathParams: { id: '123' },
|
|
110
|
-
* headers: { 'X-Custom': 'value' },
|
|
111
|
-
* query: { include: 'posts' }
|
|
112
|
-
* });
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
call(config?: EndpointCallConfig<ReqSchema, PathParams, QueryParams>): Promise<z.infer<ResSchema>>;
|
|
21
|
+
type InferResponse<S> = S extends z.ZodType ? z.infer<S> : S extends Record<number, z.ZodType> ? z.infer<S[keyof S]> : never;
|
|
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> {
|
|
23
|
+
private client;
|
|
24
|
+
private config;
|
|
25
|
+
constructor(client: HttpClient, config: EndpointConfig<ResSchema, ReqSchema, QuerySchema, PathSchema>);
|
|
26
|
+
call(params: EndpointCallParams<ReqSchema, QuerySchema, PathSchema>): Promise<InferResponse<ResSchema>>;
|
|
116
27
|
}
|
|
28
|
+
export {};
|
|
117
29
|
//# sourceMappingURL=base-endpoint.d.ts.map
|
|
@@ -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,
|
|
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"}
|