@molecule/app-http 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 +115 -0
- package/dist/client.d.ts +99 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +9 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors.d.ts +27 -0
- package/dist/interceptors.d.ts.map +1 -0
- package/dist/interceptors.js +10 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/provider.d.ts +20 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +298 -0
- package/dist/provider.js.map +1 -0
- package/dist/types.d.ts +99 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +23 -0
- package/dist/types.js.map +1 -0
- package/dist/unwrap.d.ts +66 -0
- package/dist/unwrap.d.ts.map +1 -0
- package/dist/unwrap.js +221 -0
- package/dist/unwrap.js.map +1 -0
- package/dist/utilities.d.ts +79 -0
- package/dist/utilities.d.ts.map +1 -0
- package/dist/utilities.js +89 -0
- package/dist/utilities.js.map +1 -0
- package/package.json +52 -0
package/dist/provider.js
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client provider implementations.
|
|
3
|
+
*
|
|
4
|
+
* Contains concrete implementations of the HttpClient interface.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { t } from '@molecule/app-i18n';
|
|
9
|
+
import { getLogger } from '@molecule/app-logger';
|
|
10
|
+
import { HttpError } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Creates a fetch-based HTTP client using the native Fetch API.
|
|
13
|
+
*
|
|
14
|
+
* Supports request/response/error interceptors, automatic JSON
|
|
15
|
+
* serialization, auth token injection, timeout via AbortController,
|
|
16
|
+
* and 401 error handler hooks.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Client configuration including baseURL, default headers, timeout, and credentials.
|
|
19
|
+
* @returns A fully configured `HttpClient` instance.
|
|
20
|
+
*/
|
|
21
|
+
export const createFetchClient = (config = {}) => {
|
|
22
|
+
const logger = getLogger('http');
|
|
23
|
+
let authToken = null;
|
|
24
|
+
const requestInterceptors = [];
|
|
25
|
+
const responseInterceptors = [];
|
|
26
|
+
const errorInterceptors = [];
|
|
27
|
+
const authErrorHandlers = new Set();
|
|
28
|
+
// Track whether the document is currently navigating / unloading.
|
|
29
|
+
// Browser tears down in-flight fetch()es on navigation as
|
|
30
|
+
// `TypeError: Failed to fetch`, which is indistinguishable from a
|
|
31
|
+
// real outage at the catch site. The pagehide / beforeunload listeners
|
|
32
|
+
// give us a hint we can use to demote the log severity in that case
|
|
33
|
+
// without hiding genuine network failures.
|
|
34
|
+
let navigationInProgress = false;
|
|
35
|
+
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
|
|
36
|
+
const markNav = () => {
|
|
37
|
+
navigationInProgress = true;
|
|
38
|
+
// Auto-clear shortly after; if the navigation is real, the page
|
|
39
|
+
// will unload and we won't see anything else from this client
|
|
40
|
+
// anyway. If it's a same-page event, this lets us recover.
|
|
41
|
+
setTimeout(() => {
|
|
42
|
+
navigationInProgress = false;
|
|
43
|
+
}, 1000);
|
|
44
|
+
};
|
|
45
|
+
window.addEventListener('beforeunload', markNav);
|
|
46
|
+
window.addEventListener('pagehide', markNav);
|
|
47
|
+
}
|
|
48
|
+
const client = {
|
|
49
|
+
baseURL: config.baseURL || '',
|
|
50
|
+
defaultHeaders: config.defaultHeaders || {},
|
|
51
|
+
async request(requestConfig) {
|
|
52
|
+
// Apply request interceptors
|
|
53
|
+
let finalConfig = { ...requestConfig };
|
|
54
|
+
for (const interceptor of requestInterceptors) {
|
|
55
|
+
finalConfig = await interceptor(finalConfig);
|
|
56
|
+
}
|
|
57
|
+
// Build URL
|
|
58
|
+
let url = finalConfig.url;
|
|
59
|
+
if (client.baseURL && !url.startsWith('http://') && !url.startsWith('https://')) {
|
|
60
|
+
// Guard against double-prefixing: callers (e.g. @molecule/app-billing-react
|
|
61
|
+
// hooks) pass absolute `/api/...` paths whether or not a baseURL is bonded.
|
|
62
|
+
// If the URL already starts with the bonded baseURL, leave it alone.
|
|
63
|
+
const prefix = client.baseURL.endsWith('/') ? client.baseURL : client.baseURL + '/';
|
|
64
|
+
if (!url.startsWith(prefix) && url !== client.baseURL) {
|
|
65
|
+
url = client.baseURL + url;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Add query params
|
|
69
|
+
if (finalConfig.params) {
|
|
70
|
+
const params = new URLSearchParams();
|
|
71
|
+
for (const [key, value] of Object.entries(finalConfig.params)) {
|
|
72
|
+
if (value !== undefined) {
|
|
73
|
+
params.append(key, String(value));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const queryString = params.toString();
|
|
77
|
+
if (queryString) {
|
|
78
|
+
url += (url.includes('?') ? '&' : '?') + queryString;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Build headers
|
|
82
|
+
const headers = {
|
|
83
|
+
...client.defaultHeaders,
|
|
84
|
+
...finalConfig.headers,
|
|
85
|
+
};
|
|
86
|
+
// Add auth token
|
|
87
|
+
if (authToken) {
|
|
88
|
+
headers['Authorization'] = `Bearer ${authToken}`;
|
|
89
|
+
}
|
|
90
|
+
// Add content-type for JSON
|
|
91
|
+
if (finalConfig.data && !headers['Content-Type']) {
|
|
92
|
+
headers['Content-Type'] = 'application/json';
|
|
93
|
+
}
|
|
94
|
+
// Build fetch options
|
|
95
|
+
const fetchOptions = {
|
|
96
|
+
method: finalConfig.method,
|
|
97
|
+
headers,
|
|
98
|
+
credentials: (finalConfig.withCredentials ?? config.withCredentials) ? 'include' : 'same-origin',
|
|
99
|
+
signal: finalConfig.signal,
|
|
100
|
+
};
|
|
101
|
+
// Add body
|
|
102
|
+
if (finalConfig.data) {
|
|
103
|
+
if (finalConfig.data instanceof FormData || finalConfig.data instanceof Blob) {
|
|
104
|
+
fetchOptions.body = finalConfig.data;
|
|
105
|
+
// Remove Content-Type for FormData (browser sets it with boundary)
|
|
106
|
+
if (finalConfig.data instanceof FormData) {
|
|
107
|
+
delete headers['Content-Type'];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
fetchOptions.body = JSON.stringify(finalConfig.data);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Create abort controller for timeout
|
|
115
|
+
let timeoutId;
|
|
116
|
+
const timeout = finalConfig.timeout ?? config.timeout;
|
|
117
|
+
if (timeout && !finalConfig.signal) {
|
|
118
|
+
const controller = new AbortController();
|
|
119
|
+
fetchOptions.signal = controller.signal;
|
|
120
|
+
timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const fetchResponse = await fetch(url, fetchOptions);
|
|
124
|
+
if (timeoutId) {
|
|
125
|
+
clearTimeout(timeoutId);
|
|
126
|
+
}
|
|
127
|
+
// Parse response headers
|
|
128
|
+
const responseHeaders = {};
|
|
129
|
+
fetchResponse.headers.forEach((value, key) => {
|
|
130
|
+
responseHeaders[key] = value;
|
|
131
|
+
});
|
|
132
|
+
// Parse response body
|
|
133
|
+
let data;
|
|
134
|
+
const responseType = finalConfig.responseType || 'json';
|
|
135
|
+
switch (responseType) {
|
|
136
|
+
case 'text':
|
|
137
|
+
data = (await fetchResponse.text());
|
|
138
|
+
break;
|
|
139
|
+
case 'blob':
|
|
140
|
+
data = (await fetchResponse.blob());
|
|
141
|
+
break;
|
|
142
|
+
case 'arraybuffer':
|
|
143
|
+
data = (await fetchResponse.arrayBuffer());
|
|
144
|
+
break;
|
|
145
|
+
case 'json':
|
|
146
|
+
default: {
|
|
147
|
+
const text = await fetchResponse.text();
|
|
148
|
+
try {
|
|
149
|
+
data = text ? JSON.parse(text) : null;
|
|
150
|
+
}
|
|
151
|
+
catch (_error) {
|
|
152
|
+
// Safe to ignore: the raw text is already captured above and used
|
|
153
|
+
// as the fallback value. Non-JSON responses (plain text, HTML errors)
|
|
154
|
+
// are a known valid case for some APIs.
|
|
155
|
+
logger.debug('Response is not JSON, using raw text', url);
|
|
156
|
+
data = text;
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
let response = {
|
|
162
|
+
data,
|
|
163
|
+
status: fetchResponse.status,
|
|
164
|
+
statusText: fetchResponse.statusText,
|
|
165
|
+
headers: responseHeaders,
|
|
166
|
+
config: finalConfig,
|
|
167
|
+
};
|
|
168
|
+
// Handle error status codes
|
|
169
|
+
if (!fetchResponse.ok) {
|
|
170
|
+
logger.warn('HTTP error', finalConfig.method, url, fetchResponse.status);
|
|
171
|
+
const error = new HttpError(t('http.error.requestFailed', { status: fetchResponse.status }, { defaultValue: `Request failed with status ${fetchResponse.status}` }), fetchResponse.status, response, finalConfig, 'http.error.requestFailed');
|
|
172
|
+
// Handle auth errors
|
|
173
|
+
if (fetchResponse.status === 401) {
|
|
174
|
+
authErrorHandlers.forEach((handler) => handler());
|
|
175
|
+
}
|
|
176
|
+
// Apply error interceptors
|
|
177
|
+
let finalError = error;
|
|
178
|
+
for (const interceptor of errorInterceptors) {
|
|
179
|
+
finalError = await interceptor(finalError);
|
|
180
|
+
}
|
|
181
|
+
throw finalError;
|
|
182
|
+
}
|
|
183
|
+
// Apply response interceptors
|
|
184
|
+
for (const interceptor of responseInterceptors) {
|
|
185
|
+
response = (await interceptor(response));
|
|
186
|
+
}
|
|
187
|
+
return response;
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
if (timeoutId) {
|
|
191
|
+
clearTimeout(timeoutId);
|
|
192
|
+
}
|
|
193
|
+
if (err instanceof HttpError) {
|
|
194
|
+
throw err;
|
|
195
|
+
}
|
|
196
|
+
// Distinguish an explicit abort (AbortController, page unload
|
|
197
|
+
// wired up via signal) and SPA navigation-induced cancellation
|
|
198
|
+
// from a real network outage.
|
|
199
|
+
//
|
|
200
|
+
// - AbortError → user-initiated cancel: silent
|
|
201
|
+
// - "TypeError: Failed to fetch" while the browser tab is
|
|
202
|
+
// hidden / unloading → SPA tore down a fetch as it left the
|
|
203
|
+
// page. Demote to warn so it stays visible in the console
|
|
204
|
+
// for debugging but doesn't fail strict console-error gates.
|
|
205
|
+
// - Anything else (including "Failed to fetch" while the tab
|
|
206
|
+
// is visible) → real outage: logger.error.
|
|
207
|
+
//
|
|
208
|
+
// Components that want zero navigation noise should still pass
|
|
209
|
+
// an AbortSignal from their useEffect cleanup.
|
|
210
|
+
const errMsg = err instanceof Error ? err.message : '';
|
|
211
|
+
const errName = err instanceof Error ? err.name : '';
|
|
212
|
+
const isAbort = errName === 'AbortError' ||
|
|
213
|
+
(typeof DOMException !== 'undefined' &&
|
|
214
|
+
err instanceof DOMException &&
|
|
215
|
+
err.name === 'AbortError') ||
|
|
216
|
+
/the user aborted a request/i.test(errMsg);
|
|
217
|
+
const tabHidden = typeof document !== 'undefined' &&
|
|
218
|
+
(document.visibilityState === 'hidden' || document.hidden === true);
|
|
219
|
+
const isNavCancel = !isAbort &&
|
|
220
|
+
errName === 'TypeError' &&
|
|
221
|
+
/failed to fetch|network ?error|load failed/i.test(errMsg) &&
|
|
222
|
+
(tabHidden || navigationInProgress);
|
|
223
|
+
if (isAbort) {
|
|
224
|
+
// silent — not interesting
|
|
225
|
+
}
|
|
226
|
+
else if (isNavCancel) {
|
|
227
|
+
logger.warn('Network request cancelled by navigation', finalConfig.method, url);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
logger.error('Network error', finalConfig.method, url, err);
|
|
231
|
+
}
|
|
232
|
+
const error = new HttpError(err instanceof Error
|
|
233
|
+
? err.message
|
|
234
|
+
: t('http.error.networkError', undefined, { defaultValue: 'Network error' }), 0, undefined, finalConfig, 'http.error.networkError');
|
|
235
|
+
// Apply error interceptors
|
|
236
|
+
let finalError = error;
|
|
237
|
+
for (const interceptor of errorInterceptors) {
|
|
238
|
+
finalError = await interceptor(finalError);
|
|
239
|
+
}
|
|
240
|
+
throw finalError;
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
get(url, requestConfig) {
|
|
244
|
+
return client.request({ ...requestConfig, method: 'GET', url });
|
|
245
|
+
},
|
|
246
|
+
post(url, data, requestConfig) {
|
|
247
|
+
return client.request({ ...requestConfig, method: 'POST', url, data });
|
|
248
|
+
},
|
|
249
|
+
put(url, data, requestConfig) {
|
|
250
|
+
return client.request({ ...requestConfig, method: 'PUT', url, data });
|
|
251
|
+
},
|
|
252
|
+
patch(url, data, requestConfig) {
|
|
253
|
+
return client.request({ ...requestConfig, method: 'PATCH', url, data });
|
|
254
|
+
},
|
|
255
|
+
delete(url, requestConfig) {
|
|
256
|
+
return client.request({ ...requestConfig, method: 'DELETE', url });
|
|
257
|
+
},
|
|
258
|
+
addRequestInterceptor(interceptor) {
|
|
259
|
+
requestInterceptors.push(interceptor);
|
|
260
|
+
return () => {
|
|
261
|
+
const index = requestInterceptors.indexOf(interceptor);
|
|
262
|
+
if (index !== -1) {
|
|
263
|
+
requestInterceptors.splice(index, 1);
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
addResponseInterceptor(interceptor) {
|
|
268
|
+
responseInterceptors.push(interceptor);
|
|
269
|
+
return () => {
|
|
270
|
+
const index = responseInterceptors.indexOf(interceptor);
|
|
271
|
+
if (index !== -1) {
|
|
272
|
+
responseInterceptors.splice(index, 1);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
},
|
|
276
|
+
addErrorInterceptor(interceptor) {
|
|
277
|
+
errorInterceptors.push(interceptor);
|
|
278
|
+
return () => {
|
|
279
|
+
const index = errorInterceptors.indexOf(interceptor);
|
|
280
|
+
if (index !== -1) {
|
|
281
|
+
errorInterceptors.splice(index, 1);
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
setAuthToken(token) {
|
|
286
|
+
authToken = token;
|
|
287
|
+
},
|
|
288
|
+
getAuthToken() {
|
|
289
|
+
return authToken;
|
|
290
|
+
},
|
|
291
|
+
onAuthError(handler) {
|
|
292
|
+
authErrorHandlers.add(handler);
|
|
293
|
+
return () => authErrorHandlers.delete(handler);
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
return client;
|
|
297
|
+
};
|
|
298
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAKhD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAA2B,EAAE,EAAc,EAAE;IAC7E,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;IAChC,IAAI,SAAS,GAAkB,IAAI,CAAA;IACnC,MAAM,mBAAmB,GAAyB,EAAE,CAAA;IACpD,MAAM,oBAAoB,GAA0B,EAAE,CAAA;IACtD,MAAM,iBAAiB,GAAuB,EAAE,CAAA;IAChD,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAc,CAAA;IAE/C,kEAAkE;IAClE,0DAA0D;IAC1D,kEAAkE;IAClE,uEAAuE;IACvE,oEAAoE;IACpE,2CAA2C;IAC3C,IAAI,oBAAoB,GAAG,KAAK,CAAA;IAChC,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACnF,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,oBAAoB,GAAG,IAAI,CAAA;YAC3B,gEAAgE;YAChE,8DAA8D;YAC9D,2DAA2D;YAC3D,UAAU,CAAC,GAAG,EAAE;gBACd,oBAAoB,GAAG,KAAK,CAAA;YAC9B,CAAC,EAAE,IAAI,CAAC,CAAA;QACV,CAAC,CAAA;QACD,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;QAChD,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IAC9C,CAAC;IAED,MAAM,MAAM,GAAe;QACzB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;QAC7B,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,EAAE;QAE3C,KAAK,CAAC,OAAO,CAAc,aAAgC;YACzD,6BAA6B;YAC7B,IAAI,WAAW,GAAG,EAAE,GAAG,aAAa,EAAE,CAAA;YACtC,KAAK,MAAM,WAAW,IAAI,mBAAmB,EAAE,CAAC;gBAC9C,WAAW,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAA;YAC9C,CAAC;YAED,YAAY;YACZ,IAAI,GAAG,GAAG,WAAW,CAAC,GAAG,CAAA;YACzB,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAChF,4EAA4E;gBAC5E,4EAA4E;gBAC5E,qEAAqE;gBACrE,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,GAAG,CAAA;gBACnF,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,GAAG,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC;oBACtD,GAAG,GAAG,MAAM,CAAC,OAAO,GAAG,GAAG,CAAA;gBAC5B,CAAC;YACH,CAAC;YAED,mBAAmB;YACnB,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;gBACvB,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;gBACpC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC9D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;wBACxB,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;oBACnC,CAAC;gBACH,CAAC;gBACD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAA;gBACrC,IAAI,WAAW,EAAE,CAAC;oBAChB,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,WAAW,CAAA;gBACtD,CAAC;YACH,CAAC;YAED,gBAAgB;YAChB,MAAM,OAAO,GAA2B;gBACtC,GAAG,MAAM,CAAC,cAAc;gBACxB,GAAG,WAAW,CAAC,OAAO;aACvB,CAAA;YAED,iBAAiB;YACjB,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,SAAS,EAAE,CAAA;YAClD,CAAC;YAED,4BAA4B;YAC5B,IAAI,WAAW,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;gBACjD,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAA;YAC9C,CAAC;YAED,sBAAsB;YACtB,MAAM,YAAY,GAAgB;gBAChC,MAAM,EAAE,WAAW,CAAC,MAAM;gBAC1B,OAAO;gBACP,WAAW,EACT,CAAC,WAAW,CAAC,eAAe,IAAI,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa;gBACrF,MAAM,EAAE,WAAW,CAAC,MAAM;aAC3B,CAAA;YAED,WAAW;YACX,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;gBACrB,IAAI,WAAW,CAAC,IAAI,YAAY,QAAQ,IAAI,WAAW,CAAC,IAAI,YAAY,IAAI,EAAE,CAAC;oBAC7E,YAAY,CAAC,IAAI,GAAG,WAAW,CAAC,IAAgB,CAAA;oBAChD,mEAAmE;oBACnE,IAAI,WAAW,CAAC,IAAI,YAAY,QAAQ,EAAE,CAAC;wBACzC,OAAO,OAAO,CAAC,cAAc,CAAC,CAAA;oBAChC,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;gBACtD,CAAC;YACH,CAAC;YAED,sCAAsC;YACtC,IAAI,SAAoD,CAAA;YACxD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAA;YACrD,IAAI,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;gBACnC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;gBACxC,YAAY,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAA;gBACvC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;YAC3D,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;gBAEpD,IAAI,SAAS,EAAE,CAAC;oBACd,YAAY,CAAC,SAAS,CAAC,CAAA;gBACzB,CAAC;gBAED,yBAAyB;gBACzB,MAAM,eAAe,GAA2B,EAAE,CAAA;gBAClD,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;oBAC3C,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;gBAC9B,CAAC,CAAC,CAAA;gBAEF,sBAAsB;gBACtB,IAAI,IAAO,CAAA;gBACX,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,IAAI,MAAM,CAAA;gBAEvD,QAAQ,YAAY,EAAE,CAAC;oBACrB,KAAK,MAAM;wBACT,IAAI,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAAM,CAAA;wBACxC,MAAK;oBACP,KAAK,MAAM;wBACT,IAAI,GAAG,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,CAAM,CAAA;wBACxC,MAAK;oBACP,KAAK,aAAa;wBAChB,IAAI,GAAG,CAAC,MAAM,aAAa,CAAC,WAAW,EAAE,CAAM,CAAA;wBAC/C,MAAK;oBACP,KAAK,MAAM,CAAC;oBACZ,OAAO,CAAC,CAAC,CAAC;wBACR,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAA;wBACvC,IAAI,CAAC;4BACH,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;wBACvC,CAAC;wBAAC,OAAO,MAAM,EAAE,CAAC;4BAChB,kEAAkE;4BAClE,sEAAsE;4BACtE,wCAAwC;4BACxC,MAAM,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAA;4BACzD,IAAI,GAAG,IAAS,CAAA;wBAClB,CAAC;wBACD,MAAK;oBACP,CAAC;gBACH,CAAC;gBAED,IAAI,QAAQ,GAAoB;oBAC9B,IAAI;oBACJ,MAAM,EAAE,aAAa,CAAC,MAAM;oBAC5B,UAAU,EAAE,aAAa,CAAC,UAAU;oBACpC,OAAO,EAAE,eAAe;oBACxB,MAAM,EAAE,WAAW;iBACpB,CAAA;gBAED,4BAA4B;gBAC5B,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;oBACtB,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;oBACxE,MAAM,KAAK,GAAG,IAAI,SAAS,CACzB,CAAC,CACC,0BAA0B,EAC1B,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,EAAE,EAChC,EAAE,YAAY,EAAE,8BAA8B,aAAa,CAAC,MAAM,EAAE,EAAE,CACvE,EACD,aAAa,CAAC,MAAM,EACpB,QAAQ,EACR,WAAW,EACX,0BAA0B,CAC3B,CAAA;oBAED,qBAAqB;oBACrB,IAAI,aAAa,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;wBACjC,iBAAiB,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAA;oBACnD,CAAC;oBAED,2BAA2B;oBAC3B,IAAI,UAAU,GAAG,KAAK,CAAA;oBACtB,KAAK,MAAM,WAAW,IAAI,iBAAiB,EAAE,CAAC;wBAC5C,UAAU,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAA;oBAC5C,CAAC;oBAED,MAAM,UAAU,CAAA;gBAClB,CAAC;gBAED,8BAA8B;gBAC9B,KAAK,MAAM,WAAW,IAAI,oBAAoB,EAAE,CAAC;oBAC/C,QAAQ,GAAG,CAAC,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAoB,CAAA;gBAC7D,CAAC;gBAED,OAAO,QAAQ,CAAA;YACjB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,SAAS,EAAE,CAAC;oBACd,YAAY,CAAC,SAAS,CAAC,CAAA;gBACzB,CAAC;gBAED,IAAI,GAAG,YAAY,SAAS,EAAE,CAAC;oBAC7B,MAAM,GAAG,CAAA;gBACX,CAAC;gBAED,8DAA8D;gBAC9D,+DAA+D;gBAC/D,8BAA8B;gBAC9B,EAAE;gBACF,gDAAgD;gBAChD,2DAA2D;gBAC3D,+DAA+D;gBAC/D,6DAA6D;gBAC7D,gEAAgE;gBAChE,8DAA8D;gBAC9D,8CAA8C;gBAC9C,EAAE;gBACF,+DAA+D;gBAC/D,+CAA+C;gBAC/C,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAA;gBACtD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;gBACpD,MAAM,OAAO,GACX,OAAO,KAAK,YAAY;oBACxB,CAAC,OAAO,YAAY,KAAK,WAAW;wBAClC,GAAG,YAAY,YAAY;wBAC3B,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC;oBAC5B,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBAE5C,MAAM,SAAS,GACb,OAAO,QAAQ,KAAK,WAAW;oBAC/B,CAAC,QAAQ,CAAC,eAAe,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,CAAA;gBACrE,MAAM,WAAW,GACf,CAAC,OAAO;oBACR,OAAO,KAAK,WAAW;oBACvB,6CAA6C,CAAC,IAAI,CAAC,MAAM,CAAC;oBAC1D,CAAC,SAAS,IAAI,oBAAoB,CAAC,CAAA;gBAErC,IAAI,OAAO,EAAE,CAAC;oBACZ,2BAA2B;gBAC7B,CAAC;qBAAM,IAAI,WAAW,EAAE,CAAC;oBACvB,MAAM,CAAC,IAAI,CAAC,yCAAyC,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;gBACjF,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;gBAC7D,CAAC;gBACD,MAAM,KAAK,GAAG,IAAI,SAAS,CACzB,GAAG,YAAY,KAAK;oBAClB,CAAC,CAAC,GAAG,CAAC,OAAO;oBACb,CAAC,CAAC,CAAC,CAAC,yBAAyB,EAAE,SAAS,EAAE,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC,EAC9E,CAAC,EACD,SAAS,EACT,WAAW,EACX,yBAAyB,CAC1B,CAAA;gBAED,2BAA2B;gBAC3B,IAAI,UAAU,GAAG,KAAK,CAAA;gBACtB,KAAK,MAAM,WAAW,IAAI,iBAAiB,EAAE,CAAC;oBAC5C,UAAU,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAA;gBAC5C,CAAC;gBAED,MAAM,UAAU,CAAA;YAClB,CAAC;QACH,CAAC;QAED,GAAG,CAAc,GAAW,EAAE,aAA6B;YACzD,OAAO,MAAM,CAAC,OAAO,CAAI,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAA;QACpE,CAAC;QAED,IAAI,CACF,GAAW,EACX,IAAc,EACd,aAA6B;YAE7B,OAAO,MAAM,CAAC,OAAO,CAAI,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAA;QAC3E,CAAC;QAED,GAAG,CACD,GAAW,EACX,IAAc,EACd,aAA6B;YAE7B,OAAO,MAAM,CAAC,OAAO,CAAI,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAA;QAC1E,CAAC;QAED,KAAK,CACH,GAAW,EACX,IAAc,EACd,aAA6B;YAE7B,OAAO,MAAM,CAAC,OAAO,CAAI,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAA;QAC5E,CAAC;QAED,MAAM,CAAc,GAAW,EAAE,aAA6B;YAC5D,OAAO,MAAM,CAAC,OAAO,CAAI,EAAE,GAAG,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAA;QACvE,CAAC;QAED,qBAAqB,CAAC,WAA+B;YACnD,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACrC,OAAO,GAAG,EAAE;gBACV,MAAM,KAAK,GAAG,mBAAmB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;gBACtD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBACjB,mBAAmB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;gBACtC,CAAC;YACH,CAAC,CAAA;QACH,CAAC;QAED,sBAAsB,CAAC,WAAgC;YACrD,oBAAoB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACtC,OAAO,GAAG,EAAE;gBACV,MAAM,KAAK,GAAG,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;gBACvD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBACjB,oBAAoB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;gBACvC,CAAC;YACH,CAAC,CAAA;QACH,CAAC;QAED,mBAAmB,CAAC,WAA6B;YAC/C,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACnC,OAAO,GAAG,EAAE;gBACV,MAAM,KAAK,GAAG,iBAAiB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;gBACpD,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;oBACjB,iBAAiB,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;gBACpC,CAAC;YACH,CAAC,CAAA;QACH,CAAC;QAED,YAAY,CAAC,KAAoB;YAC/B,SAAS,GAAG,KAAK,CAAA;QACnB,CAAC;QAED,YAAY;YACV,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,WAAW,CAAC,OAAmB;YAC7B,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC9B,OAAO,GAAG,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;QAChD,CAAC;KACF,CAAA;IAED,OAAO,MAAM,CAAA;AACf,CAAC,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for the HTTP client.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* HTTP request method.
|
|
8
|
+
*/
|
|
9
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
10
|
+
/**
|
|
11
|
+
* HTTP request options (headers, query params, timeout, credentials, response type, abort signal).
|
|
12
|
+
*/
|
|
13
|
+
export interface RequestConfig {
|
|
14
|
+
/**
|
|
15
|
+
* Request headers.
|
|
16
|
+
*/
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Query parameters.
|
|
20
|
+
*/
|
|
21
|
+
params?: Record<string, string | number | boolean | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Request timeout in milliseconds.
|
|
24
|
+
*/
|
|
25
|
+
timeout?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Whether to include credentials (cookies).
|
|
28
|
+
*/
|
|
29
|
+
withCredentials?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Response type.
|
|
32
|
+
*/
|
|
33
|
+
responseType?: 'json' | 'text' | 'blob' | 'arraybuffer';
|
|
34
|
+
/**
|
|
35
|
+
* Abort signal for cancellation.
|
|
36
|
+
*/
|
|
37
|
+
signal?: AbortSignal;
|
|
38
|
+
/**
|
|
39
|
+
* Request body data.
|
|
40
|
+
*/
|
|
41
|
+
data?: unknown;
|
|
42
|
+
/**
|
|
43
|
+
* Custom request options (implementation-specific).
|
|
44
|
+
*/
|
|
45
|
+
options?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Full request configuration including method and URL.
|
|
49
|
+
*/
|
|
50
|
+
export interface FullRequestConfig extends RequestConfig {
|
|
51
|
+
/**
|
|
52
|
+
* HTTP method.
|
|
53
|
+
*/
|
|
54
|
+
method: HttpMethod;
|
|
55
|
+
/**
|
|
56
|
+
* Request URL (can be relative or absolute).
|
|
57
|
+
*/
|
|
58
|
+
url: string;
|
|
59
|
+
/**
|
|
60
|
+
* Request body data.
|
|
61
|
+
*/
|
|
62
|
+
data?: unknown;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parsed HTTP response with status code, headers, and typed body data.
|
|
66
|
+
*/
|
|
67
|
+
export interface HttpResponse<T = unknown> {
|
|
68
|
+
/**
|
|
69
|
+
* Response data.
|
|
70
|
+
*/
|
|
71
|
+
data: T;
|
|
72
|
+
/**
|
|
73
|
+
* HTTP status code.
|
|
74
|
+
*/
|
|
75
|
+
status: number;
|
|
76
|
+
/**
|
|
77
|
+
* HTTP status text.
|
|
78
|
+
*/
|
|
79
|
+
statusText: string;
|
|
80
|
+
/**
|
|
81
|
+
* Response headers.
|
|
82
|
+
*/
|
|
83
|
+
headers: Record<string, string>;
|
|
84
|
+
/**
|
|
85
|
+
* Original request config.
|
|
86
|
+
*/
|
|
87
|
+
config: FullRequestConfig;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* HTTP error with response details.
|
|
91
|
+
*/
|
|
92
|
+
export declare class HttpError extends Error {
|
|
93
|
+
status: number;
|
|
94
|
+
response?: HttpResponse | undefined;
|
|
95
|
+
config?: FullRequestConfig | undefined;
|
|
96
|
+
errorKey?: string | undefined;
|
|
97
|
+
constructor(message: string, status: number, response?: HttpResponse | undefined, config?: FullRequestConfig | undefined, errorKey?: string | undefined);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;AAEzF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;IAE9D;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,aAAa,CAAA;IAEvD;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;IAEpB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD;;OAEG;IACH,MAAM,EAAE,UAAU,CAAA;IAElB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IAEX;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC;;OAEG;IACH,IAAI,EAAE,CAAC,CAAA;IAEP;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE/B;;OAEG;IACH,MAAM,EAAE,iBAAiB,CAAA;CAC1B;AAED;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAGzB,MAAM,EAAE,MAAM;IACd,QAAQ,CAAC,EAAE,YAAY;IACvB,MAAM,CAAC,EAAE,iBAAiB;IAC1B,QAAQ,CAAC,EAAE,MAAM;gBAJxB,OAAO,EAAE,MAAM,EACR,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,YAAY,YAAA,EACvB,MAAM,CAAC,EAAE,iBAAiB,YAAA,EAC1B,QAAQ,CAAC,EAAE,MAAM,YAAA;CAK3B"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core type definitions for the HTTP client.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* HTTP error with response details.
|
|
8
|
+
*/
|
|
9
|
+
export class HttpError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
response;
|
|
12
|
+
config;
|
|
13
|
+
errorKey;
|
|
14
|
+
constructor(message, status, response, config, errorKey) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.status = status;
|
|
17
|
+
this.response = response;
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.errorKey = errorKey;
|
|
20
|
+
this.name = 'HttpError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsGH;;GAEG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGzB;IACA;IACA;IACA;IALT,YACE,OAAe,EACR,MAAc,EACd,QAAuB,EACvB,MAA0B,EAC1B,QAAiB;QAExB,KAAK,CAAC,OAAO,CAAC,CAAA;QALP,WAAM,GAAN,MAAM,CAAQ;QACd,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAoB;QAC1B,aAAQ,GAAR,QAAQ,CAAS;QAGxB,IAAI,CAAC,IAAI,GAAG,WAAW,CAAA;IACzB,CAAC;CACF"}
|
package/dist/unwrap.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response-envelope unwrappers.
|
|
3
|
+
*
|
|
4
|
+
* Apps and mock servers commonly return either a bare value (`T` or
|
|
5
|
+
* `T[]`) or an envelope `{ data: T }` / `{ data: T[] }`. These helpers
|
|
6
|
+
* normalize either shape into a predictable `T[]` or `T | null` for
|
|
7
|
+
* downstream code, eliminating the per-call `'data' in res ? ...` dance.
|
|
8
|
+
*
|
|
9
|
+
* Lifted out of the 59 apps that previously carried a local
|
|
10
|
+
* `lib/unwrap.ts` copy. The two functions cover the response shapes used
|
|
11
|
+
* by the molecule mock server and the typical resource routes — a bare
|
|
12
|
+
* value, a `{ data }` envelope, and (for lists) the RICH pagination
|
|
13
|
+
* envelope `{ data, total, limit, offset }` returned by the pre-built
|
|
14
|
+
* `@molecule/api-resource-*` list endpoints (comment, review,
|
|
15
|
+
* activity-feed, bookmark, …). Other bespoke envelopes are out of scope
|
|
16
|
+
* — handle those in the caller.
|
|
17
|
+
*
|
|
18
|
+
* @module
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Normalize an unknown response body into a typed array.
|
|
22
|
+
*
|
|
23
|
+
* Accepts:
|
|
24
|
+
* - a bare array → returned as-is (cast)
|
|
25
|
+
* - `{ data: T[] }` envelope → the inner array
|
|
26
|
+
* - `HttpResponse<T[]>` (i.e. `{ data: T[], status, ... }`) → the inner array
|
|
27
|
+
* - `HttpResponse<{ data: T[] }>` (the response of an envelope-returning
|
|
28
|
+
* endpoint as it arrives from `@molecule/app-http`'s `HttpClient`) → the
|
|
29
|
+
* doubly-nested inner array
|
|
30
|
+
* - `HttpResponse<{ data: T[], total, limit, offset }>` (a RICH pagination
|
|
31
|
+
* envelope from a pre-built `@molecule/api-resource-*` list endpoint) → the
|
|
32
|
+
* inner `data` array (the numeric `total`/`limit`/`offset` make the shape
|
|
33
|
+
* unambiguous, so callers can pass the whole HttpResponse and still get the rows)
|
|
34
|
+
* - anything else → `[]`
|
|
35
|
+
*
|
|
36
|
+
* Callers commonly pass either the raw JSON body (e.g. from `fetch().then(r =>
|
|
37
|
+
* r.json())`) or the `HttpResponse` returned by `useHttpClient().get(...)`.
|
|
38
|
+
* Both shapes are handled here so pages don't have to remember to call
|
|
39
|
+
* `unwrapList(res.data)` vs `unwrapList(res)`.
|
|
40
|
+
*
|
|
41
|
+
* @param res - Raw response body OR an `HttpResponse` envelope from `@molecule/app-http`.
|
|
42
|
+
* @returns A typed array `T[]`; never `null`/`undefined`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function unwrapList<T>(res: unknown): T[];
|
|
45
|
+
/**
|
|
46
|
+
* Normalize an unknown response body into a single typed resource.
|
|
47
|
+
*
|
|
48
|
+
* Accepts:
|
|
49
|
+
* - a non-empty plain object → returned as-is (cast)
|
|
50
|
+
* - `{ data: T }` envelope → the inner value
|
|
51
|
+
* - `{ data: null }`, `{ data: undefined }`, `{ data: [] }`, or
|
|
52
|
+
* `{ data: {} }` (mock-server's no-match shape) → `null`
|
|
53
|
+
* - an empty object `{}` → `null`
|
|
54
|
+
* - arrays, primitives, `null`, `undefined` → `null`
|
|
55
|
+
*
|
|
56
|
+
* The "envelope contains an array → null" branch handles the case
|
|
57
|
+
* where the mock server returns `[]` for unmatched endpoints but the
|
|
58
|
+
* caller expects a single resource.
|
|
59
|
+
*
|
|
60
|
+
* @param res - Raw response body (e.g. `HttpResponse.data` from `@molecule/app-http`).
|
|
61
|
+
* @returns The typed resource `T`, or `null` when the response shape
|
|
62
|
+
* indicates "no resource" (including the various empty envelopes
|
|
63
|
+
* above).
|
|
64
|
+
*/
|
|
65
|
+
export declare function unwrapSingle<T>(res: unknown): T | null;
|
|
66
|
+
//# sourceMappingURL=unwrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unwrap.d.ts","sourceRoot":"","sources":["../src/unwrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,EAAE,CAmC/C;AAyED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAmDtD"}
|