@tahanabavi/typefetch 1.0.2 → 1.1.0

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/dist/index.js CHANGED
@@ -1,22 +1,297 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
9
+ var __pow = Math.pow;
10
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
11
+ var __spreadValues = (a, b) => {
12
+ for (var prop in b || (b = {}))
13
+ if (__hasOwnProp.call(b, prop))
14
+ __defNormalProp(a, prop, b[prop]);
15
+ if (__getOwnPropSymbols)
16
+ for (var prop of __getOwnPropSymbols(b)) {
17
+ if (__propIsEnum.call(b, prop))
18
+ __defNormalProp(a, prop, b[prop]);
7
19
  }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
- __exportStar(require("./client"), exports);
19
- __exportStar(require("./middlewares/logging"), exports);
20
- __exportStar(require("./middlewares/retry"), exports);
21
- __exportStar(require("./middlewares/auth"), exports);
22
- __exportStar(require("./middlewares/cache"), exports);
20
+ return a;
21
+ };
22
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
23
+ var __export = (target, all) => {
24
+ for (var name in all)
25
+ __defProp(target, name, { get: all[name], enumerable: true });
26
+ };
27
+ var __copyProps = (to, from, except, desc) => {
28
+ if (from && typeof from === "object" || typeof from === "function") {
29
+ for (let key of __getOwnPropNames(from))
30
+ if (!__hasOwnProp.call(to, key) && key !== except)
31
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
32
+ }
33
+ return to;
34
+ };
35
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
36
+ var __async = (__this, __arguments, generator) => {
37
+ return new Promise((resolve, reject) => {
38
+ var fulfilled = (value) => {
39
+ try {
40
+ step(generator.next(value));
41
+ } catch (e) {
42
+ reject(e);
43
+ }
44
+ };
45
+ var rejected = (value) => {
46
+ try {
47
+ step(generator.throw(value));
48
+ } catch (e) {
49
+ reject(e);
50
+ }
51
+ };
52
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
53
+ step((generator = generator.apply(__this, __arguments)).next());
54
+ });
55
+ };
56
+
57
+ // src/index.ts
58
+ var index_exports = {};
59
+ __export(index_exports, {
60
+ ApiClient: () => ApiClient,
61
+ RichError: () => RichError,
62
+ authMiddleware: () => authMiddleware,
63
+ cacheMiddleware: () => cacheMiddleware,
64
+ loggingMiddleware: () => loggingMiddleware,
65
+ retryMiddleware: () => retryMiddleware
66
+ });
67
+ module.exports = __toCommonJS(index_exports);
68
+
69
+ // src/client.ts
70
+ var RichError = class extends Error {
71
+ constructor(error) {
72
+ super(error.message);
73
+ Object.assign(this, error);
74
+ }
75
+ };
76
+ var ApiClient = class {
77
+ constructor(config, contracts) {
78
+ this.config = config;
79
+ this.contracts = contracts;
80
+ this.middlewares = [];
81
+ this.responseTransform = (d) => d;
82
+ this.useMockData = false;
83
+ this.mockDelay = { min: 100, max: 1e3 };
84
+ this.useMockData = config.useMockData || false;
85
+ this.mockDelay = config.mockDelay || { min: 100, max: 1e3 };
86
+ }
87
+ init() {
88
+ const modules = {};
89
+ for (const moduleName in this.contracts) {
90
+ const module2 = this.contracts[moduleName];
91
+ modules[moduleName] = {};
92
+ for (const endpointName in module2) {
93
+ const endpoint = module2[endpointName];
94
+ modules[moduleName][endpointName] = (input) => this.request(endpoint, input);
95
+ }
96
+ }
97
+ this._modules = modules;
98
+ }
99
+ get modules() {
100
+ return this._modules;
101
+ }
102
+ use(middleware, options) {
103
+ this.middlewares.push({ fn: middleware, options });
104
+ }
105
+ onError(handler) {
106
+ this.errorHandler = handler;
107
+ }
108
+ useResponseTransform(fn) {
109
+ this.responseTransform = fn;
110
+ }
111
+ setMockMode(enabled, delay) {
112
+ this.useMockData = enabled;
113
+ if (delay) {
114
+ this.mockDelay = delay;
115
+ }
116
+ }
117
+ setResponseWrapper(wrapper) {
118
+ this.responseWrapper = wrapper;
119
+ }
120
+ request(endpoint, input) {
121
+ return __async(this, null, function* () {
122
+ var _a, _b, _c, _d;
123
+ endpoint.request.parse(input);
124
+ if (this.useMockData && endpoint.mockData) {
125
+ return this.handleMockRequest(endpoint);
126
+ }
127
+ if (endpoint.auth && !this.config.token) {
128
+ const error = this.createError({
129
+ message: `Missing token for ${endpoint.path}`,
130
+ status: 401,
131
+ code: "NO_TOKEN"
132
+ });
133
+ (_a = this.errorHandler) == null ? void 0 : _a.call(this, error);
134
+ throw error;
135
+ }
136
+ const headers = { "Content-Type": "application/json" };
137
+ if (endpoint.auth && this.config.token)
138
+ headers["Authorization"] = `Bearer ${this.config.token}`;
139
+ const ctx = {
140
+ url: this.config.baseUrl + endpoint.path,
141
+ init: {
142
+ method: endpoint.method,
143
+ headers,
144
+ body: endpoint.method !== "GET" ? JSON.stringify(input) : void 0
145
+ }
146
+ };
147
+ const runner = this.middlewares.reduceRight(
148
+ (next, mw) => () => mw.fn(ctx, next, mw.options),
149
+ () => fetch(ctx.url, ctx.init)
150
+ );
151
+ try {
152
+ const res = yield runner();
153
+ const json = yield res.json();
154
+ let responseData = json;
155
+ if (this.responseWrapper) {
156
+ const wrappedSchema = this.responseWrapper(endpoint.response);
157
+ const parsedResponse = wrappedSchema.parse(json);
158
+ if (parsedResponse.success === false) {
159
+ const error = this.createError({
160
+ message: parsedResponse.message || "Request failed",
161
+ status: parsedResponse.code || res.status,
162
+ code: `API_ERROR_${parsedResponse.code}`
163
+ });
164
+ (_b = this.errorHandler) == null ? void 0 : _b.call(this, error);
165
+ throw error;
166
+ }
167
+ responseData = parsedResponse.data;
168
+ }
169
+ if (!res.ok) {
170
+ const error = this.createError({
171
+ message: json.message || res.statusText,
172
+ status: res.status,
173
+ code: json.code,
174
+ title: json.title,
175
+ detail: json.detail,
176
+ errors: json.errors
177
+ });
178
+ (_c = this.errorHandler) == null ? void 0 : _c.call(this, error);
179
+ throw error;
180
+ }
181
+ return this.responseTransform(endpoint.response.parse(responseData));
182
+ } catch (err) {
183
+ const error = this.normalizeError(err);
184
+ (_d = this.errorHandler) == null ? void 0 : _d.call(this, error);
185
+ throw error;
186
+ }
187
+ });
188
+ }
189
+ handleMockRequest(endpoint) {
190
+ return __async(this, null, function* () {
191
+ const delay = this.getRandomDelay();
192
+ yield new Promise((resolve) => setTimeout(resolve, delay));
193
+ let mockData;
194
+ if (typeof endpoint.mockData === "function") {
195
+ mockData = endpoint.mockData();
196
+ } else {
197
+ mockData = endpoint.mockData;
198
+ }
199
+ if (this.responseWrapper) {
200
+ const wrappedSchema = this.responseWrapper(endpoint.response);
201
+ const mockWrappedResponse = {
202
+ success: true,
203
+ data: mockData,
204
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
205
+ requestId: `mock-${Math.random().toString(36).substr(2, 9)}`
206
+ };
207
+ const parsedWrappedResponse = wrappedSchema.parse(mockWrappedResponse);
208
+ return this.responseTransform(
209
+ endpoint.response.parse(parsedWrappedResponse.data)
210
+ );
211
+ }
212
+ return this.responseTransform(endpoint.response.parse(mockData));
213
+ });
214
+ }
215
+ getRandomDelay() {
216
+ return Math.floor(
217
+ Math.random() * (this.mockDelay.max - this.mockDelay.min + 1)
218
+ ) + this.mockDelay.min;
219
+ }
220
+ createError(error) {
221
+ return new RichError(error);
222
+ }
223
+ normalizeError(err) {
224
+ if (err instanceof RichError) return err;
225
+ return this.createError({ message: err.message || "Unknown error" });
226
+ }
227
+ };
228
+
229
+ // src/middlewares/logging.ts
230
+ var loggingMiddleware = (ctx, next, options) => __async(null, null, function* () {
231
+ const { logRequest = true, logResponse = true, debug = true } = options || {};
232
+ if (debug && logRequest) console.log("\u27A1\uFE0F Request:", ctx.url, ctx.init);
233
+ const res = yield next();
234
+ if (debug && logResponse) console.log("\u2B05\uFE0F Response:", res.status);
235
+ return res;
236
+ });
237
+
238
+ // src/middlewares/retry.ts
239
+ var retryMiddleware = (options) => {
240
+ const { maxRetries = 3, delay = 500 } = options || {};
241
+ const middleware = (ctx, next) => __async(null, null, function* () {
242
+ let attempt = 0;
243
+ while (true) {
244
+ try {
245
+ return yield next();
246
+ } catch (err) {
247
+ if (attempt >= maxRetries) throw err;
248
+ attempt++;
249
+ yield new Promise((r) => setTimeout(r, delay * __pow(2, attempt)));
250
+ }
251
+ }
252
+ });
253
+ return middleware;
254
+ };
255
+
256
+ // src/middlewares/auth.ts
257
+ var authMiddleware = (ctx, next, options) => __async(null, null, function* () {
258
+ if (options == null ? void 0 : options.refreshToken) {
259
+ try {
260
+ const newToken = yield options.refreshToken();
261
+ ctx.init.headers = __spreadProps(__spreadValues({}, ctx.init.headers), {
262
+ Authorization: `Bearer ${newToken}`
263
+ });
264
+ } catch (e) {
265
+ }
266
+ }
267
+ return next();
268
+ });
269
+
270
+ // src/middlewares/cache.ts
271
+ var cacheMiddleware = (options = {}) => {
272
+ const { ttl = 6e4 } = options;
273
+ const cache = /* @__PURE__ */ new Map();
274
+ return (ctx, next) => __async(null, null, function* () {
275
+ if (ctx.init.method === "GET") {
276
+ const cached = cache.get(ctx.url);
277
+ const now = Date.now();
278
+ if (cached && cached.expires > now)
279
+ return new Response(JSON.stringify(cached.data));
280
+ const res = yield next();
281
+ const data = yield res.clone().json().catch(() => null);
282
+ if (data) cache.set(ctx.url, { data, expires: now + ttl });
283
+ return res;
284
+ }
285
+ return next();
286
+ });
287
+ };
288
+ // Annotate the CommonJS export names for ESM import in node:
289
+ 0 && (module.exports = {
290
+ ApiClient,
291
+ RichError,
292
+ authMiddleware,
293
+ cacheMiddleware,
294
+ loggingMiddleware,
295
+ retryMiddleware
296
+ });
297
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/middlewares/logging.ts","../src/middlewares/retry.ts","../src/middlewares/auth.ts","../src/middlewares/cache.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./client\";\nexport * from \"./middlewares/logging\";\nexport * from \"./middlewares/retry\";\nexport * from \"./middlewares/auth\";\nexport * from \"./middlewares/cache\";\n","import {\n Contracts,\n EndpointDef,\n EndpointDefZ,\n Middleware,\n ErrorLike,\n EndpointMethods,\n} from \"@/types\";\nimport { z } from \"zod\";\n\nexport class RichError extends Error implements ErrorLike {\n status?: number;\n code?: string;\n title?: string;\n detail?: string;\n errors?: Record<string, string[]>;\n\n constructor(error: Partial<ErrorLike> & { message: string }) {\n super(error.message);\n Object.assign(this, error);\n }\n}\n\nexport class ApiClient<C extends Contracts, E extends ErrorLike = RichError> {\n private middlewares: Array<{ fn: Middleware; options?: any }> = [];\n private errorHandler?: (error: E) => void;\n private responseTransform: (data: any) => any = (d) => d;\n private useMockData: boolean = false;\n private mockDelay: { min: number; max: number } = { min: 100, max: 1000 };\n private responseWrapper?: (successResponse: z.ZodTypeAny) => z.ZodTypeAny;\n\n private _modules!: {\n [M in keyof C]: EndpointMethods<C[M]>;\n };\n\n constructor(\n private config: {\n baseUrl: string;\n token?: string;\n useMockData?: boolean;\n mockDelay?: { min: number; max: number };\n },\n private contracts: C\n ) {\n this.useMockData = config.useMockData || false;\n this.mockDelay = config.mockDelay || { min: 100, max: 1000 };\n }\n\n init() {\n const modules = {} as {\n [M in keyof C]: EndpointMethods<C[M]>;\n };\n\n for (const moduleName in this.contracts) {\n const module = this.contracts[moduleName];\n (modules as any)[moduleName] = {} as EndpointMethods<typeof module>;\n\n for (const endpointName in module) {\n const endpoint = module[endpointName] as EndpointDefZ;\n\n (modules as any)[moduleName][endpointName] = (\n input: z.infer<(typeof endpoint)[\"request\"]>\n ) => this.request(endpoint, input);\n }\n }\n\n this._modules = modules;\n }\n\n get modules() {\n return this._modules;\n }\n\n use<T>(middleware: Middleware<T>, options?: T) {\n this.middlewares.push({ fn: middleware, options });\n }\n\n onError(handler: (error: E) => void) {\n this.errorHandler = handler;\n }\n\n useResponseTransform(fn: (data: any) => any) {\n this.responseTransform = fn;\n }\n\n setMockMode(enabled: boolean, delay?: { min: number; max: number }) {\n this.useMockData = enabled;\n if (delay) {\n this.mockDelay = delay;\n }\n }\n\n setResponseWrapper(wrapper: (successResponse: z.ZodTypeAny) => z.ZodTypeAny) {\n this.responseWrapper = wrapper;\n }\n\n private async request<TReq extends z.ZodTypeAny, TRes extends z.ZodTypeAny>(\n endpoint: EndpointDef<TReq, TRes>,\n input: z.infer<TReq>\n ): Promise<z.infer<TRes>> {\n endpoint.request.parse(input);\n\n if (this.useMockData && endpoint.mockData) {\n return this.handleMockRequest(endpoint);\n }\n\n if (endpoint.auth && !this.config.token) {\n const error = this.createError({\n message: `Missing token for ${endpoint.path}`,\n status: 401,\n code: \"NO_TOKEN\",\n });\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n\n const headers: HeadersInit = { \"Content-Type\": \"application/json\" };\n if (endpoint.auth && this.config.token)\n headers[\"Authorization\"] = `Bearer ${this.config.token}`;\n\n const ctx = {\n url: this.config.baseUrl + endpoint.path,\n init: {\n method: endpoint.method,\n headers,\n body: endpoint.method !== \"GET\" ? JSON.stringify(input) : undefined,\n },\n };\n\n const runner = this.middlewares.reduceRight(\n (next, mw) => () => mw.fn(ctx, next, mw.options),\n () => fetch(ctx.url, ctx.init)\n );\n\n try {\n const res = await runner();\n const json = await res.json();\n\n let responseData = json;\n if (this.responseWrapper) {\n const wrappedSchema = this.responseWrapper(endpoint.response);\n const parsedResponse = wrappedSchema.parse(json);\n\n if (parsedResponse.success === false) {\n const error = this.createError({\n message: parsedResponse.message || \"Request failed\",\n status: parsedResponse.code || res.status,\n code: `API_ERROR_${parsedResponse.code}`,\n });\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n\n responseData = parsedResponse.data;\n }\n\n if (!res.ok) {\n const error = this.createError({\n message: json.message || res.statusText,\n status: res.status,\n code: json.code,\n title: json.title,\n detail: json.detail,\n errors: json.errors,\n });\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n\n return this.responseTransform(endpoint.response.parse(responseData));\n } catch (err: any) {\n const error = this.normalizeError(err);\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n }\n\n private async handleMockRequest<\n TReq extends z.ZodTypeAny,\n TRes extends z.ZodTypeAny\n >(endpoint: EndpointDef<TReq, TRes>): Promise<z.infer<TRes>> {\n const delay = this.getRandomDelay();\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n let mockData: z.infer<TRes>;\n if (typeof endpoint.mockData === \"function\") {\n mockData = (endpoint.mockData as () => z.infer<TRes>)();\n } else {\n mockData = endpoint.mockData as z.infer<TRes>;\n }\n\n if (this.responseWrapper) {\n const wrappedSchema = this.responseWrapper(endpoint.response);\n\n const mockWrappedResponse = {\n success: true,\n data: mockData,\n timestamp: new Date().toISOString(),\n requestId: `mock-${Math.random().toString(36).substr(2, 9)}`,\n };\n\n const parsedWrappedResponse = wrappedSchema.parse(mockWrappedResponse);\n\n return this.responseTransform(\n endpoint.response.parse(parsedWrappedResponse.data)\n );\n }\n\n return this.responseTransform(endpoint.response.parse(mockData));\n }\n\n private getRandomDelay(): number {\n return (\n Math.floor(\n Math.random() * (this.mockDelay.max - this.mockDelay.min + 1)\n ) + this.mockDelay.min\n );\n }\n\n private createError(error: Partial<RichError> & { message: string }) {\n return new RichError(error);\n }\n\n private normalizeError(err: any) {\n if (err instanceof RichError) return err;\n return this.createError({ message: err.message || \"Unknown error\" });\n }\n}\n","import { Middleware } from \"@/types\";\n\nexport type LoggingOptions = {\n logRequest?: boolean;\n logResponse?: boolean;\n debug?: boolean;\n};\n\nexport const loggingMiddleware: Middleware<LoggingOptions> = async (\n ctx,\n next,\n options\n) => {\n const { logRequest = true, logResponse = true, debug = true } = options || {};\n\n if (debug && logRequest) console.log(\"➡️ Request:\", ctx.url, ctx.init);\n\n const res = await next();\n\n if (debug && logResponse) console.log(\"⬅️ Response:\", res.status);\n\n return res;\n};\n","import { Middleware } from \"@/types\";\n\n\nexport type RetryOptions = {\n maxRetries?: number;\n delay?: number; // ms\n};\n\nexport const retryMiddleware = (options?: RetryOptions): Middleware => {\n const { maxRetries = 3, delay = 500 } = options || {};\n\n const middleware: Middleware = async (ctx, next) => {\n let attempt = 0;\n while (true) {\n try {\n return await next();\n } catch (err) {\n if (attempt >= maxRetries) throw err;\n attempt++;\n await new Promise((r) => setTimeout(r, delay * 2 ** attempt));\n }\n }\n };\n\n return middleware;\n};\n","import { Middleware } from \"@/types\";\n\nexport type AuthOptions = {\n refreshToken?: () => Promise<string>;\n};\n\nexport const authMiddleware: Middleware<AuthOptions> = async (\n ctx,\n next,\n options\n) => {\n if (options?.refreshToken) {\n try {\n const newToken = await options.refreshToken();\n ctx.init.headers = {\n ...ctx.init.headers,\n Authorization: `Bearer ${newToken}`,\n };\n } catch {}\n }\n\n return next();\n};\n","import { MiddlewareContext, MiddlewareNext } from \"@/types\";\n\nexport type CacheOptions = { ttl?: number };\n\nexport const cacheMiddleware = (options: CacheOptions = {}) => {\n const { ttl = 60000 } = options;\n const cache = new Map<string, { data: any; expires: number }>();\n\n return async (ctx: MiddlewareContext, next: MiddlewareNext) => {\n if (ctx.init.method === \"GET\") {\n const cached = cache.get(ctx.url);\n const now = Date.now();\n if (cached && cached.expires > now)\n return new Response(JSON.stringify(cached.data));\n\n const res = await next();\n const data = await res\n .clone()\n .json()\n .catch(() => null);\n if (data) cache.set(ctx.url, { data, expires: now + ttl });\n return res;\n }\n return next();\n };\n};\n"],"mappings":"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","names":["module"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,269 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __pow = Math.pow;
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __spreadValues = (a, b) => {
10
+ for (var prop in b || (b = {}))
11
+ if (__hasOwnProp.call(b, prop))
12
+ __defNormalProp(a, prop, b[prop]);
13
+ if (__getOwnPropSymbols)
14
+ for (var prop of __getOwnPropSymbols(b)) {
15
+ if (__propIsEnum.call(b, prop))
16
+ __defNormalProp(a, prop, b[prop]);
17
+ }
18
+ return a;
19
+ };
20
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
21
+ var __async = (__this, __arguments, generator) => {
22
+ return new Promise((resolve, reject) => {
23
+ var fulfilled = (value) => {
24
+ try {
25
+ step(generator.next(value));
26
+ } catch (e) {
27
+ reject(e);
28
+ }
29
+ };
30
+ var rejected = (value) => {
31
+ try {
32
+ step(generator.throw(value));
33
+ } catch (e) {
34
+ reject(e);
35
+ }
36
+ };
37
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
38
+ step((generator = generator.apply(__this, __arguments)).next());
39
+ });
40
+ };
41
+
42
+ // src/client.ts
43
+ var RichError = class extends Error {
44
+ constructor(error) {
45
+ super(error.message);
46
+ Object.assign(this, error);
47
+ }
48
+ };
49
+ var ApiClient = class {
50
+ constructor(config, contracts) {
51
+ this.config = config;
52
+ this.contracts = contracts;
53
+ this.middlewares = [];
54
+ this.responseTransform = (d) => d;
55
+ this.useMockData = false;
56
+ this.mockDelay = { min: 100, max: 1e3 };
57
+ this.useMockData = config.useMockData || false;
58
+ this.mockDelay = config.mockDelay || { min: 100, max: 1e3 };
59
+ }
60
+ init() {
61
+ const modules = {};
62
+ for (const moduleName in this.contracts) {
63
+ const module = this.contracts[moduleName];
64
+ modules[moduleName] = {};
65
+ for (const endpointName in module) {
66
+ const endpoint = module[endpointName];
67
+ modules[moduleName][endpointName] = (input) => this.request(endpoint, input);
68
+ }
69
+ }
70
+ this._modules = modules;
71
+ }
72
+ get modules() {
73
+ return this._modules;
74
+ }
75
+ use(middleware, options) {
76
+ this.middlewares.push({ fn: middleware, options });
77
+ }
78
+ onError(handler) {
79
+ this.errorHandler = handler;
80
+ }
81
+ useResponseTransform(fn) {
82
+ this.responseTransform = fn;
83
+ }
84
+ setMockMode(enabled, delay) {
85
+ this.useMockData = enabled;
86
+ if (delay) {
87
+ this.mockDelay = delay;
88
+ }
89
+ }
90
+ setResponseWrapper(wrapper) {
91
+ this.responseWrapper = wrapper;
92
+ }
93
+ request(endpoint, input) {
94
+ return __async(this, null, function* () {
95
+ var _a, _b, _c, _d;
96
+ endpoint.request.parse(input);
97
+ if (this.useMockData && endpoint.mockData) {
98
+ return this.handleMockRequest(endpoint);
99
+ }
100
+ if (endpoint.auth && !this.config.token) {
101
+ const error = this.createError({
102
+ message: `Missing token for ${endpoint.path}`,
103
+ status: 401,
104
+ code: "NO_TOKEN"
105
+ });
106
+ (_a = this.errorHandler) == null ? void 0 : _a.call(this, error);
107
+ throw error;
108
+ }
109
+ const headers = { "Content-Type": "application/json" };
110
+ if (endpoint.auth && this.config.token)
111
+ headers["Authorization"] = `Bearer ${this.config.token}`;
112
+ const ctx = {
113
+ url: this.config.baseUrl + endpoint.path,
114
+ init: {
115
+ method: endpoint.method,
116
+ headers,
117
+ body: endpoint.method !== "GET" ? JSON.stringify(input) : void 0
118
+ }
119
+ };
120
+ const runner = this.middlewares.reduceRight(
121
+ (next, mw) => () => mw.fn(ctx, next, mw.options),
122
+ () => fetch(ctx.url, ctx.init)
123
+ );
124
+ try {
125
+ const res = yield runner();
126
+ const json = yield res.json();
127
+ let responseData = json;
128
+ if (this.responseWrapper) {
129
+ const wrappedSchema = this.responseWrapper(endpoint.response);
130
+ const parsedResponse = wrappedSchema.parse(json);
131
+ if (parsedResponse.success === false) {
132
+ const error = this.createError({
133
+ message: parsedResponse.message || "Request failed",
134
+ status: parsedResponse.code || res.status,
135
+ code: `API_ERROR_${parsedResponse.code}`
136
+ });
137
+ (_b = this.errorHandler) == null ? void 0 : _b.call(this, error);
138
+ throw error;
139
+ }
140
+ responseData = parsedResponse.data;
141
+ }
142
+ if (!res.ok) {
143
+ const error = this.createError({
144
+ message: json.message || res.statusText,
145
+ status: res.status,
146
+ code: json.code,
147
+ title: json.title,
148
+ detail: json.detail,
149
+ errors: json.errors
150
+ });
151
+ (_c = this.errorHandler) == null ? void 0 : _c.call(this, error);
152
+ throw error;
153
+ }
154
+ return this.responseTransform(endpoint.response.parse(responseData));
155
+ } catch (err) {
156
+ const error = this.normalizeError(err);
157
+ (_d = this.errorHandler) == null ? void 0 : _d.call(this, error);
158
+ throw error;
159
+ }
160
+ });
161
+ }
162
+ handleMockRequest(endpoint) {
163
+ return __async(this, null, function* () {
164
+ const delay = this.getRandomDelay();
165
+ yield new Promise((resolve) => setTimeout(resolve, delay));
166
+ let mockData;
167
+ if (typeof endpoint.mockData === "function") {
168
+ mockData = endpoint.mockData();
169
+ } else {
170
+ mockData = endpoint.mockData;
171
+ }
172
+ if (this.responseWrapper) {
173
+ const wrappedSchema = this.responseWrapper(endpoint.response);
174
+ const mockWrappedResponse = {
175
+ success: true,
176
+ data: mockData,
177
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
178
+ requestId: `mock-${Math.random().toString(36).substr(2, 9)}`
179
+ };
180
+ const parsedWrappedResponse = wrappedSchema.parse(mockWrappedResponse);
181
+ return this.responseTransform(
182
+ endpoint.response.parse(parsedWrappedResponse.data)
183
+ );
184
+ }
185
+ return this.responseTransform(endpoint.response.parse(mockData));
186
+ });
187
+ }
188
+ getRandomDelay() {
189
+ return Math.floor(
190
+ Math.random() * (this.mockDelay.max - this.mockDelay.min + 1)
191
+ ) + this.mockDelay.min;
192
+ }
193
+ createError(error) {
194
+ return new RichError(error);
195
+ }
196
+ normalizeError(err) {
197
+ if (err instanceof RichError) return err;
198
+ return this.createError({ message: err.message || "Unknown error" });
199
+ }
200
+ };
201
+
202
+ // src/middlewares/logging.ts
203
+ var loggingMiddleware = (ctx, next, options) => __async(null, null, function* () {
204
+ const { logRequest = true, logResponse = true, debug = true } = options || {};
205
+ if (debug && logRequest) console.log("\u27A1\uFE0F Request:", ctx.url, ctx.init);
206
+ const res = yield next();
207
+ if (debug && logResponse) console.log("\u2B05\uFE0F Response:", res.status);
208
+ return res;
209
+ });
210
+
211
+ // src/middlewares/retry.ts
212
+ var retryMiddleware = (options) => {
213
+ const { maxRetries = 3, delay = 500 } = options || {};
214
+ const middleware = (ctx, next) => __async(null, null, function* () {
215
+ let attempt = 0;
216
+ while (true) {
217
+ try {
218
+ return yield next();
219
+ } catch (err) {
220
+ if (attempt >= maxRetries) throw err;
221
+ attempt++;
222
+ yield new Promise((r) => setTimeout(r, delay * __pow(2, attempt)));
223
+ }
224
+ }
225
+ });
226
+ return middleware;
227
+ };
228
+
229
+ // src/middlewares/auth.ts
230
+ var authMiddleware = (ctx, next, options) => __async(null, null, function* () {
231
+ if (options == null ? void 0 : options.refreshToken) {
232
+ try {
233
+ const newToken = yield options.refreshToken();
234
+ ctx.init.headers = __spreadProps(__spreadValues({}, ctx.init.headers), {
235
+ Authorization: `Bearer ${newToken}`
236
+ });
237
+ } catch (e) {
238
+ }
239
+ }
240
+ return next();
241
+ });
242
+
243
+ // src/middlewares/cache.ts
244
+ var cacheMiddleware = (options = {}) => {
245
+ const { ttl = 6e4 } = options;
246
+ const cache = /* @__PURE__ */ new Map();
247
+ return (ctx, next) => __async(null, null, function* () {
248
+ if (ctx.init.method === "GET") {
249
+ const cached = cache.get(ctx.url);
250
+ const now = Date.now();
251
+ if (cached && cached.expires > now)
252
+ return new Response(JSON.stringify(cached.data));
253
+ const res = yield next();
254
+ const data = yield res.clone().json().catch(() => null);
255
+ if (data) cache.set(ctx.url, { data, expires: now + ttl });
256
+ return res;
257
+ }
258
+ return next();
259
+ });
260
+ };
261
+ export {
262
+ ApiClient,
263
+ RichError,
264
+ authMiddleware,
265
+ cacheMiddleware,
266
+ loggingMiddleware,
267
+ retryMiddleware
268
+ };
269
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/client.ts","../src/middlewares/logging.ts","../src/middlewares/retry.ts","../src/middlewares/auth.ts","../src/middlewares/cache.ts"],"sourcesContent":["import {\n Contracts,\n EndpointDef,\n EndpointDefZ,\n Middleware,\n ErrorLike,\n EndpointMethods,\n} from \"@/types\";\nimport { z } from \"zod\";\n\nexport class RichError extends Error implements ErrorLike {\n status?: number;\n code?: string;\n title?: string;\n detail?: string;\n errors?: Record<string, string[]>;\n\n constructor(error: Partial<ErrorLike> & { message: string }) {\n super(error.message);\n Object.assign(this, error);\n }\n}\n\nexport class ApiClient<C extends Contracts, E extends ErrorLike = RichError> {\n private middlewares: Array<{ fn: Middleware; options?: any }> = [];\n private errorHandler?: (error: E) => void;\n private responseTransform: (data: any) => any = (d) => d;\n private useMockData: boolean = false;\n private mockDelay: { min: number; max: number } = { min: 100, max: 1000 };\n private responseWrapper?: (successResponse: z.ZodTypeAny) => z.ZodTypeAny;\n\n private _modules!: {\n [M in keyof C]: EndpointMethods<C[M]>;\n };\n\n constructor(\n private config: {\n baseUrl: string;\n token?: string;\n useMockData?: boolean;\n mockDelay?: { min: number; max: number };\n },\n private contracts: C\n ) {\n this.useMockData = config.useMockData || false;\n this.mockDelay = config.mockDelay || { min: 100, max: 1000 };\n }\n\n init() {\n const modules = {} as {\n [M in keyof C]: EndpointMethods<C[M]>;\n };\n\n for (const moduleName in this.contracts) {\n const module = this.contracts[moduleName];\n (modules as any)[moduleName] = {} as EndpointMethods<typeof module>;\n\n for (const endpointName in module) {\n const endpoint = module[endpointName] as EndpointDefZ;\n\n (modules as any)[moduleName][endpointName] = (\n input: z.infer<(typeof endpoint)[\"request\"]>\n ) => this.request(endpoint, input);\n }\n }\n\n this._modules = modules;\n }\n\n get modules() {\n return this._modules;\n }\n\n use<T>(middleware: Middleware<T>, options?: T) {\n this.middlewares.push({ fn: middleware, options });\n }\n\n onError(handler: (error: E) => void) {\n this.errorHandler = handler;\n }\n\n useResponseTransform(fn: (data: any) => any) {\n this.responseTransform = fn;\n }\n\n setMockMode(enabled: boolean, delay?: { min: number; max: number }) {\n this.useMockData = enabled;\n if (delay) {\n this.mockDelay = delay;\n }\n }\n\n setResponseWrapper(wrapper: (successResponse: z.ZodTypeAny) => z.ZodTypeAny) {\n this.responseWrapper = wrapper;\n }\n\n private async request<TReq extends z.ZodTypeAny, TRes extends z.ZodTypeAny>(\n endpoint: EndpointDef<TReq, TRes>,\n input: z.infer<TReq>\n ): Promise<z.infer<TRes>> {\n endpoint.request.parse(input);\n\n if (this.useMockData && endpoint.mockData) {\n return this.handleMockRequest(endpoint);\n }\n\n if (endpoint.auth && !this.config.token) {\n const error = this.createError({\n message: `Missing token for ${endpoint.path}`,\n status: 401,\n code: \"NO_TOKEN\",\n });\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n\n const headers: HeadersInit = { \"Content-Type\": \"application/json\" };\n if (endpoint.auth && this.config.token)\n headers[\"Authorization\"] = `Bearer ${this.config.token}`;\n\n const ctx = {\n url: this.config.baseUrl + endpoint.path,\n init: {\n method: endpoint.method,\n headers,\n body: endpoint.method !== \"GET\" ? JSON.stringify(input) : undefined,\n },\n };\n\n const runner = this.middlewares.reduceRight(\n (next, mw) => () => mw.fn(ctx, next, mw.options),\n () => fetch(ctx.url, ctx.init)\n );\n\n try {\n const res = await runner();\n const json = await res.json();\n\n let responseData = json;\n if (this.responseWrapper) {\n const wrappedSchema = this.responseWrapper(endpoint.response);\n const parsedResponse = wrappedSchema.parse(json);\n\n if (parsedResponse.success === false) {\n const error = this.createError({\n message: parsedResponse.message || \"Request failed\",\n status: parsedResponse.code || res.status,\n code: `API_ERROR_${parsedResponse.code}`,\n });\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n\n responseData = parsedResponse.data;\n }\n\n if (!res.ok) {\n const error = this.createError({\n message: json.message || res.statusText,\n status: res.status,\n code: json.code,\n title: json.title,\n detail: json.detail,\n errors: json.errors,\n });\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n\n return this.responseTransform(endpoint.response.parse(responseData));\n } catch (err: any) {\n const error = this.normalizeError(err);\n this.errorHandler?.(error as unknown as E);\n throw error;\n }\n }\n\n private async handleMockRequest<\n TReq extends z.ZodTypeAny,\n TRes extends z.ZodTypeAny\n >(endpoint: EndpointDef<TReq, TRes>): Promise<z.infer<TRes>> {\n const delay = this.getRandomDelay();\n await new Promise((resolve) => setTimeout(resolve, delay));\n\n let mockData: z.infer<TRes>;\n if (typeof endpoint.mockData === \"function\") {\n mockData = (endpoint.mockData as () => z.infer<TRes>)();\n } else {\n mockData = endpoint.mockData as z.infer<TRes>;\n }\n\n if (this.responseWrapper) {\n const wrappedSchema = this.responseWrapper(endpoint.response);\n\n const mockWrappedResponse = {\n success: true,\n data: mockData,\n timestamp: new Date().toISOString(),\n requestId: `mock-${Math.random().toString(36).substr(2, 9)}`,\n };\n\n const parsedWrappedResponse = wrappedSchema.parse(mockWrappedResponse);\n\n return this.responseTransform(\n endpoint.response.parse(parsedWrappedResponse.data)\n );\n }\n\n return this.responseTransform(endpoint.response.parse(mockData));\n }\n\n private getRandomDelay(): number {\n return (\n Math.floor(\n Math.random() * (this.mockDelay.max - this.mockDelay.min + 1)\n ) + this.mockDelay.min\n );\n }\n\n private createError(error: Partial<RichError> & { message: string }) {\n return new RichError(error);\n }\n\n private normalizeError(err: any) {\n if (err instanceof RichError) return err;\n return this.createError({ message: err.message || \"Unknown error\" });\n }\n}\n","import { Middleware } from \"@/types\";\n\nexport type LoggingOptions = {\n logRequest?: boolean;\n logResponse?: boolean;\n debug?: boolean;\n};\n\nexport const loggingMiddleware: Middleware<LoggingOptions> = async (\n ctx,\n next,\n options\n) => {\n const { logRequest = true, logResponse = true, debug = true } = options || {};\n\n if (debug && logRequest) console.log(\"➡️ Request:\", ctx.url, ctx.init);\n\n const res = await next();\n\n if (debug && logResponse) console.log(\"⬅️ Response:\", res.status);\n\n return res;\n};\n","import { Middleware } from \"@/types\";\n\n\nexport type RetryOptions = {\n maxRetries?: number;\n delay?: number; // ms\n};\n\nexport const retryMiddleware = (options?: RetryOptions): Middleware => {\n const { maxRetries = 3, delay = 500 } = options || {};\n\n const middleware: Middleware = async (ctx, next) => {\n let attempt = 0;\n while (true) {\n try {\n return await next();\n } catch (err) {\n if (attempt >= maxRetries) throw err;\n attempt++;\n await new Promise((r) => setTimeout(r, delay * 2 ** attempt));\n }\n }\n };\n\n return middleware;\n};\n","import { Middleware } from \"@/types\";\n\nexport type AuthOptions = {\n refreshToken?: () => Promise<string>;\n};\n\nexport const authMiddleware: Middleware<AuthOptions> = async (\n ctx,\n next,\n options\n) => {\n if (options?.refreshToken) {\n try {\n const newToken = await options.refreshToken();\n ctx.init.headers = {\n ...ctx.init.headers,\n Authorization: `Bearer ${newToken}`,\n };\n } catch {}\n }\n\n return next();\n};\n","import { MiddlewareContext, MiddlewareNext } from \"@/types\";\n\nexport type CacheOptions = { ttl?: number };\n\nexport const cacheMiddleware = (options: CacheOptions = {}) => {\n const { ttl = 60000 } = options;\n const cache = new Map<string, { data: any; expires: number }>();\n\n return async (ctx: MiddlewareContext, next: MiddlewareNext) => {\n if (ctx.init.method === \"GET\") {\n const cached = cache.get(ctx.url);\n const now = Date.now();\n if (cached && cached.expires > now)\n return new Response(JSON.stringify(cached.data));\n\n const res = await next();\n const data = await res\n .clone()\n .json()\n .catch(() => null);\n if (data) cache.set(ctx.url, { data, expires: now + ttl });\n return res;\n }\n return next();\n };\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,11 +1,15 @@
1
1
  {
2
2
  "name": "@tahanabavi/typefetch",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "A fully type-safe, extensible API client for TypeScript projects, featuring global error handling, configurable middleware, automatic retries, auth refresh, response transforms, and seamless contract integration. Designed for large-scale applications and developer-friendly API interactions.",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "/dist"
10
+ ],
7
11
  "scripts": {
8
- "build": "tsc",
12
+ "build": "tsup",
9
13
  "test": "jest",
10
14
  "test:watch": "jest --watch",
11
15
  "test:coverage": "jest --coverage"
@@ -15,6 +19,7 @@
15
19
  "jest": "^30.1.3",
16
20
  "jest-fetch-mock": "^3.0.3",
17
21
  "ts-jest": "^29.4.1",
22
+ "tsup": "^8.5.0",
18
23
  "typescript": "^5.9.2",
19
24
  "zod": "^3.25.76"
20
25
  },