fetchwire 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/LICENSE +21 -0
- package/README.md +568 -0
- package/dist/index.d.mts +172 -0
- package/dist/index.d.ts +172 -0
- package/dist/index.js +279 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +246 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +37 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
declare class ApiError extends Error {
|
|
2
|
+
errorCode?: string;
|
|
3
|
+
statusCode?: number;
|
|
4
|
+
constructor(message: string, errorCode?: string, statusCode?: number);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Standard HTTP response shape used by fetchwire.
|
|
9
|
+
* @template T Type of the `data` payload.
|
|
10
|
+
*/
|
|
11
|
+
interface HttpResponse<T> {
|
|
12
|
+
/**
|
|
13
|
+
* Parsed response body returned by your API, if available.
|
|
14
|
+
*/
|
|
15
|
+
data?: T;
|
|
16
|
+
message?: string;
|
|
17
|
+
status?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Set of optional global interceptors that can react to HTTP errors.
|
|
21
|
+
*
|
|
22
|
+
* All handlers can be synchronous or async.
|
|
23
|
+
*/
|
|
24
|
+
interface WireInterceptors {
|
|
25
|
+
/**
|
|
26
|
+
* Called when a 401 Unauthorized response is returned.
|
|
27
|
+
*/
|
|
28
|
+
onUnauthorized?: (error: ApiError) => void | Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Called when a 403 Forbidden response is returned.
|
|
31
|
+
*/
|
|
32
|
+
onForbidden?: (error: ApiError) => void | Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Called for other non‑success errors, after more specific handlers (if any).
|
|
35
|
+
*/
|
|
36
|
+
onError?: (error: ApiError) => void | Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Global configuration passed to `initWire`.
|
|
40
|
+
*/
|
|
41
|
+
interface WireConfig {
|
|
42
|
+
/**
|
|
43
|
+
* Base URL that all relative endpoints will be appended to,
|
|
44
|
+
* e.g. "https://api.example.com".
|
|
45
|
+
*/
|
|
46
|
+
baseUrl: string;
|
|
47
|
+
/**
|
|
48
|
+
* Default headers applied to every request.
|
|
49
|
+
*
|
|
50
|
+
* These will be merged with:
|
|
51
|
+
* - the Authorization header built from `getToken`, and
|
|
52
|
+
* - any per‑request headers.
|
|
53
|
+
*/
|
|
54
|
+
headers?: HeadersInit;
|
|
55
|
+
/**
|
|
56
|
+
* Async function that returns the current access token, or null if not logged in.
|
|
57
|
+
*
|
|
58
|
+
* When a non‑empty token is returned, fetchwire will send it as:
|
|
59
|
+
* `Authorization: Bearer <token>`.
|
|
60
|
+
*/
|
|
61
|
+
getToken: () => Promise<string | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Optional global interceptors to handle unauthorized/forbidden/other errors.
|
|
64
|
+
*/
|
|
65
|
+
interceptors?: WireInterceptors;
|
|
66
|
+
/**
|
|
67
|
+
* HTTP status codes that should be treated as "unauthorized" for the purpose
|
|
68
|
+
* of calling `interceptors.onUnauthorized`. Defaults to `[401]` when omitted.
|
|
69
|
+
*/
|
|
70
|
+
unauthorizedStatusCodes?: number[];
|
|
71
|
+
/**
|
|
72
|
+
* HTTP status codes that should be treated as "forbidden" for the purpose
|
|
73
|
+
* of calling `interceptors.onForbidden`. Defaults to `[403]` when omitted.
|
|
74
|
+
*/
|
|
75
|
+
forbiddenStatusCodes?: number[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Options for the `useFetchFn` hook.
|
|
79
|
+
*/
|
|
80
|
+
interface FetchOptions {
|
|
81
|
+
/**
|
|
82
|
+
* Tags that this fetch subscribes to.
|
|
83
|
+
*
|
|
84
|
+
* When a mutation invalidates any of these tags, the hook will automatically
|
|
85
|
+
* re‑run the last request via `refreshFetchFn`.
|
|
86
|
+
*/
|
|
87
|
+
tags?: string[];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Options for the `useMutationFn` hook.
|
|
91
|
+
*/
|
|
92
|
+
interface MutationOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Tags that should be invalidated after a successful mutation.
|
|
95
|
+
*
|
|
96
|
+
* All active `useFetchFn` hooks that subscribed to any of these tags
|
|
97
|
+
* will be notified and refreshed.
|
|
98
|
+
*/
|
|
99
|
+
invalidatesTags?: string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Per‑execution callbacks for `useMutationFn`.
|
|
103
|
+
* @template T Type of the mutation result data.
|
|
104
|
+
*/
|
|
105
|
+
interface ExecuteMutationOptions<T> {
|
|
106
|
+
/**
|
|
107
|
+
* Called when the mutation succeeds.
|
|
108
|
+
*
|
|
109
|
+
* @param data Parsed response data from the server.
|
|
110
|
+
*/
|
|
111
|
+
onSuccess?: (data: T) => void | Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* Called when the mutation fails with an `ApiError`.
|
|
114
|
+
*
|
|
115
|
+
* @param error Normalized API error.
|
|
116
|
+
*/
|
|
117
|
+
onError?: (error: ApiError) => void | Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initializes the library with mandatory configurations.
|
|
122
|
+
* Must be executed at the application entry point before any API calls.
|
|
123
|
+
* @param config - The required configuration object including baseUrl and getToken.
|
|
124
|
+
*/
|
|
125
|
+
declare const initWire: (config: WireConfig) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Updates the existing configuration.
|
|
128
|
+
* Merges new headers with existing ones and overrides other provided fields.
|
|
129
|
+
* @param config - A partial configuration object to update.
|
|
130
|
+
*/
|
|
131
|
+
declare const updateWireConfig: (config: Partial<WireConfig>) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Retrieves the current global configuration state.
|
|
134
|
+
* @throws Error if the configuration state is null.
|
|
135
|
+
* @returns The validated WireConfig object.
|
|
136
|
+
*/
|
|
137
|
+
declare const getWireConfig: () => WireConfig;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Sends an API request and returns the response.
|
|
141
|
+
* @param endpoint - The API endpoint to call. Example: '/api/v1/users'.
|
|
142
|
+
* @param options - The request options is a RequestInit object.
|
|
143
|
+
*/
|
|
144
|
+
declare function wireApi<T>(endpoint: string, options?: RequestInit): Promise<HttpResponse<T>>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A hook for executing a fetch function and managing the state of the fetch.
|
|
148
|
+
* @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.
|
|
149
|
+
* @returns The state of the fetch and the fetch function.
|
|
150
|
+
*/
|
|
151
|
+
declare function useFetchFn<T>(options?: FetchOptions): {
|
|
152
|
+
executeFetchFn: (fetchFn: () => Promise<HttpResponse<T>>) => Promise<HttpResponse<T> | null>;
|
|
153
|
+
refreshFetchFn: () => Promise<HttpResponse<T> | null> | null;
|
|
154
|
+
data: T | null;
|
|
155
|
+
isLoading: boolean;
|
|
156
|
+
isRefreshing: boolean;
|
|
157
|
+
error: ApiError | null;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* A hook for executing a mutation function and managing the state of the mutation.
|
|
162
|
+
* @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.
|
|
163
|
+
* @returns The state of the mutation and the mutation function.
|
|
164
|
+
*/
|
|
165
|
+
declare function useMutationFn<T>(options?: MutationOptions): {
|
|
166
|
+
executeMutationFn: (mutationFn: () => Promise<HttpResponse<T>>, executeOptions?: ExecuteMutationOptions<T>) => Promise<HttpResponse<T> | null>;
|
|
167
|
+
reset: () => void;
|
|
168
|
+
data: T | null;
|
|
169
|
+
isMutating: boolean;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export { ApiError, type ExecuteMutationOptions, type FetchOptions, type HttpResponse, type MutationOptions, type WireConfig, type WireInterceptors, getWireConfig, initWire, updateWireConfig, useFetchFn, useMutationFn, wireApi };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
declare class ApiError extends Error {
|
|
2
|
+
errorCode?: string;
|
|
3
|
+
statusCode?: number;
|
|
4
|
+
constructor(message: string, errorCode?: string, statusCode?: number);
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Standard HTTP response shape used by fetchwire.
|
|
9
|
+
* @template T Type of the `data` payload.
|
|
10
|
+
*/
|
|
11
|
+
interface HttpResponse<T> {
|
|
12
|
+
/**
|
|
13
|
+
* Parsed response body returned by your API, if available.
|
|
14
|
+
*/
|
|
15
|
+
data?: T;
|
|
16
|
+
message?: string;
|
|
17
|
+
status?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Set of optional global interceptors that can react to HTTP errors.
|
|
21
|
+
*
|
|
22
|
+
* All handlers can be synchronous or async.
|
|
23
|
+
*/
|
|
24
|
+
interface WireInterceptors {
|
|
25
|
+
/**
|
|
26
|
+
* Called when a 401 Unauthorized response is returned.
|
|
27
|
+
*/
|
|
28
|
+
onUnauthorized?: (error: ApiError) => void | Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Called when a 403 Forbidden response is returned.
|
|
31
|
+
*/
|
|
32
|
+
onForbidden?: (error: ApiError) => void | Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Called for other non‑success errors, after more specific handlers (if any).
|
|
35
|
+
*/
|
|
36
|
+
onError?: (error: ApiError) => void | Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Global configuration passed to `initWire`.
|
|
40
|
+
*/
|
|
41
|
+
interface WireConfig {
|
|
42
|
+
/**
|
|
43
|
+
* Base URL that all relative endpoints will be appended to,
|
|
44
|
+
* e.g. "https://api.example.com".
|
|
45
|
+
*/
|
|
46
|
+
baseUrl: string;
|
|
47
|
+
/**
|
|
48
|
+
* Default headers applied to every request.
|
|
49
|
+
*
|
|
50
|
+
* These will be merged with:
|
|
51
|
+
* - the Authorization header built from `getToken`, and
|
|
52
|
+
* - any per‑request headers.
|
|
53
|
+
*/
|
|
54
|
+
headers?: HeadersInit;
|
|
55
|
+
/**
|
|
56
|
+
* Async function that returns the current access token, or null if not logged in.
|
|
57
|
+
*
|
|
58
|
+
* When a non‑empty token is returned, fetchwire will send it as:
|
|
59
|
+
* `Authorization: Bearer <token>`.
|
|
60
|
+
*/
|
|
61
|
+
getToken: () => Promise<string | null>;
|
|
62
|
+
/**
|
|
63
|
+
* Optional global interceptors to handle unauthorized/forbidden/other errors.
|
|
64
|
+
*/
|
|
65
|
+
interceptors?: WireInterceptors;
|
|
66
|
+
/**
|
|
67
|
+
* HTTP status codes that should be treated as "unauthorized" for the purpose
|
|
68
|
+
* of calling `interceptors.onUnauthorized`. Defaults to `[401]` when omitted.
|
|
69
|
+
*/
|
|
70
|
+
unauthorizedStatusCodes?: number[];
|
|
71
|
+
/**
|
|
72
|
+
* HTTP status codes that should be treated as "forbidden" for the purpose
|
|
73
|
+
* of calling `interceptors.onForbidden`. Defaults to `[403]` when omitted.
|
|
74
|
+
*/
|
|
75
|
+
forbiddenStatusCodes?: number[];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Options for the `useFetchFn` hook.
|
|
79
|
+
*/
|
|
80
|
+
interface FetchOptions {
|
|
81
|
+
/**
|
|
82
|
+
* Tags that this fetch subscribes to.
|
|
83
|
+
*
|
|
84
|
+
* When a mutation invalidates any of these tags, the hook will automatically
|
|
85
|
+
* re‑run the last request via `refreshFetchFn`.
|
|
86
|
+
*/
|
|
87
|
+
tags?: string[];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Options for the `useMutationFn` hook.
|
|
91
|
+
*/
|
|
92
|
+
interface MutationOptions {
|
|
93
|
+
/**
|
|
94
|
+
* Tags that should be invalidated after a successful mutation.
|
|
95
|
+
*
|
|
96
|
+
* All active `useFetchFn` hooks that subscribed to any of these tags
|
|
97
|
+
* will be notified and refreshed.
|
|
98
|
+
*/
|
|
99
|
+
invalidatesTags?: string[];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Per‑execution callbacks for `useMutationFn`.
|
|
103
|
+
* @template T Type of the mutation result data.
|
|
104
|
+
*/
|
|
105
|
+
interface ExecuteMutationOptions<T> {
|
|
106
|
+
/**
|
|
107
|
+
* Called when the mutation succeeds.
|
|
108
|
+
*
|
|
109
|
+
* @param data Parsed response data from the server.
|
|
110
|
+
*/
|
|
111
|
+
onSuccess?: (data: T) => void | Promise<void>;
|
|
112
|
+
/**
|
|
113
|
+
* Called when the mutation fails with an `ApiError`.
|
|
114
|
+
*
|
|
115
|
+
* @param error Normalized API error.
|
|
116
|
+
*/
|
|
117
|
+
onError?: (error: ApiError) => void | Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initializes the library with mandatory configurations.
|
|
122
|
+
* Must be executed at the application entry point before any API calls.
|
|
123
|
+
* @param config - The required configuration object including baseUrl and getToken.
|
|
124
|
+
*/
|
|
125
|
+
declare const initWire: (config: WireConfig) => void;
|
|
126
|
+
/**
|
|
127
|
+
* Updates the existing configuration.
|
|
128
|
+
* Merges new headers with existing ones and overrides other provided fields.
|
|
129
|
+
* @param config - A partial configuration object to update.
|
|
130
|
+
*/
|
|
131
|
+
declare const updateWireConfig: (config: Partial<WireConfig>) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Retrieves the current global configuration state.
|
|
134
|
+
* @throws Error if the configuration state is null.
|
|
135
|
+
* @returns The validated WireConfig object.
|
|
136
|
+
*/
|
|
137
|
+
declare const getWireConfig: () => WireConfig;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Sends an API request and returns the response.
|
|
141
|
+
* @param endpoint - The API endpoint to call. Example: '/api/v1/users'.
|
|
142
|
+
* @param options - The request options is a RequestInit object.
|
|
143
|
+
*/
|
|
144
|
+
declare function wireApi<T>(endpoint: string, options?: RequestInit): Promise<HttpResponse<T>>;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A hook for executing a fetch function and managing the state of the fetch.
|
|
148
|
+
* @param options - Has tags property that will trigger refetching of the useFetchFn with the given tags.
|
|
149
|
+
* @returns The state of the fetch and the fetch function.
|
|
150
|
+
*/
|
|
151
|
+
declare function useFetchFn<T>(options?: FetchOptions): {
|
|
152
|
+
executeFetchFn: (fetchFn: () => Promise<HttpResponse<T>>) => Promise<HttpResponse<T> | null>;
|
|
153
|
+
refreshFetchFn: () => Promise<HttpResponse<T> | null> | null;
|
|
154
|
+
data: T | null;
|
|
155
|
+
isLoading: boolean;
|
|
156
|
+
isRefreshing: boolean;
|
|
157
|
+
error: ApiError | null;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* A hook for executing a mutation function and managing the state of the mutation.
|
|
162
|
+
* @param options - Has invalidatesTags property that will trigger refetching of the useFetchFn with the given tags.
|
|
163
|
+
* @returns The state of the mutation and the mutation function.
|
|
164
|
+
*/
|
|
165
|
+
declare function useMutationFn<T>(options?: MutationOptions): {
|
|
166
|
+
executeMutationFn: (mutationFn: () => Promise<HttpResponse<T>>, executeOptions?: ExecuteMutationOptions<T>) => Promise<HttpResponse<T> | null>;
|
|
167
|
+
reset: () => void;
|
|
168
|
+
data: T | null;
|
|
169
|
+
isMutating: boolean;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export { ApiError, type ExecuteMutationOptions, type FetchOptions, type HttpResponse, type MutationOptions, type WireConfig, type WireInterceptors, getWireConfig, initWire, updateWireConfig, useFetchFn, useMutationFn, wireApi };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ApiError: () => ApiError,
|
|
24
|
+
getWireConfig: () => getWireConfig,
|
|
25
|
+
initWire: () => initWire,
|
|
26
|
+
updateWireConfig: () => updateWireConfig,
|
|
27
|
+
useFetchFn: () => useFetchFn,
|
|
28
|
+
useMutationFn: () => useMutationFn,
|
|
29
|
+
wireApi: () => wireApi
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/util/api-error.ts
|
|
34
|
+
var ApiError = class extends Error {
|
|
35
|
+
constructor(message, errorCode, statusCode) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "ApiError";
|
|
38
|
+
this.errorCode = errorCode;
|
|
39
|
+
this.statusCode = statusCode;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/core/config.ts
|
|
44
|
+
var globalWireConfig = null;
|
|
45
|
+
var initWire = (config) => {
|
|
46
|
+
globalWireConfig = {
|
|
47
|
+
...config,
|
|
48
|
+
headers: config.headers || {}
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
var updateWireConfig = (config) => {
|
|
52
|
+
if (!globalWireConfig) {
|
|
53
|
+
throw new Error("Wire not initialized. Call initWire() first.");
|
|
54
|
+
}
|
|
55
|
+
globalWireConfig = {
|
|
56
|
+
...globalWireConfig,
|
|
57
|
+
...config,
|
|
58
|
+
headers: {
|
|
59
|
+
...globalWireConfig.headers,
|
|
60
|
+
...config.headers
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
var getWireConfig = () => {
|
|
65
|
+
if (!globalWireConfig) {
|
|
66
|
+
throw new Error("Wire not initialized. Call initWire() first.");
|
|
67
|
+
}
|
|
68
|
+
return globalWireConfig;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/core/wire.ts
|
|
72
|
+
async function wireApi(endpoint, options = {}) {
|
|
73
|
+
const config = getWireConfig();
|
|
74
|
+
const url = `${config.baseUrl}${endpoint}`;
|
|
75
|
+
const accessToken = await config.getToken();
|
|
76
|
+
const headers = {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
...accessToken ? { Authorization: `Bearer ${accessToken}` } : {},
|
|
79
|
+
...config.headers,
|
|
80
|
+
...options.headers
|
|
81
|
+
};
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(url, { ...options, headers });
|
|
84
|
+
if (!response.ok) {
|
|
85
|
+
let errorData;
|
|
86
|
+
try {
|
|
87
|
+
errorData = await response.json();
|
|
88
|
+
} catch {
|
|
89
|
+
errorData = { message: "Unknown server error", error: "UNKNOWN" };
|
|
90
|
+
}
|
|
91
|
+
const apiError = new ApiError(
|
|
92
|
+
errorData.message,
|
|
93
|
+
errorData.error,
|
|
94
|
+
response.status
|
|
95
|
+
);
|
|
96
|
+
const unauthorizedStatusCodes = config.unauthorizedStatusCodes && config.unauthorizedStatusCodes.length > 0 ? config.unauthorizedStatusCodes : [401];
|
|
97
|
+
const forbiddenStatusCodes = config.forbiddenStatusCodes && config.forbiddenStatusCodes.length > 0 ? config.forbiddenStatusCodes : [403];
|
|
98
|
+
if (config.interceptors?.onUnauthorized && unauthorizedStatusCodes.includes(response.status)) {
|
|
99
|
+
config.interceptors.onUnauthorized(apiError);
|
|
100
|
+
} else if (config.interceptors?.onForbidden && forbiddenStatusCodes.includes(response.status)) {
|
|
101
|
+
config.interceptors.onForbidden(apiError);
|
|
102
|
+
} else if (config.interceptors?.onError) {
|
|
103
|
+
config.interceptors.onError(apiError);
|
|
104
|
+
}
|
|
105
|
+
throw apiError;
|
|
106
|
+
}
|
|
107
|
+
return await response.json();
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error instanceof ApiError) throw error;
|
|
110
|
+
throw new ApiError(
|
|
111
|
+
error instanceof Error ? error.message : "Network error",
|
|
112
|
+
"NETWORK_ERROR",
|
|
113
|
+
520
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/hook/use-fetch-fn.ts
|
|
119
|
+
var import_react = require("react");
|
|
120
|
+
|
|
121
|
+
// src/core/event-emitter.ts
|
|
122
|
+
var EventEmitter = class {
|
|
123
|
+
constructor() {
|
|
124
|
+
this.events = {};
|
|
125
|
+
}
|
|
126
|
+
emit(event) {
|
|
127
|
+
if (!this.events[event]) return;
|
|
128
|
+
this.events[event].forEach((listener) => listener());
|
|
129
|
+
}
|
|
130
|
+
addListener(event, listener) {
|
|
131
|
+
if (!this.events[event]) {
|
|
132
|
+
this.events[event] = [];
|
|
133
|
+
}
|
|
134
|
+
this.events[event].push(listener);
|
|
135
|
+
return {
|
|
136
|
+
remove: () => {
|
|
137
|
+
this.events[event] = this.events[event].filter((l) => l !== listener);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var eventEmitter = new EventEmitter();
|
|
143
|
+
|
|
144
|
+
// src/hook/use-fetch-fn.ts
|
|
145
|
+
function useFetchFn(options) {
|
|
146
|
+
const [state, setState] = (0, import_react.useState)({
|
|
147
|
+
data: null,
|
|
148
|
+
isLoading: false,
|
|
149
|
+
isRefreshing: false,
|
|
150
|
+
error: null
|
|
151
|
+
});
|
|
152
|
+
const isMounted = (0, import_react.useRef)(true);
|
|
153
|
+
const lastFetchFn = (0, import_react.useRef)(null);
|
|
154
|
+
(0, import_react.useEffect)(() => {
|
|
155
|
+
isMounted.current = true;
|
|
156
|
+
return () => {
|
|
157
|
+
isMounted.current = false;
|
|
158
|
+
};
|
|
159
|
+
}, []);
|
|
160
|
+
const execute = (0, import_react.useCallback)(
|
|
161
|
+
async (fetchFn, execOptions) => {
|
|
162
|
+
lastFetchFn.current = fetchFn;
|
|
163
|
+
setState((prev) => ({
|
|
164
|
+
...prev,
|
|
165
|
+
isLoading: !execOptions.isRefresh,
|
|
166
|
+
isRefreshing: !!execOptions.isRefresh,
|
|
167
|
+
error: null
|
|
168
|
+
}));
|
|
169
|
+
try {
|
|
170
|
+
const response = await fetchFn();
|
|
171
|
+
if (isMounted.current) {
|
|
172
|
+
setState({
|
|
173
|
+
data: response.data || null,
|
|
174
|
+
isLoading: false,
|
|
175
|
+
isRefreshing: false,
|
|
176
|
+
error: null
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return response;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
const apiError = error;
|
|
182
|
+
if (isMounted.current) {
|
|
183
|
+
setState({
|
|
184
|
+
data: null,
|
|
185
|
+
isLoading: false,
|
|
186
|
+
isRefreshing: false,
|
|
187
|
+
error: apiError
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
[]
|
|
194
|
+
);
|
|
195
|
+
const executeFetchFn = (0, import_react.useCallback)(
|
|
196
|
+
(fetchFn) => {
|
|
197
|
+
return execute(fetchFn, { isRefresh: false });
|
|
198
|
+
},
|
|
199
|
+
[execute]
|
|
200
|
+
);
|
|
201
|
+
const refreshFetchFn = (0, import_react.useCallback)(() => {
|
|
202
|
+
if (lastFetchFn.current) {
|
|
203
|
+
return execute(lastFetchFn.current, { isRefresh: true });
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}, [execute]);
|
|
207
|
+
(0, import_react.useEffect)(() => {
|
|
208
|
+
if (!options?.tags || options.tags.length === 0) return;
|
|
209
|
+
const subscriptions = options.tags.map(
|
|
210
|
+
(tag) => eventEmitter.addListener(tag, () => {
|
|
211
|
+
refreshFetchFn();
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
return () => subscriptions.forEach((sub) => sub.remove());
|
|
215
|
+
}, [options?.tags, refreshFetchFn]);
|
|
216
|
+
return { ...state, executeFetchFn, refreshFetchFn };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/hook/use-mutation-fn.ts
|
|
220
|
+
var import_react2 = require("react");
|
|
221
|
+
function useMutationFn(options) {
|
|
222
|
+
const [state, setState] = (0, import_react2.useState)({
|
|
223
|
+
data: null,
|
|
224
|
+
isMutating: false
|
|
225
|
+
});
|
|
226
|
+
const isMounted = (0, import_react2.useRef)(true);
|
|
227
|
+
(0, import_react2.useEffect)(() => {
|
|
228
|
+
isMounted.current = true;
|
|
229
|
+
return () => {
|
|
230
|
+
isMounted.current = false;
|
|
231
|
+
};
|
|
232
|
+
}, []);
|
|
233
|
+
const executeMutationFn = (0, import_react2.useCallback)(
|
|
234
|
+
async (mutationFn, executeOptions) => {
|
|
235
|
+
setState((prev) => ({ ...prev, isMutating: true }));
|
|
236
|
+
try {
|
|
237
|
+
const response = await mutationFn();
|
|
238
|
+
if (isMounted.current) {
|
|
239
|
+
setState({
|
|
240
|
+
data: response.data || null,
|
|
241
|
+
isMutating: false
|
|
242
|
+
});
|
|
243
|
+
options?.invalidatesTags?.forEach((tag) => {
|
|
244
|
+
eventEmitter.emit(tag);
|
|
245
|
+
});
|
|
246
|
+
if (response.data) executeOptions?.onSuccess?.(response.data);
|
|
247
|
+
else executeOptions?.onSuccess?.(null);
|
|
248
|
+
}
|
|
249
|
+
return response;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
const apiError = error;
|
|
252
|
+
if (isMounted.current) {
|
|
253
|
+
setState({
|
|
254
|
+
data: null,
|
|
255
|
+
isMutating: false
|
|
256
|
+
});
|
|
257
|
+
if (apiError) executeOptions?.onError?.(apiError);
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
[options?.invalidatesTags]
|
|
263
|
+
);
|
|
264
|
+
const reset = (0, import_react2.useCallback)(() => {
|
|
265
|
+
setState({ data: null, isMutating: false });
|
|
266
|
+
}, []);
|
|
267
|
+
return { ...state, executeMutationFn, reset };
|
|
268
|
+
}
|
|
269
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
270
|
+
0 && (module.exports = {
|
|
271
|
+
ApiError,
|
|
272
|
+
getWireConfig,
|
|
273
|
+
initWire,
|
|
274
|
+
updateWireConfig,
|
|
275
|
+
useFetchFn,
|
|
276
|
+
useMutationFn,
|
|
277
|
+
wireApi
|
|
278
|
+
});
|
|
279
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|