@tahanabavi/typefetch 1.0.3 → 1.1.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,6 +1,6 @@
1
1
  # TypeFetch
2
2
 
3
- TypeFetch is a type-safe client for working with APIs, built with TypeScript and Zod. This project allows you to define API contracts and safely use types, while also supporting middlewares, error handling, and response transformation.
3
+ TypeFetch is a type-safe client for working with APIs, built with TypeScript and Zod. This project allows you to define API contracts and safely use types, while also supporting middlewares, error handling, response transformation, mock data, and response wrappers.
4
4
 
5
5
  ---
6
6
 
@@ -12,6 +12,8 @@ TypeFetch is a type-safe client for working with APIs, built with TypeScript and
12
12
  - Error handling with the `RichError` class
13
13
  - Ability to transform responses using a response transformer
14
14
  - Authentication support via token
15
+ - Mock data support for development and testing
16
+ - Response wrapper for consistent API response formats
15
17
 
16
18
  ---
17
19
 
@@ -25,9 +27,39 @@ yarn add @tahanabavi/typefetch
25
27
 
26
28
  ---
27
29
 
30
+ ## What's New in v1.1.1
31
+
32
+ ### 🎯 Mock Data Support
33
+
34
+ - Add mock data to endpoints for development and testing
35
+ - Configurable random delays to simulate network latency
36
+ - Support for both static data and dynamic functions
37
+ - Runtime toggle between mock and real API modes
38
+
39
+ ### 🔄 Response Wrapper
40
+
41
+ - Consistent API response format handling
42
+ - Automatic validation of wrapped responses
43
+ - Support for success/error response patterns
44
+ - Seamless integration with existing contracts
45
+
46
+ ### 🚀 Enhanced Error Handling
47
+
48
+ - Better Zod error wrapping and reporting
49
+ - Improved type safety for response wrappers
50
+
51
+ ### 🔧 Token Provider System
52
+
53
+ - Dynamic token resolution: Tokens resolved at request time, not initialization
54
+ - Universal compatibility: Works seamlessly in both server and client environments
55
+ - Async token providers: Support for asynchronous token retrieval
56
+ - Multiple token sources: Flexible token sourcing from cookies, context, or external services
57
+
58
+ ---
59
+
28
60
  ## Defining Contracts
29
61
 
30
- Contracts are defined using the `Contracts` and `EndpointDef` types
62
+ Contracts are defined using the `Contracts` and `EndpointDef` types.
31
63
 
32
64
  ```ts
33
65
  import { z } from "zod";
@@ -40,12 +72,16 @@ const contracts = {
40
72
  auth: true,
41
73
  request: z.object({ id: z.string() }),
42
74
  response: z.object({ id: z.string(), name: z.string() }),
75
+ // Optional mock data
76
+ mockData: { id: "1", name: "John Doe" },
43
77
  },
44
78
  createUser: {
45
79
  method: "POST",
46
80
  path: "/user",
47
81
  request: z.object({ name: z.string() }),
48
82
  response: z.object({ id: z.string(), name: z.string() }),
83
+ // Dynamic mock data function
84
+ mockData: () => ({ id: Math.random().toString(), name: "Dynamic User" }),
49
85
  },
50
86
  },
51
87
  } as const;
@@ -62,6 +98,8 @@ const client = new ApiClient(
62
98
  {
63
99
  baseUrl: "https://api.example.com",
64
100
  token: "your-auth-token",
101
+ useMockData: true,
102
+ mockDelay: { min: 100, max: 1000 },
65
103
  },
66
104
  contracts
67
105
  );
@@ -82,7 +120,7 @@ All errors are provided via the `RichError` class. You can define a custom error
82
120
 
83
121
  ```ts
84
122
  client.onError((error: RichError) => {
85
- console.error("API Error:", error.message, error.status);
123
+ console.error("API Error:", error.message, error.status, error.code);
86
124
  });
87
125
  ```
88
126
 
@@ -140,11 +178,61 @@ client.useResponseTransform((data) => {
140
178
 
141
179
  ---
142
180
 
181
+ ## Mock Data Features
182
+
183
+ Static Mock Data:
184
+
185
+ ```ts
186
+ mockData: { id: "1", name: "Static User" }
187
+ ```
188
+
189
+ Dynamic Mock Data:
190
+
191
+ ```ts
192
+ mockData: () => ({ id: Math.random().toString(), name: `User-${Date.now()}` });
193
+ ```
194
+
195
+ Runtime Control:
196
+
197
+ ```ts
198
+ client.setMockMode(true, { min: 100, max: 2000 });
199
+ client.setMockMode(false);
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Response Wrapper Features
205
+
206
+ ```ts
207
+ const apiResponseWrapper = (successResponse: z.ZodTypeAny) =>
208
+ z.union([
209
+ z.object({
210
+ success: z.literal(true),
211
+ data: successResponse,
212
+ timestamp: z.string(),
213
+ requestId: z.string(),
214
+ }),
215
+ z.object({
216
+ success: z.literal(false),
217
+ message: z.string(),
218
+ code: z.number(),
219
+ timestamp: z.string(),
220
+ requestId: z.string(),
221
+ }),
222
+ ]);
223
+
224
+ client.setResponseWrapper(apiResponseWrapper);
225
+ ```
226
+
227
+ ---
228
+
143
229
  ## Important Notes
144
230
 
145
231
  - Always call `client.init()` before using endpoints.
146
232
  - Types are automatically inferred from Zod, making inputs and outputs type-safe.
147
233
  - Middleware execution order: first added middleware runs last, last added middleware runs first.
234
+ - Mock data is used only when `useMockData` is true and mock data is defined.
235
+ - Response wrapper automatically handles success/error patterns.
148
236
 
149
237
  ---
150
238
 
@@ -156,23 +244,50 @@ import { ApiClient, RichError } from "typefetch";
156
244
  import { LoggingMiddleware, RetryMiddleware } from "typefetch/middlewares";
157
245
 
158
246
  const contracts = {
159
- post: {
160
- getPost: {
247
+ user: {
248
+ getUser: {
161
249
  method: "GET",
162
- path: "/posts/:id",
250
+ path: "/users/:id",
163
251
  auth: true,
164
252
  request: z.object({ id: z.string() }),
165
- response: z.object({ id: z.string(), title: z.string() }),
253
+ response: z.object({
254
+ id: z.string(),
255
+ name: z.string(),
256
+ email: z.string(),
257
+ }),
258
+ mockData: { id: "1", name: "John Doe", email: "john@example.com" },
166
259
  },
167
260
  },
168
261
  } as const;
169
262
 
263
+ const apiResponseWrapper = (successResponse: z.ZodTypeAny) =>
264
+ z.union([
265
+ z.object({
266
+ success: z.literal(true),
267
+ data: successResponse,
268
+ timestamp: z.string(),
269
+ requestId: z.string(),
270
+ }),
271
+ z.object({
272
+ success: z.literal(false),
273
+ message: z.string(),
274
+ code: z.number(),
275
+ timestamp: z.string(),
276
+ requestId: z.string(),
277
+ }),
278
+ ]);
279
+
170
280
  const client = new ApiClient(
171
- { baseUrl: "https://api.example.com", token: "abc123" },
281
+ {
282
+ baseUrl: "https://api.example.com",
283
+ token: "abc123",
284
+ useMockData: process.env.NODE_ENV === "development",
285
+ },
172
286
  contracts
173
287
  );
174
288
 
175
289
  client.init();
290
+ client.setResponseWrapper(apiResponseWrapper);
176
291
  client.use(LoggingMiddleware);
177
292
  client.use(RetryMiddleware, { maxRetries: 2 });
178
293
 
@@ -183,7 +298,13 @@ client.onError((err: RichError) => {
183
298
  const { modules: api } = client;
184
299
 
185
300
  (async () => {
186
- const post = await api.post.getPost({ id: "1" });
187
- console.log(post);
301
+ const user = await api.user.getUser({ id: "1" });
302
+ console.log(user);
188
303
  })();
189
304
  ```
305
+
306
+ ---
307
+
308
+ ## License
309
+
310
+ MIT
package/dist/index.d.mts CHANGED
@@ -6,6 +6,7 @@ type EndpointDef<TReq extends z.ZodTypeAny, TRes extends z.ZodTypeAny> = {
6
6
  auth?: boolean;
7
7
  request: TReq;
8
8
  response: TRes;
9
+ mockData?: (() => z.infer<TRes>) | z.infer<TRes>;
9
10
  };
10
11
  type Contracts = {
11
12
  [ModuleName: string]: {
@@ -28,6 +29,7 @@ type EndpointDefZ = EndpointDef<z.ZodTypeAny, z.ZodTypeAny>;
28
29
  type EndpointMethods<M extends Record<string, EndpointDefZ>> = {
29
30
  [K in keyof M]: (input: z.infer<M[K]["request"]>) => Promise<z.infer<M[K]["response"]>>;
30
31
  };
32
+ type TokenProvider = () => string | Promise<string>;
31
33
 
32
34
  declare class RichError extends Error implements ErrorLike {
33
35
  status?: number;
@@ -45,17 +47,36 @@ declare class ApiClient<C extends Contracts, E extends ErrorLike = RichError> {
45
47
  private middlewares;
46
48
  private errorHandler?;
47
49
  private responseTransform;
50
+ private useMockData;
51
+ private mockDelay;
52
+ private responseWrapper?;
53
+ private tokenProvider?;
48
54
  private _modules;
49
55
  constructor(config: {
50
56
  baseUrl: string;
51
57
  token?: string;
58
+ tokenProvider?: TokenProvider;
59
+ useMockData?: boolean;
60
+ mockDelay?: {
61
+ min: number;
62
+ max: number;
63
+ };
52
64
  }, contracts: C);
53
65
  init(): void;
54
66
  get modules(): { [M in keyof C]: EndpointMethods<C[M]>; };
55
67
  use<T>(middleware: Middleware<T>, options?: T): void;
56
68
  onError(handler: (error: E) => void): void;
57
69
  useResponseTransform(fn: (data: any) => any): void;
70
+ setMockMode(enabled: boolean, delay?: {
71
+ min: number;
72
+ max: number;
73
+ }): void;
74
+ setResponseWrapper(wrapper: (successResponse: z.ZodTypeAny) => z.ZodTypeAny): void;
75
+ setTokenProvider(provider: TokenProvider): void;
76
+ getCurrentToken(): Promise<string | undefined>;
58
77
  private request;
78
+ private handleMockRequest;
79
+ private getRandomDelay;
59
80
  private createError;
60
81
  private normalizeError;
61
82
  }
@@ -83,4 +104,4 @@ type CacheOptions = {
83
104
  };
84
105
  declare const cacheMiddleware: (options?: CacheOptions) => (ctx: MiddlewareContext, next: MiddlewareNext) => Promise<Response>;
85
106
 
86
- export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
107
+ export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, type TokenProvider, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ type EndpointDef<TReq extends z.ZodTypeAny, TRes extends z.ZodTypeAny> = {
6
6
  auth?: boolean;
7
7
  request: TReq;
8
8
  response: TRes;
9
+ mockData?: (() => z.infer<TRes>) | z.infer<TRes>;
9
10
  };
10
11
  type Contracts = {
11
12
  [ModuleName: string]: {
@@ -28,6 +29,7 @@ type EndpointDefZ = EndpointDef<z.ZodTypeAny, z.ZodTypeAny>;
28
29
  type EndpointMethods<M extends Record<string, EndpointDefZ>> = {
29
30
  [K in keyof M]: (input: z.infer<M[K]["request"]>) => Promise<z.infer<M[K]["response"]>>;
30
31
  };
32
+ type TokenProvider = () => string | Promise<string>;
31
33
 
32
34
  declare class RichError extends Error implements ErrorLike {
33
35
  status?: number;
@@ -45,17 +47,36 @@ declare class ApiClient<C extends Contracts, E extends ErrorLike = RichError> {
45
47
  private middlewares;
46
48
  private errorHandler?;
47
49
  private responseTransform;
50
+ private useMockData;
51
+ private mockDelay;
52
+ private responseWrapper?;
53
+ private tokenProvider?;
48
54
  private _modules;
49
55
  constructor(config: {
50
56
  baseUrl: string;
51
57
  token?: string;
58
+ tokenProvider?: TokenProvider;
59
+ useMockData?: boolean;
60
+ mockDelay?: {
61
+ min: number;
62
+ max: number;
63
+ };
52
64
  }, contracts: C);
53
65
  init(): void;
54
66
  get modules(): { [M in keyof C]: EndpointMethods<C[M]>; };
55
67
  use<T>(middleware: Middleware<T>, options?: T): void;
56
68
  onError(handler: (error: E) => void): void;
57
69
  useResponseTransform(fn: (data: any) => any): void;
70
+ setMockMode(enabled: boolean, delay?: {
71
+ min: number;
72
+ max: number;
73
+ }): void;
74
+ setResponseWrapper(wrapper: (successResponse: z.ZodTypeAny) => z.ZodTypeAny): void;
75
+ setTokenProvider(provider: TokenProvider): void;
76
+ getCurrentToken(): Promise<string | undefined>;
58
77
  private request;
78
+ private handleMockRequest;
79
+ private getRandomDelay;
59
80
  private createError;
60
81
  private normalizeError;
61
82
  }
@@ -83,4 +104,4 @@ type CacheOptions = {
83
104
  };
84
105
  declare const cacheMiddleware: (options?: CacheOptions) => (ctx: MiddlewareContext, next: MiddlewareNext) => Promise<Response>;
85
106
 
86
- export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };
107
+ export { ApiClient, type AuthOptions, type CacheOptions, type Contracts, type EndpointDef, type EndpointDefZ, type EndpointMethods, type ErrorLike, type LoggingOptions, type Middleware, type MiddlewareContext, type MiddlewareNext, type RetryOptions, RichError, type TokenProvider, authMiddleware, cacheMiddleware, loggingMiddleware, retryMiddleware };