@harishmano/react-enterprise-api 1.0.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.mjs ADDED
@@ -0,0 +1,664 @@
1
+ // src/createApiClient.ts
2
+ import axios from "axios";
3
+
4
+ // src/resource.ts
5
+ import {
6
+ useQuery,
7
+ useMutation,
8
+ useQueryClient,
9
+ useInfiniteQuery,
10
+ keepPreviousData
11
+ } from "@tanstack/react-query";
12
+
13
+ // src/utils.ts
14
+ function buildQueryParams(options, defaultParams) {
15
+ var _a;
16
+ const params = { ...defaultParams };
17
+ if (!options) return params;
18
+ if (options.pagination) {
19
+ const { page, pageSize, sortBy, sortOrder } = options.pagination;
20
+ if (page !== void 0) params.page = page;
21
+ if (pageSize !== void 0) params.pageSize = pageSize;
22
+ if (sortBy) params.sortBy = sortBy;
23
+ if (sortOrder) params.sortOrder = sortOrder;
24
+ }
25
+ if (options.search) {
26
+ params.search = options.search;
27
+ if ((_a = options.searchFields) == null ? void 0 : _a.length) {
28
+ params.searchFields = options.searchFields.join(",");
29
+ }
30
+ }
31
+ if (options.filters) {
32
+ if (Array.isArray(options.filters)) {
33
+ params.filters = JSON.stringify(options.filters);
34
+ } else {
35
+ Object.assign(params, options.filters);
36
+ }
37
+ }
38
+ return params;
39
+ }
40
+ function buildQueryKey(resource, options) {
41
+ const key = [resource];
42
+ if (options == null ? void 0 : options.pagination) key.push({ pagination: options.pagination });
43
+ if (options == null ? void 0 : options.search) key.push({ search: options.search });
44
+ if (options == null ? void 0 : options.filters) key.push({ filters: serializeFilters(options.filters) });
45
+ return key;
46
+ }
47
+ function serializeFilters(filters) {
48
+ if (!filters) return "";
49
+ return JSON.stringify(filters);
50
+ }
51
+ function triggerBrowserDownload(blob, filename, mimeType) {
52
+ const resolvedBlob = mimeType && blob.type !== mimeType ? new Blob([blob], { type: mimeType }) : blob;
53
+ const url = URL.createObjectURL(resolvedBlob);
54
+ const a = document.createElement("a");
55
+ a.href = url;
56
+ a.download = filename;
57
+ document.body.appendChild(a);
58
+ a.click();
59
+ document.body.removeChild(a);
60
+ URL.revokeObjectURL(url);
61
+ }
62
+ function sleep(ms) {
63
+ return new Promise((resolve) => setTimeout(resolve, ms));
64
+ }
65
+
66
+ // src/resource.ts
67
+ function createResource(client, name, resourceOptions = {}) {
68
+ const {
69
+ path = `/${name}`,
70
+ defaultParams,
71
+ transform,
72
+ staleTime: defaultStaleTime = 1e3 * 60,
73
+ optimistic = false
74
+ } = resourceOptions;
75
+ function applyTransform(data) {
76
+ return transform ? transform(data) : data;
77
+ }
78
+ function useList(options) {
79
+ var _a;
80
+ const params = buildQueryParams(options, defaultParams);
81
+ const queryKey = buildQueryKey(name, options);
82
+ return useQuery({
83
+ queryKey,
84
+ queryFn: async ({ signal }) => {
85
+ const res = await client.get(path, {
86
+ params,
87
+ signal,
88
+ ...options == null ? void 0 : options.axiosConfig
89
+ });
90
+ return applyTransform(res.data);
91
+ },
92
+ staleTime: (_a = options == null ? void 0 : options.staleTime) != null ? _a : defaultStaleTime,
93
+ placeholderData: keepPreviousData,
94
+ enabled: options == null ? void 0 : options.enabled,
95
+ refetchInterval: options == null ? void 0 : options.refetchInterval
96
+ });
97
+ }
98
+ function useGet(id, options) {
99
+ var _a, _b;
100
+ return useQuery({
101
+ queryKey: [name, id],
102
+ queryFn: async ({ signal }) => {
103
+ const res = await client.get(`${path}/${id}`, {
104
+ params: buildQueryParams(options, defaultParams),
105
+ signal,
106
+ ...options == null ? void 0 : options.axiosConfig
107
+ });
108
+ return applyTransform(res.data);
109
+ },
110
+ staleTime: (_a = options == null ? void 0 : options.staleTime) != null ? _a : defaultStaleTime,
111
+ enabled: (_b = options == null ? void 0 : options.enabled) != null ? _b : !!id,
112
+ refetchInterval: options == null ? void 0 : options.refetchInterval
113
+ });
114
+ }
115
+ function usePaginatedList(pagination, options) {
116
+ var _a;
117
+ const mergedOptions = { ...options, pagination };
118
+ const params = buildQueryParams(mergedOptions, defaultParams);
119
+ const queryKey = buildQueryKey(`${name}/paginated`, mergedOptions);
120
+ return useQuery({
121
+ queryKey,
122
+ queryFn: async ({ signal }) => {
123
+ const res = await client.get(path, {
124
+ params,
125
+ signal,
126
+ ...options == null ? void 0 : options.axiosConfig
127
+ });
128
+ return applyTransform(res.data);
129
+ },
130
+ staleTime: (_a = options == null ? void 0 : options.staleTime) != null ? _a : defaultStaleTime,
131
+ placeholderData: keepPreviousData,
132
+ enabled: options == null ? void 0 : options.enabled
133
+ });
134
+ }
135
+ function useInfiniteList(options) {
136
+ var _a;
137
+ const baseParams = buildQueryParams(options, defaultParams);
138
+ return useInfiniteQuery({
139
+ queryKey: [...buildQueryKey(name, options), "infinite"],
140
+ queryFn: async ({ pageParam = 1, signal }) => {
141
+ var _a2;
142
+ const res = await client.get(path, {
143
+ params: { ...baseParams, page: pageParam, pageSize: (_a2 = options == null ? void 0 : options.pageSize) != null ? _a2 : 20 },
144
+ signal,
145
+ ...options == null ? void 0 : options.axiosConfig
146
+ });
147
+ return applyTransform(res.data);
148
+ },
149
+ initialPageParam: 1,
150
+ getNextPageParam: (lastPage, allPages) => Array.isArray(lastPage) && lastPage.length > 0 ? allPages.length + 1 : void 0,
151
+ staleTime: (_a = options == null ? void 0 : options.staleTime) != null ? _a : defaultStaleTime,
152
+ enabled: options == null ? void 0 : options.enabled
153
+ });
154
+ }
155
+ function useCursorList(pagination, options) {
156
+ var _a;
157
+ const baseParams = buildQueryParams(options, defaultParams);
158
+ return useInfiniteQuery({
159
+ queryKey: [...buildQueryKey(name, options), "cursor", pagination],
160
+ queryFn: async ({ pageParam, signal }) => {
161
+ var _a2;
162
+ const res = await client.get(path, {
163
+ params: {
164
+ ...baseParams,
165
+ cursor: pageParam != null ? pageParam : pagination == null ? void 0 : pagination.cursor,
166
+ pageSize: (_a2 = pagination == null ? void 0 : pagination.pageSize) != null ? _a2 : 20,
167
+ sortBy: pagination == null ? void 0 : pagination.sortBy,
168
+ sortOrder: pagination == null ? void 0 : pagination.sortOrder
169
+ },
170
+ signal,
171
+ ...options == null ? void 0 : options.axiosConfig
172
+ });
173
+ return applyTransform(res.data);
174
+ },
175
+ initialPageParam: null,
176
+ getNextPageParam: (lastPage) => lastPage.hasMore ? lastPage.nextCursor : void 0,
177
+ staleTime: (_a = options == null ? void 0 : options.staleTime) != null ? _a : defaultStaleTime,
178
+ enabled: options == null ? void 0 : options.enabled
179
+ });
180
+ }
181
+ function useCreate(mutationOptions) {
182
+ const qc = useQueryClient();
183
+ return useMutation({
184
+ mutationFn: async (data) => {
185
+ const res = await client.post(path, data);
186
+ return applyTransform(res.data);
187
+ },
188
+ onMutate: optimistic ? async (newItem) => {
189
+ await qc.cancelQueries({ queryKey: [name] });
190
+ const prev = qc.getQueryData([name]);
191
+ qc.setQueryData([name], (old = []) => [
192
+ ...old,
193
+ newItem
194
+ ]);
195
+ return { prev };
196
+ } : void 0,
197
+ onError: (error, variables, context) => {
198
+ var _a;
199
+ const ctx = context;
200
+ if (optimistic && (ctx == null ? void 0 : ctx.prev)) qc.setQueryData([name], ctx.prev);
201
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onError) == null ? void 0 : _a.call(mutationOptions, error, variables);
202
+ },
203
+ onSuccess: (data, variables) => {
204
+ var _a;
205
+ qc.invalidateQueries({ queryKey: [name] });
206
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onSuccess) == null ? void 0 : _a.call(mutationOptions, data, variables);
207
+ },
208
+ onSettled: mutationOptions == null ? void 0 : mutationOptions.onSettled
209
+ });
210
+ }
211
+ function useUpdate(mutationOptions) {
212
+ const qc = useQueryClient();
213
+ return useMutation({
214
+ mutationFn: async ({ id, data }) => {
215
+ const res = await client.put(`${path}/${id}`, data);
216
+ return applyTransform(res.data);
217
+ },
218
+ onMutate: optimistic ? async ({ id, data }) => {
219
+ await qc.cancelQueries({ queryKey: [name, id] });
220
+ const prev = qc.getQueryData([name, id]);
221
+ qc.setQueryData([name, id], (old) => ({
222
+ ...old,
223
+ ...data
224
+ }));
225
+ return { prev };
226
+ } : void 0,
227
+ onError: (error, variables, context) => {
228
+ var _a;
229
+ const ctx = context;
230
+ if (optimistic && (ctx == null ? void 0 : ctx.prev)) qc.setQueryData([name, variables.id], ctx.prev);
231
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onError) == null ? void 0 : _a.call(mutationOptions, error, variables);
232
+ },
233
+ onSuccess: (data, variables) => {
234
+ var _a;
235
+ qc.invalidateQueries({ queryKey: [name] });
236
+ qc.invalidateQueries({ queryKey: [name, variables.id] });
237
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onSuccess) == null ? void 0 : _a.call(mutationOptions, data, variables);
238
+ },
239
+ onSettled: mutationOptions == null ? void 0 : mutationOptions.onSettled
240
+ });
241
+ }
242
+ function usePatch(mutationOptions) {
243
+ const qc = useQueryClient();
244
+ return useMutation({
245
+ mutationFn: async ({ id, data }) => {
246
+ const res = await client.patch(`${path}/${id}`, data);
247
+ return applyTransform(res.data);
248
+ },
249
+ onMutate: optimistic ? async ({ id, data }) => {
250
+ await qc.cancelQueries({ queryKey: [name, id] });
251
+ const prev = qc.getQueryData([name, id]);
252
+ qc.setQueryData([name, id], (old) => ({
253
+ ...old,
254
+ ...data
255
+ }));
256
+ return { prev };
257
+ } : void 0,
258
+ onError: (error, variables, context) => {
259
+ var _a;
260
+ const ctx = context;
261
+ if (optimistic && (ctx == null ? void 0 : ctx.prev)) qc.setQueryData([name, variables.id], ctx.prev);
262
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onError) == null ? void 0 : _a.call(mutationOptions, error, variables);
263
+ },
264
+ onSuccess: (data, variables) => {
265
+ var _a;
266
+ qc.invalidateQueries({ queryKey: [name] });
267
+ qc.invalidateQueries({ queryKey: [name, variables.id] });
268
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onSuccess) == null ? void 0 : _a.call(mutationOptions, data, variables);
269
+ },
270
+ onSettled: mutationOptions == null ? void 0 : mutationOptions.onSettled
271
+ });
272
+ }
273
+ function useDelete(mutationOptions) {
274
+ const qc = useQueryClient();
275
+ return useMutation({
276
+ mutationFn: async (id) => {
277
+ await client.delete(`${path}/${id}`);
278
+ },
279
+ onMutate: optimistic ? async (id) => {
280
+ await qc.cancelQueries({ queryKey: [name] });
281
+ const prev = qc.getQueryData([name]);
282
+ qc.setQueryData(
283
+ [name],
284
+ (old = []) => old.filter((item) => item.id !== id)
285
+ );
286
+ return { prev };
287
+ } : void 0,
288
+ onError: (error, id, context) => {
289
+ var _a;
290
+ const ctx = context;
291
+ if (optimistic && (ctx == null ? void 0 : ctx.prev)) qc.setQueryData([name], ctx.prev);
292
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onError) == null ? void 0 : _a.call(mutationOptions, error, id);
293
+ },
294
+ onSuccess: (_, id) => {
295
+ var _a;
296
+ qc.invalidateQueries({ queryKey: [name] });
297
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onSuccess) == null ? void 0 : _a.call(mutationOptions, void 0, id);
298
+ },
299
+ onSettled: mutationOptions == null ? void 0 : mutationOptions.onSettled
300
+ });
301
+ }
302
+ function useBulkDelete(mutationOptions) {
303
+ const qc = useQueryClient();
304
+ return useMutation({
305
+ mutationFn: async (ids) => {
306
+ await client.delete(path, { data: { ids } });
307
+ },
308
+ onSuccess: (_, ids) => {
309
+ var _a;
310
+ qc.invalidateQueries({ queryKey: [name] });
311
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onSuccess) == null ? void 0 : _a.call(mutationOptions, void 0, ids);
312
+ },
313
+ onError: mutationOptions == null ? void 0 : mutationOptions.onError
314
+ });
315
+ }
316
+ function useBulkUpdate(mutationOptions) {
317
+ const qc = useQueryClient();
318
+ return useMutation({
319
+ mutationFn: async ({ ids, data }) => {
320
+ const res = await client.patch(path, { ids, ...data });
321
+ return applyTransform(res.data);
322
+ },
323
+ onSuccess: (data, variables) => {
324
+ var _a;
325
+ qc.invalidateQueries({ queryKey: [name] });
326
+ (_a = mutationOptions == null ? void 0 : mutationOptions.onSuccess) == null ? void 0 : _a.call(mutationOptions, data, variables);
327
+ },
328
+ onError: mutationOptions == null ? void 0 : mutationOptions.onError
329
+ });
330
+ }
331
+ function useUpload(uploadOptions) {
332
+ const qc = useQueryClient();
333
+ return useMutation({
334
+ mutationFn: async ({ id, file, extraFields }) => {
335
+ var _a;
336
+ const formData = new FormData();
337
+ const fieldName = (_a = uploadOptions == null ? void 0 : uploadOptions.fieldName) != null ? _a : "file";
338
+ if (Array.isArray(file)) {
339
+ file.forEach((f) => formData.append(fieldName, f));
340
+ } else {
341
+ formData.append(fieldName, file);
342
+ }
343
+ const mergedExtra = { ...uploadOptions == null ? void 0 : uploadOptions.extraFields, ...extraFields };
344
+ Object.entries(mergedExtra).forEach(([k, v]) => formData.append(k, v));
345
+ const url = id ? `${path}/${id}/upload` : `${path}/upload`;
346
+ const res = await client.post(url, formData, {
347
+ headers: { "Content-Type": "multipart/form-data" },
348
+ onUploadProgress: (e) => {
349
+ if ((uploadOptions == null ? void 0 : uploadOptions.onProgress) && e.total) {
350
+ uploadOptions.onProgress(Math.round(e.loaded * 100 / e.total));
351
+ }
352
+ }
353
+ });
354
+ return applyTransform(res.data);
355
+ },
356
+ onSuccess: () => qc.invalidateQueries({ queryKey: [name] })
357
+ });
358
+ }
359
+ function useFormData(opts) {
360
+ var _a, _b;
361
+ const qc = useQueryClient();
362
+ const method = (_a = opts == null ? void 0 : opts.method) != null ? _a : "post";
363
+ const url = (opts == null ? void 0 : opts.id) ? `${path}/${opts.id}` : path;
364
+ return useMutation({
365
+ mutationFn: async (formData) => {
366
+ const res = await client[method](url, formData, {
367
+ headers: { "Content-Type": "multipart/form-data" },
368
+ onUploadProgress: (e) => {
369
+ if ((opts == null ? void 0 : opts.onProgress) && e.total) {
370
+ opts.onProgress(Math.round(e.loaded * 100 / e.total));
371
+ }
372
+ }
373
+ });
374
+ return applyTransform(res.data);
375
+ },
376
+ onSuccess: (data, variables) => {
377
+ var _a2, _b2;
378
+ qc.invalidateQueries({ queryKey: [name] });
379
+ (_b2 = (_a2 = opts == null ? void 0 : opts.mutationOptions) == null ? void 0 : _a2.onSuccess) == null ? void 0 : _b2.call(_a2, data, variables);
380
+ },
381
+ onError: (_b = opts == null ? void 0 : opts.mutationOptions) == null ? void 0 : _b.onError
382
+ });
383
+ }
384
+ function useDownload(downloadOptions) {
385
+ return useMutation({
386
+ mutationFn: async ({ id, params }) => {
387
+ var _a, _b;
388
+ const url = id ? `${path}/${id}/download` : `${path}/download`;
389
+ const res = await client.get(url, {
390
+ params,
391
+ responseType: "blob",
392
+ onDownloadProgress: (e) => {
393
+ if ((downloadOptions == null ? void 0 : downloadOptions.onProgress) && e.total) {
394
+ downloadOptions.onProgress(Math.round(e.loaded * 100 / e.total));
395
+ }
396
+ }
397
+ });
398
+ if ((downloadOptions == null ? void 0 : downloadOptions.saveAs) !== false) {
399
+ const filename = (_b = (_a = downloadOptions == null ? void 0 : downloadOptions.filename) != null ? _a : extractFilename(res.headers["content-disposition"])) != null ? _b : `${name}-download`;
400
+ triggerBrowserDownload(res.data, filename, downloadOptions == null ? void 0 : downloadOptions.mimeType);
401
+ }
402
+ return res.data;
403
+ }
404
+ });
405
+ }
406
+ function useExport(opts) {
407
+ return useMutation({
408
+ mutationFn: async (queryOptions) => {
409
+ var _a, _b, _c;
410
+ const params = buildQueryParams(queryOptions, defaultParams);
411
+ const res = await client.get(`${path}/export`, {
412
+ params: { ...params, format: (_a = opts == null ? void 0 : opts.format) != null ? _a : "csv" },
413
+ responseType: "blob",
414
+ onDownloadProgress: (e) => {
415
+ if ((opts == null ? void 0 : opts.onProgress) && e.total) {
416
+ opts.onProgress(Math.round(e.loaded * 100 / e.total));
417
+ }
418
+ }
419
+ });
420
+ const fmt = (_b = opts == null ? void 0 : opts.format) != null ? _b : "csv";
421
+ const filename = (_c = opts == null ? void 0 : opts.filename) != null ? _c : `${name}-export.${fmt}`;
422
+ const mimeMap = {
423
+ csv: "text/csv",
424
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
425
+ pdf: "application/pdf"
426
+ };
427
+ triggerBrowserDownload(res.data, filename, mimeMap[fmt]);
428
+ return res.data;
429
+ }
430
+ });
431
+ }
432
+ function useAction(action, opts) {
433
+ var _a, _b;
434
+ const qc = useQueryClient();
435
+ const method = (_a = opts == null ? void 0 : opts.method) != null ? _a : "post";
436
+ const url = (opts == null ? void 0 : opts.id) ? `${path}/${opts.id}/${action}` : `${path}/${action}`;
437
+ return useMutation({
438
+ mutationFn: async (payload) => {
439
+ const res = await client[method](url, payload);
440
+ return applyTransform(res.data);
441
+ },
442
+ onSuccess: (data, variables) => {
443
+ var _a2, _b2;
444
+ if ((opts == null ? void 0 : opts.invalidate) !== false) {
445
+ qc.invalidateQueries({ queryKey: [name] });
446
+ }
447
+ (_b2 = (_a2 = opts == null ? void 0 : opts.mutationOptions) == null ? void 0 : _a2.onSuccess) == null ? void 0 : _b2.call(_a2, data, variables);
448
+ },
449
+ onError: (_b = opts == null ? void 0 : opts.mutationOptions) == null ? void 0 : _b.onError
450
+ });
451
+ }
452
+ function useInvalidate() {
453
+ const qc = useQueryClient();
454
+ return (id) => {
455
+ if (id) {
456
+ qc.invalidateQueries({ queryKey: [name, id] });
457
+ } else {
458
+ qc.invalidateQueries({ queryKey: [name] });
459
+ }
460
+ };
461
+ }
462
+ function usePrefetch() {
463
+ const qc = useQueryClient();
464
+ return (id) => {
465
+ if (id) {
466
+ qc.prefetchQuery({
467
+ queryKey: [name, id],
468
+ queryFn: () => client.get(`${path}/${id}`).then((r) => r.data)
469
+ });
470
+ } else {
471
+ qc.prefetchQuery({
472
+ queryKey: [name],
473
+ queryFn: () => client.get(path).then((r) => r.data)
474
+ });
475
+ }
476
+ };
477
+ }
478
+ function useSetCache() {
479
+ const qc = useQueryClient();
480
+ return (data, id) => {
481
+ if (id) {
482
+ qc.setQueryData([name, id], data);
483
+ } else {
484
+ qc.setQueryData([name], data);
485
+ }
486
+ };
487
+ }
488
+ return {
489
+ // ── Queries ──────────────────────────────────────────────────────────
490
+ /** Full list — with filters, search, sorting, polling */
491
+ useList,
492
+ /** Single item by ID */
493
+ useGet,
494
+ /** Page-number pagination */
495
+ usePaginatedList,
496
+ /** Offset-based infinite scroll */
497
+ useInfiniteList,
498
+ /** Cursor-based infinite scroll (for DB cursor pagination) */
499
+ useCursorList,
500
+ // ── Mutations ─────────────────────────────────────────────────────────
501
+ /** Create — POST /resource */
502
+ useCreate,
503
+ /** Full replace — PUT /resource/:id */
504
+ useUpdate,
505
+ /** Partial update — PATCH /resource/:id */
506
+ usePatch,
507
+ /** Delete — DELETE /resource/:id */
508
+ useDelete,
509
+ /** Delete many — DELETE /resource { ids: [...] } */
510
+ useBulkDelete,
511
+ /** Update many — PATCH /resource { ids: [...], ...fields } */
512
+ useBulkUpdate,
513
+ // ── File Operations ───────────────────────────────────────────────────
514
+ /** Upload file(s) with progress tracking */
515
+ useUpload,
516
+ /** Submit any FormData (mixed files + fields) */
517
+ useFormData,
518
+ /** Download blob file with progress + auto "Save As" */
519
+ useDownload,
520
+ /** Export list to CSV / XLSX / PDF */
521
+ useExport,
522
+ // ── Custom Actions ────────────────────────────────────────────────────
523
+ /** Arbitrary endpoint action (e.g. /resource/:id/approve) */
524
+ useAction,
525
+ // ── Cache Utilities ───────────────────────────────────────────────────
526
+ /** Manually invalidate cache */
527
+ useInvalidate,
528
+ /** Prefetch on hover/navigation */
529
+ usePrefetch,
530
+ /** Manually write data into cache (SSR/seed) */
531
+ useSetCache,
532
+ // ── Meta ──────────────────────────────────────────────────────────────
533
+ path,
534
+ name
535
+ };
536
+ }
537
+ function extractFilename(contentDisposition) {
538
+ if (!contentDisposition) return null;
539
+ const match = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
540
+ return match ? match[1].replace(/['"]/g, "").trim() : null;
541
+ }
542
+
543
+ // src/createApiClient.ts
544
+ function createApiClient(config) {
545
+ const {
546
+ baseURL,
547
+ getToken,
548
+ onTokenRefresh,
549
+ onAuthFailure,
550
+ onError,
551
+ headers = {},
552
+ timeout = 3e4,
553
+ retry = { count: 0, delay: 1e3, statusCodes: [429, 503] }
554
+ } = config;
555
+ const client = axios.create({
556
+ baseURL,
557
+ timeout,
558
+ headers: {
559
+ "Content-Type": "application/json",
560
+ ...headers
561
+ }
562
+ });
563
+ client.interceptors.request.use(async (req) => {
564
+ const token = await (getToken == null ? void 0 : getToken());
565
+ if (token) {
566
+ req.headers.Authorization = `Bearer ${token}`;
567
+ }
568
+ return req;
569
+ });
570
+ let isRefreshing = false;
571
+ let refreshQueue = [];
572
+ function processRefreshQueue(token, error = null) {
573
+ refreshQueue.forEach(({ resolve, reject }) => {
574
+ if (token) resolve(token);
575
+ else reject(error);
576
+ });
577
+ refreshQueue = [];
578
+ }
579
+ client.interceptors.response.use(
580
+ (res) => res,
581
+ async (error) => {
582
+ var _a, _b;
583
+ const originalRequest = error.config;
584
+ if (onError) onError(error);
585
+ if (((_a = error.response) == null ? void 0 : _a.status) === 401 && originalRequest && !originalRequest._retryCount) {
586
+ if (isRefreshing) {
587
+ return new Promise((resolve, reject) => {
588
+ refreshQueue.push({ resolve, reject });
589
+ }).then((token) => {
590
+ originalRequest.headers.Authorization = `Bearer ${token}`;
591
+ return client(originalRequest);
592
+ });
593
+ }
594
+ if (onTokenRefresh) {
595
+ isRefreshing = true;
596
+ try {
597
+ const newToken = await refreshTokenRequest(config);
598
+ onTokenRefresh(newToken);
599
+ processRefreshQueue(newToken);
600
+ isRefreshing = false;
601
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
602
+ return client(originalRequest);
603
+ } catch (refreshError) {
604
+ processRefreshQueue(null, refreshError);
605
+ isRefreshing = false;
606
+ onAuthFailure == null ? void 0 : onAuthFailure();
607
+ return Promise.reject(refreshError);
608
+ }
609
+ } else {
610
+ onAuthFailure == null ? void 0 : onAuthFailure();
611
+ }
612
+ }
613
+ if (originalRequest && shouldRetry(error, retry)) {
614
+ originalRequest._retryCount = ((_b = originalRequest._retryCount) != null ? _b : 0) + 1;
615
+ if (originalRequest._retryCount <= retry.count) {
616
+ const delay = retry.delay !== void 0 ? retry.delay * originalRequest._retryCount : 1e3;
617
+ await sleep(delay);
618
+ return client(originalRequest);
619
+ }
620
+ }
621
+ return Promise.reject(error);
622
+ }
623
+ );
624
+ return {
625
+ /** Access the raw axios instance for custom requests */
626
+ axiosInstance: client,
627
+ /** Create a resource with CRUD hooks */
628
+ resource: (name, options) => createResource(client, name, options),
629
+ /** Raw GET */
630
+ get: (url, axiosConfig) => client.get(url, axiosConfig).then((r) => r.data),
631
+ /** Raw POST */
632
+ post: (url, data, axiosConfig) => client.post(url, data, axiosConfig).then((r) => r.data),
633
+ /** Raw PUT */
634
+ put: (url, data, axiosConfig) => client.put(url, data, axiosConfig).then((r) => r.data),
635
+ /** Raw PATCH */
636
+ patch: (url, data, axiosConfig) => client.patch(url, data, axiosConfig).then((r) => r.data),
637
+ /** Raw DELETE */
638
+ delete: (url, axiosConfig) => client.delete(url, axiosConfig).then((r) => r.data)
639
+ };
640
+ }
641
+ async function refreshTokenRequest(config) {
642
+ var _a, _b, _c, _d;
643
+ const currentToken = await ((_a = config.getToken) == null ? void 0 : _a.call(config));
644
+ const res = await axios.post(
645
+ `${config.baseURL}/auth/refresh`,
646
+ {},
647
+ {
648
+ headers: currentToken ? { Authorization: `Bearer ${currentToken}` } : void 0
649
+ }
650
+ );
651
+ return (_d = (_b = res.data) == null ? void 0 : _b.token) != null ? _d : (_c = res.data) == null ? void 0 : _c.accessToken;
652
+ }
653
+ function shouldRetry(error, retry) {
654
+ if (!retry.count) return false;
655
+ if (!error.response) return true;
656
+ if (retry.statusCodes && retry.statusCodes.length > 0) {
657
+ return retry.statusCodes.includes(error.response.status);
658
+ }
659
+ return false;
660
+ }
661
+ export {
662
+ createApiClient,
663
+ createResource
664
+ };