@hashrytech/quick-components-kit 0.19.10 → 0.19.11
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/CHANGELOG.md +6 -0
- package/dist/modules/fetch-client.d.ts +20 -3
- package/dist/modules/fetch-client.js +37 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -63,9 +63,9 @@ export declare class FetchError extends Error {
|
|
|
63
63
|
constructor(message: string, status: number, json?: object);
|
|
64
64
|
}
|
|
65
65
|
export interface FetchClientEvents {
|
|
66
|
-
onRequest?: (request: Request) => void;
|
|
67
|
-
onResponse?: (response: Response) => void;
|
|
68
|
-
onError?: (error: Error) => void;
|
|
66
|
+
onRequest?: (request: Request) => Promise<void> | void;
|
|
67
|
+
onResponse?: (response: Response) => Promise<void> | void;
|
|
68
|
+
onError?: (error: Error) => Promise<void> | void;
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
71
71
|
* A generic REST API client.
|
|
@@ -126,6 +126,23 @@ export declare class FetchClient {
|
|
|
126
126
|
*/
|
|
127
127
|
addErrorHandler(handler: ErrorHandler): void;
|
|
128
128
|
setEventHooks(events: Partial<FetchClientEvents>): void;
|
|
129
|
+
/**
|
|
130
|
+
* Emits a typed event to a single-argument handler (if registered).
|
|
131
|
+
*
|
|
132
|
+
* Why `Parameters<...>[0]`?
|
|
133
|
+
* - `FetchClientEvents[K]` is a function type (or undefined). `NonNullable<>` removes `undefined`.
|
|
134
|
+
* - `Parameters<F>[0]` extracts the first parameter type of that function.
|
|
135
|
+
* - This keeps the arg type in sync with your `FetchClientEvents` definition.
|
|
136
|
+
*
|
|
137
|
+
* Notes:
|
|
138
|
+
* - This variant assumes each event handler accepts exactly one argument.
|
|
139
|
+
* - Handlers may be sync or async; both are awaited via `Promise.resolve(...)`.
|
|
140
|
+
* - Errors thrown by a handler are caught and logged so they don't break the request flow.
|
|
141
|
+
*
|
|
142
|
+
* If you later need multiple args per event, prefer a tuple map approach
|
|
143
|
+
* (e.g. `type EventArgsMap = { onRequest: [Request]; ... }`) to keep spreads type-safe.
|
|
144
|
+
*/
|
|
145
|
+
private emit;
|
|
129
146
|
/**
|
|
130
147
|
* Processes the request, applying default headers, auth token, and request interceptors.
|
|
131
148
|
* @param endpoint - The API endpoint (e.g., '/products', '/users/123').
|
|
@@ -49,6 +49,7 @@ export class FetchClient {
|
|
|
49
49
|
this.defaultHeaders = config.defaultHeaders || { 'Content-Type': 'application/json' };
|
|
50
50
|
this.autoRedirects = config.autoRedirects || [];
|
|
51
51
|
this.debug = config.debug || false;
|
|
52
|
+
this.events = config.events ?? {};
|
|
52
53
|
}
|
|
53
54
|
/**
|
|
54
55
|
* Sets the Bearer token for client-side requests.
|
|
@@ -90,6 +91,34 @@ export class FetchClient {
|
|
|
90
91
|
setEventHooks(events) {
|
|
91
92
|
Object.assign(this.events, events);
|
|
92
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Emits a typed event to a single-argument handler (if registered).
|
|
96
|
+
*
|
|
97
|
+
* Why `Parameters<...>[0]`?
|
|
98
|
+
* - `FetchClientEvents[K]` is a function type (or undefined). `NonNullable<>` removes `undefined`.
|
|
99
|
+
* - `Parameters<F>[0]` extracts the first parameter type of that function.
|
|
100
|
+
* - This keeps the arg type in sync with your `FetchClientEvents` definition.
|
|
101
|
+
*
|
|
102
|
+
* Notes:
|
|
103
|
+
* - This variant assumes each event handler accepts exactly one argument.
|
|
104
|
+
* - Handlers may be sync or async; both are awaited via `Promise.resolve(...)`.
|
|
105
|
+
* - Errors thrown by a handler are caught and logged so they don't break the request flow.
|
|
106
|
+
*
|
|
107
|
+
* If you later need multiple args per event, prefer a tuple map approach
|
|
108
|
+
* (e.g. `type EventArgsMap = { onRequest: [Request]; ... }`) to keep spreads type-safe.
|
|
109
|
+
*/
|
|
110
|
+
async emit(name, arg) {
|
|
111
|
+
const handler = this.events[name];
|
|
112
|
+
if (!handler)
|
|
113
|
+
return;
|
|
114
|
+
try {
|
|
115
|
+
await Promise.resolve(handler(arg));
|
|
116
|
+
}
|
|
117
|
+
catch (e) {
|
|
118
|
+
if (this.debug)
|
|
119
|
+
console.warn(`FetchClient ${String(name)} handler threw`, e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
93
122
|
/**
|
|
94
123
|
* Processes the request, applying default headers, auth token, and request interceptors.
|
|
95
124
|
* @param endpoint - The API endpoint (e.g., '/products', '/users/123').
|
|
@@ -149,6 +178,8 @@ export class FetchClient {
|
|
|
149
178
|
for (const interceptor of this.requestInterceptors) {
|
|
150
179
|
request = await Promise.resolve(interceptor(request));
|
|
151
180
|
}
|
|
181
|
+
//this.events.onRequest?.(request);
|
|
182
|
+
await this.emit('onRequest', request.clone());
|
|
152
183
|
return request;
|
|
153
184
|
}
|
|
154
185
|
/**
|
|
@@ -236,6 +267,8 @@ export class FetchClient {
|
|
|
236
267
|
try {
|
|
237
268
|
const request = await this.processRequest(endpoint, method, body, options);
|
|
238
269
|
const response = await currentFetch(request);
|
|
270
|
+
//this.events.onResponse?.(response.clone());
|
|
271
|
+
await this.emit('onResponse', response.clone());
|
|
239
272
|
const parsed = await this.processResponse(response, options);
|
|
240
273
|
return {
|
|
241
274
|
ok: true,
|
|
@@ -246,11 +279,14 @@ export class FetchClient {
|
|
|
246
279
|
catch (error) {
|
|
247
280
|
if (this.debug)
|
|
248
281
|
console.debug(`Fetch Client: Error occurred while processing request to ${endpoint} with method ${method}`, error);
|
|
249
|
-
|
|
282
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
283
|
+
await this.emit('onError', err);
|
|
284
|
+
//this.events.onError?.(err);
|
|
250
285
|
const isApiError = error instanceof FetchError;
|
|
251
286
|
const status = isApiError ? error.status : 503; // Service Unavailable fallback
|
|
252
287
|
const message = error instanceof Error ? error.message : 'Unexpected error occurred';
|
|
253
288
|
const errorObj = isApiError && error.json ? error.json : getProblemDetail({ status, title: "Server fetch error", type: "/exceptions/fetch-error/", detail: message });
|
|
289
|
+
await this.handleError(errorObj);
|
|
254
290
|
//const errorObj = status != 503 ? message : getProblemDetail({status, title: "Server fetch error", type: "/exceptions/fetch-error/", detail: "Error fetching data from API", server: message });
|
|
255
291
|
this.evaluateRedirect(errorObj, status);
|
|
256
292
|
return {
|