fetchwire 1.0.0 → 2.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/README.md +46 -49
- package/dist/index.d.mts +6 -5
- package/dist/index.d.ts +6 -5
- package/dist/index.js +7 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
# fetchwire
|
|
2
2
|
|
|
3
|
-
A lightweight, focused API fetching library for React and React Native applications.
|
|
3
|
+
A lightweight, focused API fetching library for **React and React Native** applications.
|
|
4
4
|
|
|
5
5
|
**fetchwire** wraps the native `fetch` API in a global configuration layer. It is designed to make it easy to:
|
|
6
6
|
|
|
7
7
|
- Centralize your API base URL, auth token, and common headers.
|
|
8
|
-
- Handle errors consistently
|
|
8
|
+
- Handle errors consistently.
|
|
9
9
|
|
|
10
10
|
### When to use fetchwire
|
|
11
|
+
|
|
11
12
|
- **React / React Native apps** that:
|
|
12
13
|
- Want a **simple**, centralized way to call HTTP APIs.
|
|
13
14
|
- Prefer plain hooks over a heavier state management or query library.
|
|
14
15
|
- Need basic tag-based invalidation without a full cache layer.
|
|
15
|
-
- Handle errors in a consistent way across screens.
|
|
16
16
|
|
|
17
17
|
### When not to use fetchwire
|
|
18
|
+
|
|
18
19
|
- Consider a more full-featured solution (e.g. TanStack Query / React Query, SWR, RTK Query) if:
|
|
19
20
|
- You need advanced, automatic caching strategies.
|
|
20
21
|
- You need built-in pagination helpers, infinite queries.
|
|
21
22
|
- You need a more powerful data-fetching library and you want to avoid overlap.
|
|
22
23
|
|
|
23
24
|
## Support
|
|
25
|
+
|
|
24
26
|
If you find **fetchwire** helpful and want to support its development, you can buy me a coffee via:
|
|
25
27
|
|
|
26
28
|
[](https://ko-fi.com/doanvinhphu)
|
|
@@ -30,26 +32,15 @@ Your support helps maintain the library and keep it up to date!
|
|
|
30
32
|
|
|
31
33
|
## Features
|
|
32
34
|
|
|
33
|
-
- **Global configuration
|
|
35
|
+
- **Global API fetching configuration `initWire`**
|
|
34
36
|
- Configure `baseUrl`, default headers, and how to read the auth token.
|
|
35
37
|
- Optionally register global interceptors for 401/403/other errors.
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
- **Typed HTTP wrapper with `wireApi`**
|
|
39
|
-
- Thin wrapper around `fetch` that:
|
|
40
|
-
- Appends the endpoint to a global `baseUrl`.
|
|
41
|
-
- Adds auth headers from `getToken`.
|
|
42
|
-
- Merges default and per-request headers.
|
|
43
|
-
- Converts server/network errors into a typed `ApiError`.
|
|
44
|
-
|
|
45
|
-
- **React hooks for requests**
|
|
46
|
-
- **`useFetchFn<T>`** for data fetching
|
|
47
|
-
- **`useMutationFn<T>`** for mutations
|
|
38
|
+
- Converts server/network errors into a typed `ApiError`.
|
|
48
39
|
|
|
49
|
-
- **
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
40
|
+
- **React hooks for data fetching and mutation with tag-based invalidation**
|
|
41
|
+
- **`useFetchFn`** for data fetching
|
|
42
|
+
- **`useMutationFn`** for mutations
|
|
43
|
+
- With a simple, explicit way to refetch related data through tags
|
|
53
44
|
|
|
54
45
|
---
|
|
55
46
|
|
|
@@ -65,7 +56,6 @@ pnpm add fetchwire
|
|
|
65
56
|
|
|
66
57
|
### Peer expectations
|
|
67
58
|
|
|
68
|
-
- React or React Native project using function components and hooks.
|
|
69
59
|
- TypeScript is recommended but not required.
|
|
70
60
|
- For React Native / Expo, make sure the global `fetch` is available (default in modern RN/Expo).
|
|
71
61
|
|
|
@@ -123,7 +113,7 @@ setupWire();
|
|
|
123
113
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
|
124
114
|
<React.StrictMode>
|
|
125
115
|
<App />
|
|
126
|
-
</React.StrictMode
|
|
116
|
+
</React.StrictMode>
|
|
127
117
|
);
|
|
128
118
|
```
|
|
129
119
|
|
|
@@ -177,18 +167,18 @@ You can organize similar helpers for users, invoices, organizations, uploads, et
|
|
|
177
167
|
|
|
178
168
|
### 2. Fetch data with `useFetchFn`
|
|
179
169
|
|
|
180
|
-
`useFetchFn
|
|
170
|
+
`useFetchFn` is a generic hook that manages state for running an async function returning `HttpResponse<T>`, where `T` is **inferred** from your API helper.
|
|
181
171
|
|
|
182
172
|
**Key ideas:**
|
|
183
173
|
|
|
184
|
-
- You
|
|
185
|
-
-
|
|
174
|
+
- You pass a **pre-typed API helper** (e.g. `getTodosApi`) into the hook once.
|
|
175
|
+
- The hook infers the data type `T` from that helper, so you rarely need to write `<T>` in components.
|
|
186
176
|
- The hook tracks:
|
|
187
177
|
- `data: T | null`
|
|
188
178
|
- `isLoading: boolean`
|
|
189
179
|
- `isRefreshing: boolean`
|
|
190
180
|
- `error: ApiError | null`
|
|
191
|
-
- `executeFetchFn(
|
|
181
|
+
- `executeFetchFn()`
|
|
192
182
|
- `refreshFetchFn()`
|
|
193
183
|
|
|
194
184
|
Example: loading and refreshing a todo list in a React component:
|
|
@@ -207,12 +197,12 @@ export function TodoList() {
|
|
|
207
197
|
error,
|
|
208
198
|
executeFetchFn: fetchTodos,
|
|
209
199
|
refreshFetchFn: refreshTodos,
|
|
210
|
-
} = useFetchFn
|
|
200
|
+
} = useFetchFn(getTodosApi, {
|
|
211
201
|
tags: ['todos'],
|
|
212
202
|
});
|
|
213
203
|
|
|
214
204
|
useEffect(() => {
|
|
215
|
-
fetchTodos(
|
|
205
|
+
fetchTodos();
|
|
216
206
|
}, [fetchTodos]);
|
|
217
207
|
|
|
218
208
|
if (isLoading) return <div>Loading...</div>;
|
|
@@ -240,7 +230,7 @@ export function TodoList() {
|
|
|
240
230
|
|
|
241
231
|
### 3. Mutate data with `useMutationFn`
|
|
242
232
|
|
|
243
|
-
`useMutationFn
|
|
233
|
+
`useMutationFn` is a hook for mutations (create/update/delete). It:
|
|
244
234
|
|
|
245
235
|
- Tracks `data` and `isMutating`.
|
|
246
236
|
- Lets you invalidate **tags** after a successful mutation.
|
|
@@ -254,9 +244,11 @@ const {
|
|
|
254
244
|
isMutating,
|
|
255
245
|
executeMutationFn,
|
|
256
246
|
reset,
|
|
257
|
-
} = useMutationFn
|
|
247
|
+
} = useMutationFn(mutationFn, { invalidatesTags?: string[] });
|
|
258
248
|
```
|
|
259
249
|
|
|
250
|
+
`T` is inferred from the `mutationFn` return type (`Promise<HttpResponse<T>>`), so components usually do not need to specify generics.
|
|
251
|
+
|
|
260
252
|
Example: creating and toggling todos with `useMutationFn`:
|
|
261
253
|
|
|
262
254
|
```tsx
|
|
@@ -276,36 +268,42 @@ export function TodoActions() {
|
|
|
276
268
|
const {
|
|
277
269
|
isMutating: isCreating,
|
|
278
270
|
executeMutationFn: createTodo,
|
|
279
|
-
} = useMutationFn
|
|
271
|
+
} = useMutationFn(() => createTodoApi({ title }), {
|
|
280
272
|
invalidatesTags: ['todos'],
|
|
281
273
|
});
|
|
282
274
|
|
|
283
275
|
const {
|
|
284
276
|
isMutating: isToggling,
|
|
285
277
|
executeMutationFn: toggleTodo,
|
|
286
|
-
} = useMutationFn
|
|
287
|
-
|
|
288
|
-
|
|
278
|
+
} = useMutationFn(
|
|
279
|
+
(id: string) => toggleTodoApi(id),
|
|
280
|
+
{
|
|
281
|
+
invalidatesTags: ['todos'],
|
|
282
|
+
}
|
|
283
|
+
);
|
|
289
284
|
|
|
290
285
|
const {
|
|
291
286
|
isMutating: isDeleting,
|
|
292
287
|
executeMutationFn: deleteTodo,
|
|
293
|
-
} = useMutationFn
|
|
294
|
-
|
|
295
|
-
|
|
288
|
+
} = useMutationFn(
|
|
289
|
+
(id: string) => deleteTodoApi(id),
|
|
290
|
+
{
|
|
291
|
+
invalidatesTags: ['todos'],
|
|
292
|
+
}
|
|
293
|
+
);
|
|
296
294
|
|
|
297
295
|
const handleCreate = (e: FormEvent) => {
|
|
298
296
|
e.preventDefault();
|
|
299
297
|
if (!title.trim()) return;
|
|
300
298
|
|
|
301
|
-
createTodo(
|
|
299
|
+
createTodo({
|
|
302
300
|
onSuccess: () => setTitle(''),
|
|
303
301
|
});
|
|
304
302
|
};
|
|
305
303
|
|
|
306
304
|
// Example usage of toggleTodo and deleteTodo in your UI:
|
|
307
|
-
// toggleTodo(() =>
|
|
308
|
-
// deleteTodo(() =>
|
|
305
|
+
// toggleTodo({ onSuccess: () => ..., onError: (error) => ... });
|
|
306
|
+
// deleteTodo({ onSuccess: () => ..., onError: (error) => ... });
|
|
309
307
|
|
|
310
308
|
return (
|
|
311
309
|
<form onSubmit={handleCreate}>
|
|
@@ -328,8 +326,8 @@ export function TodoActions() {
|
|
|
328
326
|
|
|
329
327
|
Tags provide a simple way to coordinate refetches across your app:
|
|
330
328
|
|
|
331
|
-
- `useFetchFn({ tags: [...] })` subscribes the hook to one or more **tags**.
|
|
332
|
-
- `useMutationFn({ invalidatesTags: [...] })` emits those tags after a **successful** mutation.
|
|
329
|
+
- `useFetchFn(fetchFn, { tags: [...] })` subscribes the hook to one or more **tags**.
|
|
330
|
+
- `useMutationFn(mutationFn, { invalidatesTags: [...] })` emits those tags after a **successful** mutation.
|
|
333
331
|
- When a tag is emitted, all subscribed fetch hooks will automatically **call `refreshFetchFn`**.
|
|
334
332
|
|
|
335
333
|
This pattern keeps your code explicit and small, without introducing a full query cache library.
|
|
@@ -407,7 +405,7 @@ You can also read `error` directly from `useFetchFn` state if you want to render
|
|
|
407
405
|
|
|
408
406
|
---
|
|
409
407
|
|
|
410
|
-
##
|
|
408
|
+
## API Reference
|
|
411
409
|
|
|
412
410
|
### `initWire(config)`
|
|
413
411
|
|
|
@@ -464,14 +462,12 @@ function getWireConfig(): WireConfig;
|
|
|
464
462
|
|
|
465
463
|
---
|
|
466
464
|
|
|
467
|
-
## API Reference
|
|
468
|
-
|
|
469
465
|
### `wireApi<T>(endpoint, options?)`
|
|
470
466
|
|
|
471
467
|
```ts
|
|
472
468
|
async function wireApi<T>(
|
|
473
469
|
endpoint: string,
|
|
474
|
-
options?: RequestInit & { headers?: Record<string, string> }
|
|
470
|
+
options?: RequestInit & { headers?: Record<string, string> }
|
|
475
471
|
): Promise<HttpResponse<T>>;
|
|
476
472
|
```
|
|
477
473
|
|
|
@@ -502,7 +498,9 @@ function useFetchFn<T>(options?: FetchOptions): {
|
|
|
502
498
|
isLoading: boolean;
|
|
503
499
|
isRefreshing: boolean;
|
|
504
500
|
error: ApiError | null;
|
|
505
|
-
executeFetchFn: (
|
|
501
|
+
executeFetchFn: (
|
|
502
|
+
fetchFn: () => Promise<{ data: T }>
|
|
503
|
+
) => Promise<{ data: T } | null>;
|
|
506
504
|
refreshFetchFn: () => Promise<{ data: T } | null> | null;
|
|
507
505
|
};
|
|
508
506
|
```
|
|
@@ -534,7 +532,7 @@ function useMutationFn<T>(options?: MutationOptions): {
|
|
|
534
532
|
isMutating: boolean;
|
|
535
533
|
executeMutationFn: (
|
|
536
534
|
mutationFn: () => Promise<{ data: T }>,
|
|
537
|
-
executeOptions?: ExecuteOptions<T
|
|
535
|
+
executeOptions?: ExecuteOptions<T>
|
|
538
536
|
) => Promise<{ data: T } | null>;
|
|
539
537
|
reset: () => void;
|
|
540
538
|
};
|
|
@@ -565,4 +563,3 @@ function useMutationFn<T>(options?: MutationOptions): {
|
|
|
565
563
|
Copyright (c) Doanvinhphu
|
|
566
564
|
|
|
567
565
|
See the `LICENSE` file for details (or include the standard MIT text directly in your repository).
|
|
568
|
-
|
package/dist/index.d.mts
CHANGED
|
@@ -148,9 +148,9 @@ declare function wireApi<T>(endpoint: string, options?: RequestInit): Promise<Ht
|
|
|
148
148
|
* @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.
|
|
149
149
|
* @returns The state of the fetch and the fetch function.
|
|
150
150
|
*/
|
|
151
|
-
declare function useFetchFn<T>(options?: FetchOptions): {
|
|
152
|
-
executeFetchFn: (
|
|
153
|
-
refreshFetchFn: () => Promise<HttpResponse<T> | null
|
|
151
|
+
declare function useFetchFn<T>(fetchFn: () => Promise<HttpResponse<T>>, options?: FetchOptions): {
|
|
152
|
+
executeFetchFn: () => Promise<HttpResponse<T> | null>;
|
|
153
|
+
refreshFetchFn: () => Promise<HttpResponse<T> | null>;
|
|
154
154
|
data: T | null;
|
|
155
155
|
isLoading: boolean;
|
|
156
156
|
isRefreshing: boolean;
|
|
@@ -159,11 +159,12 @@ declare function useFetchFn<T>(options?: FetchOptions): {
|
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
161
|
* A hook for executing a mutation function and managing the state of the mutation.
|
|
162
|
+
* @param mutationFn - The mutation function to execute.
|
|
162
163
|
* @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.
|
|
163
164
|
* @returns The state of the mutation and the mutation function.
|
|
164
165
|
*/
|
|
165
|
-
declare function useMutationFn<T>(options?: MutationOptions): {
|
|
166
|
-
executeMutationFn: (
|
|
166
|
+
declare function useMutationFn<T>(mutationFn: () => Promise<HttpResponse<T>>, options?: MutationOptions): {
|
|
167
|
+
executeMutationFn: (executeOptions?: ExecuteMutationOptions<T>) => Promise<HttpResponse<T> | null>;
|
|
167
168
|
reset: () => void;
|
|
168
169
|
data: T | null;
|
|
169
170
|
isMutating: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -148,9 +148,9 @@ declare function wireApi<T>(endpoint: string, options?: RequestInit): Promise<Ht
|
|
|
148
148
|
* @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.
|
|
149
149
|
* @returns The state of the fetch and the fetch function.
|
|
150
150
|
*/
|
|
151
|
-
declare function useFetchFn<T>(options?: FetchOptions): {
|
|
152
|
-
executeFetchFn: (
|
|
153
|
-
refreshFetchFn: () => Promise<HttpResponse<T> | null
|
|
151
|
+
declare function useFetchFn<T>(fetchFn: () => Promise<HttpResponse<T>>, options?: FetchOptions): {
|
|
152
|
+
executeFetchFn: () => Promise<HttpResponse<T> | null>;
|
|
153
|
+
refreshFetchFn: () => Promise<HttpResponse<T> | null>;
|
|
154
154
|
data: T | null;
|
|
155
155
|
isLoading: boolean;
|
|
156
156
|
isRefreshing: boolean;
|
|
@@ -159,11 +159,12 @@ declare function useFetchFn<T>(options?: FetchOptions): {
|
|
|
159
159
|
|
|
160
160
|
/**
|
|
161
161
|
* A hook for executing a mutation function and managing the state of the mutation.
|
|
162
|
+
* @param mutationFn - The mutation function to execute.
|
|
162
163
|
* @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.
|
|
163
164
|
* @returns The state of the mutation and the mutation function.
|
|
164
165
|
*/
|
|
165
|
-
declare function useMutationFn<T>(options?: MutationOptions): {
|
|
166
|
-
executeMutationFn: (
|
|
166
|
+
declare function useMutationFn<T>(mutationFn: () => Promise<HttpResponse<T>>, options?: MutationOptions): {
|
|
167
|
+
executeMutationFn: (executeOptions?: ExecuteMutationOptions<T>) => Promise<HttpResponse<T> | null>;
|
|
167
168
|
reset: () => void;
|
|
168
169
|
data: T | null;
|
|
169
170
|
isMutating: boolean;
|
package/dist/index.js
CHANGED
|
@@ -142,7 +142,7 @@ var EventEmitter = class {
|
|
|
142
142
|
var eventEmitter = new EventEmitter();
|
|
143
143
|
|
|
144
144
|
// src/hook/use-fetch-fn.ts
|
|
145
|
-
function useFetchFn(options) {
|
|
145
|
+
function useFetchFn(fetchFn, options) {
|
|
146
146
|
const [state, setState] = (0, import_react.useState)({
|
|
147
147
|
data: null,
|
|
148
148
|
isLoading: false,
|
|
@@ -158,7 +158,7 @@ function useFetchFn(options) {
|
|
|
158
158
|
};
|
|
159
159
|
}, []);
|
|
160
160
|
const execute = (0, import_react.useCallback)(
|
|
161
|
-
async (
|
|
161
|
+
async (execOptions) => {
|
|
162
162
|
lastFetchFn.current = fetchFn;
|
|
163
163
|
setState((prev) => ({
|
|
164
164
|
...prev,
|
|
@@ -193,17 +193,10 @@ function useFetchFn(options) {
|
|
|
193
193
|
[]
|
|
194
194
|
);
|
|
195
195
|
const executeFetchFn = (0, import_react.useCallback)(
|
|
196
|
-
(
|
|
197
|
-
return execute(fetchFn, { isRefresh: false });
|
|
198
|
-
},
|
|
196
|
+
() => execute({ isRefresh: false }),
|
|
199
197
|
[execute]
|
|
200
198
|
);
|
|
201
|
-
const refreshFetchFn = (0, import_react.useCallback)(() => {
|
|
202
|
-
if (lastFetchFn.current) {
|
|
203
|
-
return execute(lastFetchFn.current, { isRefresh: true });
|
|
204
|
-
}
|
|
205
|
-
return null;
|
|
206
|
-
}, [execute]);
|
|
199
|
+
const refreshFetchFn = (0, import_react.useCallback)(() => execute({ isRefresh: true }), [execute]);
|
|
207
200
|
(0, import_react.useEffect)(() => {
|
|
208
201
|
if (!options?.tags || options.tags.length === 0) return;
|
|
209
202
|
const subscriptions = options.tags.map(
|
|
@@ -218,7 +211,7 @@ function useFetchFn(options) {
|
|
|
218
211
|
|
|
219
212
|
// src/hook/use-mutation-fn.ts
|
|
220
213
|
var import_react2 = require("react");
|
|
221
|
-
function useMutationFn(options) {
|
|
214
|
+
function useMutationFn(mutationFn, options) {
|
|
222
215
|
const [state, setState] = (0, import_react2.useState)({
|
|
223
216
|
data: null,
|
|
224
217
|
isMutating: false
|
|
@@ -231,7 +224,7 @@ function useMutationFn(options) {
|
|
|
231
224
|
};
|
|
232
225
|
}, []);
|
|
233
226
|
const executeMutationFn = (0, import_react2.useCallback)(
|
|
234
|
-
async (
|
|
227
|
+
async (executeOptions) => {
|
|
235
228
|
setState((prev) => ({ ...prev, isMutating: true }));
|
|
236
229
|
try {
|
|
237
230
|
const response = await mutationFn();
|
|
@@ -259,7 +252,7 @@ function useMutationFn(options) {
|
|
|
259
252
|
return null;
|
|
260
253
|
}
|
|
261
254
|
},
|
|
262
|
-
[options?.invalidatesTags]
|
|
255
|
+
[mutationFn, options?.invalidatesTags]
|
|
263
256
|
);
|
|
264
257
|
const reset = (0, import_react2.useCallback)(() => {
|
|
265
258
|
setState({ data: null, isMutating: false });
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/util/api-error.ts","../src/core/config.ts","../src/core/wire.ts","../src/hook/use-fetch-fn.ts","../src/core/event-emitter.ts","../src/hook/use-mutation-fn.ts"],"sourcesContent":["export * from './interface';\nexport * from './util/api-error';\nexport * from './core/config';\nexport * from './core/wire';\nexport * from './hook/use-fetch-fn';\nexport * from './hook/use-mutation-fn';\n","export class ApiError extends Error {\n public errorCode?: string;\n public statusCode?: number;\n\n constructor(message: string, errorCode?: string, statusCode?: number) {\n super(message);\n this.name = 'ApiError';\n this.errorCode = errorCode;\n this.statusCode = statusCode;\n }\n}","import { WireConfig } from '../interface';\n\nlet globalWireConfig: WireConfig | null = null;\n\n/**\n * Initializes the library with mandatory configurations.\n * Must be executed at the application entry point before any API calls.\n * @param config - The required configuration object including baseUrl and getToken.\n */\nexport const initWire = (config: WireConfig): void => {\n globalWireConfig = {\n ...config,\n headers: config.headers || {},\n };\n};\n\n/**\n * Updates the existing configuration.\n * Merges new headers with existing ones and overrides other provided fields.\n * @param config - A partial configuration object to update.\n */\nexport const updateWireConfig = (config: Partial<WireConfig>): void => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n\n globalWireConfig = {\n ...globalWireConfig,\n ...config,\n headers: {\n ...globalWireConfig.headers,\n ...config.headers,\n },\n };\n};\n\n/**\n * Retrieves the current global configuration state.\n * @throws Error if the configuration state is null.\n * @returns The validated WireConfig object.\n */\nexport const getWireConfig = (): WireConfig => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n return globalWireConfig;\n};","import { HttpResponse } from '../interface';\nimport { ApiError } from '../util/api-error';\nimport { getWireConfig } from './config';\n\n/**\n * Sends an API request and returns the response.\n * @param endpoint - The API endpoint to call. Example: '/api/v1/users'.\n * @param options - The request options is a RequestInit object.\n */\nexport async function wireApi<T>(\n endpoint: string,\n options: RequestInit = {}\n): Promise<HttpResponse<T>> {\n const config = getWireConfig();\n const url = `${config.baseUrl}${endpoint}`;\n const accessToken = await config.getToken();\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),\n ...config.headers,\n ...options.headers,\n };\n\n try {\n const response = await fetch(url, { ...options, headers });\n\n if (!response.ok) {\n let errorData;\n try {\n errorData = await response.json();\n } catch {\n errorData = { message: 'Unknown server error', error: 'UNKNOWN' };\n }\n\n const apiError = new ApiError(\n errorData.message,\n errorData.error,\n response.status\n );\n\n // Resolve effective status-code mappings with default values\n const unauthorizedStatusCodes =\n config.unauthorizedStatusCodes && config.unauthorizedStatusCodes.length > 0\n ? config.unauthorizedStatusCodes\n : [401];\n\n const forbiddenStatusCodes =\n config.forbiddenStatusCodes && config.forbiddenStatusCodes.length > 0\n ? config.forbiddenStatusCodes\n : [403];\n\n // Trigger interceptors based on configured status codes\n if (\n config.interceptors?.onUnauthorized &&\n unauthorizedStatusCodes.includes(response.status)\n ) {\n config.interceptors.onUnauthorized(apiError);\n } else if (\n config.interceptors?.onForbidden &&\n forbiddenStatusCodes.includes(response.status)\n ) {\n config.interceptors.onForbidden(apiError);\n } else if (config.interceptors?.onError) {\n config.interceptors.onError(apiError);\n }\n\n throw apiError;\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof ApiError) throw error;\n throw new ApiError(\n error instanceof Error ? error.message : 'Network error',\n 'NETWORK_ERROR',\n 520\n );\n }\n}\n","import { useState, useRef, useEffect, useCallback } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, FetchOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface FetchState<T> {\n data: T | null;\n isLoading: boolean;\n isRefreshing: boolean;\n error: ApiError | null;\n}\n\n/**\n * A hook for executing a fetch function and managing the state of the fetch.\n * @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the fetch and the fetch function.\n */\nexport function useFetchFn<T>(options?: FetchOptions) {\n const [state, setState] = useState<FetchState<T>>({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n\n const isMounted = useRef<boolean>(true);\n const lastFetchFn = useRef<(() => Promise<HttpResponse<T>>) | null>(null);\n\n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const execute = useCallback(\n async (\n fetchFn: () => Promise<HttpResponse<T>>,\n execOptions: { isRefresh: boolean }\n ): Promise<HttpResponse<T> | null> => {\n lastFetchFn.current = fetchFn;\n\n setState((prev) => ({\n ...prev,\n isLoading: !execOptions.isRefresh,\n isRefreshing: !!execOptions.isRefresh,\n error: null,\n }));\n\n try {\n const response = await fetchFn();\n\n if (isMounted.current) {\n setState({\n data: response.data || null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: apiError,\n });\n }\n return null;\n }\n },\n []\n );\n\n const executeFetchFn = useCallback(\n (fetchFn: () => Promise<HttpResponse<T>>) => {\n return execute(fetchFn, { isRefresh: false });\n },\n [execute]\n );\n\n const refreshFetchFn = useCallback(() => {\n if (lastFetchFn.current) {\n return execute(lastFetchFn.current, { isRefresh: true });\n }\n return null;\n }, [execute]);\n\n useEffect(() => {\n if (!options?.tags || options.tags.length === 0) return;\n\n const subscriptions = options.tags.map((tag) =>\n eventEmitter.addListener(tag, () => {\n refreshFetchFn();\n })\n );\n return () => subscriptions.forEach((sub) => sub.remove());\n }, [options?.tags, refreshFetchFn]);\n\n return { ...state, executeFetchFn, refreshFetchFn };\n}\n","type Listener = () => void;\n\nclass EventEmitter {\n private events: Record<string, Listener[]> = {};\n\n emit(event: string) {\n if (!this.events[event]) return;\n this.events[event].forEach((listener) => listener());\n }\n\n addListener(event: string, listener: Listener) {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(listener);\n \n return {\n remove: () => {\n this.events[event] = this.events[event].filter((l) => l !== listener);\n },\n };\n }\n}\n\nexport const eventEmitter = new EventEmitter();","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, MutationOptions, ExecuteMutationOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface MutationState<T> {\n data: T | null;\n isMutating: boolean;\n}\n\n/**\n * A hook for executing a mutation function and managing the state of the mutation.\n * @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the mutation and the mutation function.\n */\nexport function useMutationFn<T>(options?: MutationOptions) {\n const [state, setState] = useState<MutationState<T>>({\n data: null,\n isMutating: false,\n });\n const isMounted = useRef<boolean>(true);\n \n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const executeMutationFn = useCallback(\n async (\n mutationFn: () => Promise<HttpResponse<T>>,\n executeOptions?: ExecuteMutationOptions<T>\n ): Promise<HttpResponse<T> | null> => {\n setState((prev) => ({ ...prev, isMutating: true }));\n\n try {\n const response = await mutationFn();\n \n if (isMounted.current) {\n setState({\n data: response.data || null,\n isMutating: false,\n });\n \n options?.invalidatesTags?.forEach((tag) => {\n eventEmitter.emit(tag);\n });\n \n if (response.data) executeOptions?.onSuccess?.(response.data);\n else executeOptions?.onSuccess?.(null as unknown as T);\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isMutating: false,\n });\n if (apiError) executeOptions?.onError?.(apiError);\n }\n return null;\n }\n },\n [options?.invalidatesTags]\n );\n\n const reset = useCallback(() => {\n setState({ data: null, isMutating: false });\n }, []);\n\n return { ...state, executeMutationFn, reset };\n}"],"mappings":"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","names":["import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/util/api-error.ts","../src/core/config.ts","../src/core/wire.ts","../src/hook/use-fetch-fn.ts","../src/core/event-emitter.ts","../src/hook/use-mutation-fn.ts"],"sourcesContent":["export * from './interface';\nexport * from './util/api-error';\nexport * from './core/config';\nexport * from './core/wire';\nexport * from './hook/use-fetch-fn';\nexport * from './hook/use-mutation-fn';\n","export class ApiError extends Error {\n public errorCode?: string;\n public statusCode?: number;\n\n constructor(message: string, errorCode?: string, statusCode?: number) {\n super(message);\n this.name = 'ApiError';\n this.errorCode = errorCode;\n this.statusCode = statusCode;\n }\n}","import { WireConfig } from '../interface';\n\nlet globalWireConfig: WireConfig | null = null;\n\n/**\n * Initializes the library with mandatory configurations.\n * Must be executed at the application entry point before any API calls.\n * @param config - The required configuration object including baseUrl and getToken.\n */\nexport const initWire = (config: WireConfig): void => {\n globalWireConfig = {\n ...config,\n headers: config.headers || {},\n };\n};\n\n/**\n * Updates the existing configuration.\n * Merges new headers with existing ones and overrides other provided fields.\n * @param config - A partial configuration object to update.\n */\nexport const updateWireConfig = (config: Partial<WireConfig>): void => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n\n globalWireConfig = {\n ...globalWireConfig,\n ...config,\n headers: {\n ...globalWireConfig.headers,\n ...config.headers,\n },\n };\n};\n\n/**\n * Retrieves the current global configuration state.\n * @throws Error if the configuration state is null.\n * @returns The validated WireConfig object.\n */\nexport const getWireConfig = (): WireConfig => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n return globalWireConfig;\n};","import { HttpResponse } from '../interface';\nimport { ApiError } from '../util/api-error';\nimport { getWireConfig } from './config';\n\n/**\n * Sends an API request and returns the response.\n * @param endpoint - The API endpoint to call. Example: '/api/v1/users'.\n * @param options - The request options is a RequestInit object.\n */\nexport async function wireApi<T>(\n endpoint: string,\n options: RequestInit = {}\n): Promise<HttpResponse<T>> {\n const config = getWireConfig();\n const url = `${config.baseUrl}${endpoint}`;\n const accessToken = await config.getToken();\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),\n ...config.headers,\n ...options.headers,\n };\n\n try {\n const response = await fetch(url, { ...options, headers });\n\n if (!response.ok) {\n let errorData;\n try {\n errorData = await response.json();\n } catch {\n errorData = { message: 'Unknown server error', error: 'UNKNOWN' };\n }\n\n const apiError = new ApiError(\n errorData.message,\n errorData.error,\n response.status\n );\n\n // Resolve effective status-code mappings with default values\n const unauthorizedStatusCodes =\n config.unauthorizedStatusCodes && config.unauthorizedStatusCodes.length > 0\n ? config.unauthorizedStatusCodes\n : [401];\n\n const forbiddenStatusCodes =\n config.forbiddenStatusCodes && config.forbiddenStatusCodes.length > 0\n ? config.forbiddenStatusCodes\n : [403];\n\n // Trigger interceptors based on configured status codes\n if (\n config.interceptors?.onUnauthorized &&\n unauthorizedStatusCodes.includes(response.status)\n ) {\n config.interceptors.onUnauthorized(apiError);\n } else if (\n config.interceptors?.onForbidden &&\n forbiddenStatusCodes.includes(response.status)\n ) {\n config.interceptors.onForbidden(apiError);\n } else if (config.interceptors?.onError) {\n config.interceptors.onError(apiError);\n }\n\n throw apiError;\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof ApiError) throw error;\n throw new ApiError(\n error instanceof Error ? error.message : 'Network error',\n 'NETWORK_ERROR',\n 520\n );\n }\n}\n","import { useState, useRef, useEffect, useCallback } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, FetchOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface FetchState<T> {\n data: T | null;\n isLoading: boolean;\n isRefreshing: boolean;\n error: ApiError | null;\n}\n\n/**\n * A hook for executing a fetch function and managing the state of the fetch.\n * @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the fetch and the fetch function.\n */\nexport function useFetchFn<T>(\n fetchFn: () => Promise<HttpResponse<T>>,\n options?: FetchOptions\n) {\n const [state, setState] = useState<FetchState<T>>({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n\n const isMounted = useRef<boolean>(true);\n const lastFetchFn = useRef<(() => Promise<HttpResponse<T>>) | null>(null);\n\n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const execute = useCallback(\n async (execOptions: {\n isRefresh: boolean;\n }): Promise<HttpResponse<T> | null> => {\n lastFetchFn.current = fetchFn;\n\n setState((prev) => ({\n ...prev,\n isLoading: !execOptions.isRefresh,\n isRefreshing: !!execOptions.isRefresh,\n error: null,\n }));\n\n try {\n const response = await fetchFn();\n\n if (isMounted.current) {\n setState({\n data: response.data || null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: apiError,\n });\n }\n return null;\n }\n },\n []\n );\n\n const executeFetchFn = useCallback(\n () => execute({ isRefresh: false }),\n [execute]\n );\n const refreshFetchFn = useCallback(() => execute({ isRefresh: true }), [execute]);\n\n useEffect(() => {\n if (!options?.tags || options.tags.length === 0) return;\n\n const subscriptions = options.tags.map((tag) =>\n eventEmitter.addListener(tag, () => {\n refreshFetchFn();\n })\n );\n return () => subscriptions.forEach((sub) => sub.remove());\n }, [options?.tags, refreshFetchFn]);\n\n return { ...state, executeFetchFn, refreshFetchFn };\n}\n","type Listener = () => void;\n\nclass EventEmitter {\n private events: Record<string, Listener[]> = {};\n\n emit(event: string) {\n if (!this.events[event]) return;\n this.events[event].forEach((listener) => listener());\n }\n\n addListener(event: string, listener: Listener) {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(listener);\n \n return {\n remove: () => {\n this.events[event] = this.events[event].filter((l) => l !== listener);\n },\n };\n }\n}\n\nexport const eventEmitter = new EventEmitter();","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, MutationOptions, ExecuteMutationOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface MutationState<T> {\n data: T | null;\n isMutating: boolean;\n}\n\n/**\n * A hook for executing a mutation function and managing the state of the mutation.\n * @param mutationFn - The mutation function to execute.\n * @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the mutation and the mutation function.\n */\nexport function useMutationFn<T>(\n mutationFn: () => Promise<HttpResponse<T>>,\n options?: MutationOptions\n) {\n const [state, setState] = useState<MutationState<T>>({\n data: null,\n isMutating: false,\n });\n const isMounted = useRef<boolean>(true);\n \n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const executeMutationFn = useCallback(\n async (\n executeOptions?: ExecuteMutationOptions<T>\n ): Promise<HttpResponse<T> | null> => {\n setState((prev) => ({ ...prev, isMutating: true }));\n\n try {\n const response = await mutationFn();\n \n if (isMounted.current) {\n setState({\n data: response.data || null,\n isMutating: false,\n });\n \n options?.invalidatesTags?.forEach((tag) => {\n eventEmitter.emit(tag);\n });\n \n if (response.data) executeOptions?.onSuccess?.(response.data);\n else executeOptions?.onSuccess?.(null as unknown as T);\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isMutating: false,\n });\n if (apiError) executeOptions?.onError?.(apiError);\n }\n return null;\n }\n },\n [mutationFn, options?.invalidatesTags]\n );\n\n const reset = useCallback(() => {\n setState({ data: null, isMutating: false });\n }, []);\n\n return { ...state, executeMutationFn, reset };\n}"],"mappings":"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","names":["import_react"]}
|
package/dist/index.mjs
CHANGED
|
@@ -110,7 +110,7 @@ var EventEmitter = class {
|
|
|
110
110
|
var eventEmitter = new EventEmitter();
|
|
111
111
|
|
|
112
112
|
// src/hook/use-fetch-fn.ts
|
|
113
|
-
function useFetchFn(options) {
|
|
113
|
+
function useFetchFn(fetchFn, options) {
|
|
114
114
|
const [state, setState] = useState({
|
|
115
115
|
data: null,
|
|
116
116
|
isLoading: false,
|
|
@@ -126,7 +126,7 @@ function useFetchFn(options) {
|
|
|
126
126
|
};
|
|
127
127
|
}, []);
|
|
128
128
|
const execute = useCallback(
|
|
129
|
-
async (
|
|
129
|
+
async (execOptions) => {
|
|
130
130
|
lastFetchFn.current = fetchFn;
|
|
131
131
|
setState((prev) => ({
|
|
132
132
|
...prev,
|
|
@@ -161,17 +161,10 @@ function useFetchFn(options) {
|
|
|
161
161
|
[]
|
|
162
162
|
);
|
|
163
163
|
const executeFetchFn = useCallback(
|
|
164
|
-
(
|
|
165
|
-
return execute(fetchFn, { isRefresh: false });
|
|
166
|
-
},
|
|
164
|
+
() => execute({ isRefresh: false }),
|
|
167
165
|
[execute]
|
|
168
166
|
);
|
|
169
|
-
const refreshFetchFn = useCallback(() => {
|
|
170
|
-
if (lastFetchFn.current) {
|
|
171
|
-
return execute(lastFetchFn.current, { isRefresh: true });
|
|
172
|
-
}
|
|
173
|
-
return null;
|
|
174
|
-
}, [execute]);
|
|
167
|
+
const refreshFetchFn = useCallback(() => execute({ isRefresh: true }), [execute]);
|
|
175
168
|
useEffect(() => {
|
|
176
169
|
if (!options?.tags || options.tags.length === 0) return;
|
|
177
170
|
const subscriptions = options.tags.map(
|
|
@@ -186,7 +179,7 @@ function useFetchFn(options) {
|
|
|
186
179
|
|
|
187
180
|
// src/hook/use-mutation-fn.ts
|
|
188
181
|
import { useState as useState2, useCallback as useCallback2, useRef as useRef2, useEffect as useEffect2 } from "react";
|
|
189
|
-
function useMutationFn(options) {
|
|
182
|
+
function useMutationFn(mutationFn, options) {
|
|
190
183
|
const [state, setState] = useState2({
|
|
191
184
|
data: null,
|
|
192
185
|
isMutating: false
|
|
@@ -199,7 +192,7 @@ function useMutationFn(options) {
|
|
|
199
192
|
};
|
|
200
193
|
}, []);
|
|
201
194
|
const executeMutationFn = useCallback2(
|
|
202
|
-
async (
|
|
195
|
+
async (executeOptions) => {
|
|
203
196
|
setState((prev) => ({ ...prev, isMutating: true }));
|
|
204
197
|
try {
|
|
205
198
|
const response = await mutationFn();
|
|
@@ -227,7 +220,7 @@ function useMutationFn(options) {
|
|
|
227
220
|
return null;
|
|
228
221
|
}
|
|
229
222
|
},
|
|
230
|
-
[options?.invalidatesTags]
|
|
223
|
+
[mutationFn, options?.invalidatesTags]
|
|
231
224
|
);
|
|
232
225
|
const reset = useCallback2(() => {
|
|
233
226
|
setState({ data: null, isMutating: false });
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/util/api-error.ts","../src/core/config.ts","../src/core/wire.ts","../src/hook/use-fetch-fn.ts","../src/core/event-emitter.ts","../src/hook/use-mutation-fn.ts"],"sourcesContent":["export class ApiError extends Error {\n public errorCode?: string;\n public statusCode?: number;\n\n constructor(message: string, errorCode?: string, statusCode?: number) {\n super(message);\n this.name = 'ApiError';\n this.errorCode = errorCode;\n this.statusCode = statusCode;\n }\n}","import { WireConfig } from '../interface';\n\nlet globalWireConfig: WireConfig | null = null;\n\n/**\n * Initializes the library with mandatory configurations.\n * Must be executed at the application entry point before any API calls.\n * @param config - The required configuration object including baseUrl and getToken.\n */\nexport const initWire = (config: WireConfig): void => {\n globalWireConfig = {\n ...config,\n headers: config.headers || {},\n };\n};\n\n/**\n * Updates the existing configuration.\n * Merges new headers with existing ones and overrides other provided fields.\n * @param config - A partial configuration object to update.\n */\nexport const updateWireConfig = (config: Partial<WireConfig>): void => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n\n globalWireConfig = {\n ...globalWireConfig,\n ...config,\n headers: {\n ...globalWireConfig.headers,\n ...config.headers,\n },\n };\n};\n\n/**\n * Retrieves the current global configuration state.\n * @throws Error if the configuration state is null.\n * @returns The validated WireConfig object.\n */\nexport const getWireConfig = (): WireConfig => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n return globalWireConfig;\n};","import { HttpResponse } from '../interface';\nimport { ApiError } from '../util/api-error';\nimport { getWireConfig } from './config';\n\n/**\n * Sends an API request and returns the response.\n * @param endpoint - The API endpoint to call. Example: '/api/v1/users'.\n * @param options - The request options is a RequestInit object.\n */\nexport async function wireApi<T>(\n endpoint: string,\n options: RequestInit = {}\n): Promise<HttpResponse<T>> {\n const config = getWireConfig();\n const url = `${config.baseUrl}${endpoint}`;\n const accessToken = await config.getToken();\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),\n ...config.headers,\n ...options.headers,\n };\n\n try {\n const response = await fetch(url, { ...options, headers });\n\n if (!response.ok) {\n let errorData;\n try {\n errorData = await response.json();\n } catch {\n errorData = { message: 'Unknown server error', error: 'UNKNOWN' };\n }\n\n const apiError = new ApiError(\n errorData.message,\n errorData.error,\n response.status\n );\n\n // Resolve effective status-code mappings with default values\n const unauthorizedStatusCodes =\n config.unauthorizedStatusCodes && config.unauthorizedStatusCodes.length > 0\n ? config.unauthorizedStatusCodes\n : [401];\n\n const forbiddenStatusCodes =\n config.forbiddenStatusCodes && config.forbiddenStatusCodes.length > 0\n ? config.forbiddenStatusCodes\n : [403];\n\n // Trigger interceptors based on configured status codes\n if (\n config.interceptors?.onUnauthorized &&\n unauthorizedStatusCodes.includes(response.status)\n ) {\n config.interceptors.onUnauthorized(apiError);\n } else if (\n config.interceptors?.onForbidden &&\n forbiddenStatusCodes.includes(response.status)\n ) {\n config.interceptors.onForbidden(apiError);\n } else if (config.interceptors?.onError) {\n config.interceptors.onError(apiError);\n }\n\n throw apiError;\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof ApiError) throw error;\n throw new ApiError(\n error instanceof Error ? error.message : 'Network error',\n 'NETWORK_ERROR',\n 520\n );\n }\n}\n","import { useState, useRef, useEffect, useCallback } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, FetchOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface FetchState<T> {\n data: T | null;\n isLoading: boolean;\n isRefreshing: boolean;\n error: ApiError | null;\n}\n\n/**\n * A hook for executing a fetch function and managing the state of the fetch.\n * @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the fetch and the fetch function.\n */\nexport function useFetchFn<T>(options?: FetchOptions) {\n const [state, setState] = useState<FetchState<T>>({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n\n const isMounted = useRef<boolean>(true);\n const lastFetchFn = useRef<(() => Promise<HttpResponse<T>>) | null>(null);\n\n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const execute = useCallback(\n async (\n fetchFn: () => Promise<HttpResponse<T>>,\n execOptions: { isRefresh: boolean }\n ): Promise<HttpResponse<T> | null> => {\n lastFetchFn.current = fetchFn;\n\n setState((prev) => ({\n ...prev,\n isLoading: !execOptions.isRefresh,\n isRefreshing: !!execOptions.isRefresh,\n error: null,\n }));\n\n try {\n const response = await fetchFn();\n\n if (isMounted.current) {\n setState({\n data: response.data || null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: apiError,\n });\n }\n return null;\n }\n },\n []\n );\n\n const executeFetchFn = useCallback(\n (fetchFn: () => Promise<HttpResponse<T>>) => {\n return execute(fetchFn, { isRefresh: false });\n },\n [execute]\n );\n\n const refreshFetchFn = useCallback(() => {\n if (lastFetchFn.current) {\n return execute(lastFetchFn.current, { isRefresh: true });\n }\n return null;\n }, [execute]);\n\n useEffect(() => {\n if (!options?.tags || options.tags.length === 0) return;\n\n const subscriptions = options.tags.map((tag) =>\n eventEmitter.addListener(tag, () => {\n refreshFetchFn();\n })\n );\n return () => subscriptions.forEach((sub) => sub.remove());\n }, [options?.tags, refreshFetchFn]);\n\n return { ...state, executeFetchFn, refreshFetchFn };\n}\n","type Listener = () => void;\n\nclass EventEmitter {\n private events: Record<string, Listener[]> = {};\n\n emit(event: string) {\n if (!this.events[event]) return;\n this.events[event].forEach((listener) => listener());\n }\n\n addListener(event: string, listener: Listener) {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(listener);\n \n return {\n remove: () => {\n this.events[event] = this.events[event].filter((l) => l !== listener);\n },\n };\n }\n}\n\nexport const eventEmitter = new EventEmitter();","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, MutationOptions, ExecuteMutationOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface MutationState<T> {\n data: T | null;\n isMutating: boolean;\n}\n\n/**\n * A hook for executing a mutation function and managing the state of the mutation.\n * @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the mutation and the mutation function.\n */\nexport function useMutationFn<T>(options?: MutationOptions) {\n const [state, setState] = useState<MutationState<T>>({\n data: null,\n isMutating: false,\n });\n const isMounted = useRef<boolean>(true);\n \n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const executeMutationFn = useCallback(\n async (\n mutationFn: () => Promise<HttpResponse<T>>,\n executeOptions?: ExecuteMutationOptions<T>\n ): Promise<HttpResponse<T> | null> => {\n setState((prev) => ({ ...prev, isMutating: true }));\n\n try {\n const response = await mutationFn();\n \n if (isMounted.current) {\n setState({\n data: response.data || null,\n isMutating: false,\n });\n \n options?.invalidatesTags?.forEach((tag) => {\n eventEmitter.emit(tag);\n });\n \n if (response.data) executeOptions?.onSuccess?.(response.data);\n else executeOptions?.onSuccess?.(null as unknown as T);\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isMutating: false,\n });\n if (apiError) executeOptions?.onError?.(apiError);\n }\n return null;\n }\n },\n [options?.invalidatesTags]\n );\n\n const reset = useCallback(() => {\n setState({ data: null, isMutating: false });\n }, []);\n\n return { ...state, executeMutationFn, reset };\n}"],"mappings":"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","names":["useState","useCallback","useRef","useEffect","useState","useRef","useEffect","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/util/api-error.ts","../src/core/config.ts","../src/core/wire.ts","../src/hook/use-fetch-fn.ts","../src/core/event-emitter.ts","../src/hook/use-mutation-fn.ts"],"sourcesContent":["export class ApiError extends Error {\n public errorCode?: string;\n public statusCode?: number;\n\n constructor(message: string, errorCode?: string, statusCode?: number) {\n super(message);\n this.name = 'ApiError';\n this.errorCode = errorCode;\n this.statusCode = statusCode;\n }\n}","import { WireConfig } from '../interface';\n\nlet globalWireConfig: WireConfig | null = null;\n\n/**\n * Initializes the library with mandatory configurations.\n * Must be executed at the application entry point before any API calls.\n * @param config - The required configuration object including baseUrl and getToken.\n */\nexport const initWire = (config: WireConfig): void => {\n globalWireConfig = {\n ...config,\n headers: config.headers || {},\n };\n};\n\n/**\n * Updates the existing configuration.\n * Merges new headers with existing ones and overrides other provided fields.\n * @param config - A partial configuration object to update.\n */\nexport const updateWireConfig = (config: Partial<WireConfig>): void => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n\n globalWireConfig = {\n ...globalWireConfig,\n ...config,\n headers: {\n ...globalWireConfig.headers,\n ...config.headers,\n },\n };\n};\n\n/**\n * Retrieves the current global configuration state.\n * @throws Error if the configuration state is null.\n * @returns The validated WireConfig object.\n */\nexport const getWireConfig = (): WireConfig => {\n if (!globalWireConfig) {\n throw new Error('Wire not initialized. Call initWire() first.');\n }\n return globalWireConfig;\n};","import { HttpResponse } from '../interface';\nimport { ApiError } from '../util/api-error';\nimport { getWireConfig } from './config';\n\n/**\n * Sends an API request and returns the response.\n * @param endpoint - The API endpoint to call. Example: '/api/v1/users'.\n * @param options - The request options is a RequestInit object.\n */\nexport async function wireApi<T>(\n endpoint: string,\n options: RequestInit = {}\n): Promise<HttpResponse<T>> {\n const config = getWireConfig();\n const url = `${config.baseUrl}${endpoint}`;\n const accessToken = await config.getToken();\n\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),\n ...config.headers,\n ...options.headers,\n };\n\n try {\n const response = await fetch(url, { ...options, headers });\n\n if (!response.ok) {\n let errorData;\n try {\n errorData = await response.json();\n } catch {\n errorData = { message: 'Unknown server error', error: 'UNKNOWN' };\n }\n\n const apiError = new ApiError(\n errorData.message,\n errorData.error,\n response.status\n );\n\n // Resolve effective status-code mappings with default values\n const unauthorizedStatusCodes =\n config.unauthorizedStatusCodes && config.unauthorizedStatusCodes.length > 0\n ? config.unauthorizedStatusCodes\n : [401];\n\n const forbiddenStatusCodes =\n config.forbiddenStatusCodes && config.forbiddenStatusCodes.length > 0\n ? config.forbiddenStatusCodes\n : [403];\n\n // Trigger interceptors based on configured status codes\n if (\n config.interceptors?.onUnauthorized &&\n unauthorizedStatusCodes.includes(response.status)\n ) {\n config.interceptors.onUnauthorized(apiError);\n } else if (\n config.interceptors?.onForbidden &&\n forbiddenStatusCodes.includes(response.status)\n ) {\n config.interceptors.onForbidden(apiError);\n } else if (config.interceptors?.onError) {\n config.interceptors.onError(apiError);\n }\n\n throw apiError;\n }\n\n return await response.json();\n } catch (error) {\n if (error instanceof ApiError) throw error;\n throw new ApiError(\n error instanceof Error ? error.message : 'Network error',\n 'NETWORK_ERROR',\n 520\n );\n }\n}\n","import { useState, useRef, useEffect, useCallback } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, FetchOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface FetchState<T> {\n data: T | null;\n isLoading: boolean;\n isRefreshing: boolean;\n error: ApiError | null;\n}\n\n/**\n * A hook for executing a fetch function and managing the state of the fetch.\n * @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the fetch and the fetch function.\n */\nexport function useFetchFn<T>(\n fetchFn: () => Promise<HttpResponse<T>>,\n options?: FetchOptions\n) {\n const [state, setState] = useState<FetchState<T>>({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n\n const isMounted = useRef<boolean>(true);\n const lastFetchFn = useRef<(() => Promise<HttpResponse<T>>) | null>(null);\n\n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const execute = useCallback(\n async (execOptions: {\n isRefresh: boolean;\n }): Promise<HttpResponse<T> | null> => {\n lastFetchFn.current = fetchFn;\n\n setState((prev) => ({\n ...prev,\n isLoading: !execOptions.isRefresh,\n isRefreshing: !!execOptions.isRefresh,\n error: null,\n }));\n\n try {\n const response = await fetchFn();\n\n if (isMounted.current) {\n setState({\n data: response.data || null,\n isLoading: false,\n isRefreshing: false,\n error: null,\n });\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isLoading: false,\n isRefreshing: false,\n error: apiError,\n });\n }\n return null;\n }\n },\n []\n );\n\n const executeFetchFn = useCallback(\n () => execute({ isRefresh: false }),\n [execute]\n );\n const refreshFetchFn = useCallback(() => execute({ isRefresh: true }), [execute]);\n\n useEffect(() => {\n if (!options?.tags || options.tags.length === 0) return;\n\n const subscriptions = options.tags.map((tag) =>\n eventEmitter.addListener(tag, () => {\n refreshFetchFn();\n })\n );\n return () => subscriptions.forEach((sub) => sub.remove());\n }, [options?.tags, refreshFetchFn]);\n\n return { ...state, executeFetchFn, refreshFetchFn };\n}\n","type Listener = () => void;\n\nclass EventEmitter {\n private events: Record<string, Listener[]> = {};\n\n emit(event: string) {\n if (!this.events[event]) return;\n this.events[event].forEach((listener) => listener());\n }\n\n addListener(event: string, listener: Listener) {\n if (!this.events[event]) {\n this.events[event] = [];\n }\n this.events[event].push(listener);\n \n return {\n remove: () => {\n this.events[event] = this.events[event].filter((l) => l !== listener);\n },\n };\n }\n}\n\nexport const eventEmitter = new EventEmitter();","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { ApiError } from '../util/api-error';\nimport { HttpResponse, MutationOptions, ExecuteMutationOptions } from '../interface';\nimport { eventEmitter } from '../core/event-emitter';\n\ninterface MutationState<T> {\n data: T | null;\n isMutating: boolean;\n}\n\n/**\n * A hook for executing a mutation function and managing the state of the mutation.\n * @param mutationFn - The mutation function to execute.\n * @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.\n * @returns The state of the mutation and the mutation function.\n */\nexport function useMutationFn<T>(\n mutationFn: () => Promise<HttpResponse<T>>,\n options?: MutationOptions\n) {\n const [state, setState] = useState<MutationState<T>>({\n data: null,\n isMutating: false,\n });\n const isMounted = useRef<boolean>(true);\n \n useEffect(() => {\n isMounted.current = true;\n return () => {\n isMounted.current = false;\n };\n }, []);\n\n const executeMutationFn = useCallback(\n async (\n executeOptions?: ExecuteMutationOptions<T>\n ): Promise<HttpResponse<T> | null> => {\n setState((prev) => ({ ...prev, isMutating: true }));\n\n try {\n const response = await mutationFn();\n \n if (isMounted.current) {\n setState({\n data: response.data || null,\n isMutating: false,\n });\n \n options?.invalidatesTags?.forEach((tag) => {\n eventEmitter.emit(tag);\n });\n \n if (response.data) executeOptions?.onSuccess?.(response.data);\n else executeOptions?.onSuccess?.(null as unknown as T);\n }\n return response;\n } catch (error) {\n const apiError = error as ApiError;\n if (isMounted.current) {\n setState({\n data: null,\n isMutating: false,\n });\n if (apiError) executeOptions?.onError?.(apiError);\n }\n return null;\n }\n },\n [mutationFn, options?.invalidatesTags]\n );\n\n const reset = useCallback(() => {\n setState({ data: null, isMutating: false });\n }, []);\n\n return { ...state, executeMutationFn, reset };\n}"],"mappings":"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","names":["useState","useCallback","useRef","useEffect","useState","useRef","useEffect","useCallback"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fetchwire",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A lightweight, focused API fetching library for React and React Native applications.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/chuhaiphu/fetchwire.git"
|
|
8
|
+
},
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"provenance": true
|
|
11
|
+
},
|
|
5
12
|
"main": "./dist/index.js",
|
|
6
13
|
"module": "./dist/index.mjs",
|
|
7
14
|
"types": "./dist/index.d.ts",
|