@faasjs/react 8.0.0-beta.23 → 8.0.0-beta.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +151 -87
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1318,7 +1318,7 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, {
|
|
|
1318
1318
|
/**
|
|
1319
1319
|
* Render children or the configured fallback for the captured error.
|
|
1320
1320
|
*/
|
|
1321
|
-
render(): string | number | bigint | boolean |
|
|
1321
|
+
render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | _$react.ReactPortal | ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | _$react_jsx_runtime0.JSX.Element | null;
|
|
1322
1322
|
}
|
|
1323
1323
|
//#endregion
|
|
1324
1324
|
//#region src/equal.d.ts
|
|
@@ -1465,7 +1465,7 @@ type OptionalWrapperProps<TWrapper extends ComponentType<{
|
|
|
1465
1465
|
* )
|
|
1466
1466
|
* ```
|
|
1467
1467
|
*/
|
|
1468
|
-
declare function OptionalWrapper(props: OptionalWrapperProps): string | number | bigint | boolean |
|
|
1468
|
+
declare function OptionalWrapper(props: OptionalWrapperProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | _$react.ReactPortal | _$react.ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | _$react_jsx_runtime0.JSX.Element | null | undefined;
|
|
1469
1469
|
declare namespace OptionalWrapper {
|
|
1470
1470
|
var displayName: string;
|
|
1471
1471
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -402,6 +402,117 @@ let mock = null;
|
|
|
402
402
|
function setMock(handler) {
|
|
403
403
|
mock = handler;
|
|
404
404
|
}
|
|
405
|
+
function buildActionUrl(action, baseUrl, options, requestId) {
|
|
406
|
+
return `${(options?.baseUrl || baseUrl) + action.toLowerCase()}?_=${requestId}`;
|
|
407
|
+
}
|
|
408
|
+
function buildActionOptions(defaultOptions, options, params, requestId) {
|
|
409
|
+
const resolvedOptions = {
|
|
410
|
+
method: "POST",
|
|
411
|
+
headers: { "Content-Type": "application/json; charset=UTF-8" },
|
|
412
|
+
mode: "cors",
|
|
413
|
+
credentials: "include",
|
|
414
|
+
body: JSON.stringify(params),
|
|
415
|
+
...defaultOptions,
|
|
416
|
+
...options || Object.create(null)
|
|
417
|
+
};
|
|
418
|
+
if (!resolvedOptions.headers["X-FaasJS-Request-Id"] && !resolvedOptions.headers["x-faasjs-request-id"]) resolvedOptions.headers["X-FaasJS-Request-Id"] = requestId;
|
|
419
|
+
return resolvedOptions;
|
|
420
|
+
}
|
|
421
|
+
async function runBeforeRequest(action, params, options) {
|
|
422
|
+
if (!options.beforeRequest) return;
|
|
423
|
+
await options.beforeRequest({
|
|
424
|
+
action,
|
|
425
|
+
params,
|
|
426
|
+
options,
|
|
427
|
+
headers: options.headers
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
function normalizeMockResponse(response) {
|
|
431
|
+
if (response instanceof Error) throw new ResponseError(response);
|
|
432
|
+
if (response instanceof Response) {
|
|
433
|
+
if (typeof ReadableStream !== "undefined" && response.body instanceof ReadableStream && response.body.locked === false) {
|
|
434
|
+
const [nextBody, currentBody] = response.body.tee();
|
|
435
|
+
response.body = nextBody;
|
|
436
|
+
const clonedResponse = {
|
|
437
|
+
status: response.status,
|
|
438
|
+
headers: response.headers,
|
|
439
|
+
body: currentBody
|
|
440
|
+
};
|
|
441
|
+
if (response.data !== void 0) clonedResponse.data = response.data;
|
|
442
|
+
return new Response({ ...clonedResponse });
|
|
443
|
+
}
|
|
444
|
+
return response;
|
|
445
|
+
}
|
|
446
|
+
if (response && typeof ReadableStream !== "undefined" && response.body instanceof ReadableStream && response.body.locked === false) {
|
|
447
|
+
const [nextBody, currentBody] = response.body.tee();
|
|
448
|
+
response.body = nextBody;
|
|
449
|
+
return new Response({
|
|
450
|
+
...response,
|
|
451
|
+
body: currentBody
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
return new Response(response || {});
|
|
455
|
+
}
|
|
456
|
+
async function resolveMockResponse(action, params, options) {
|
|
457
|
+
console.debug(`[FaasJS] Mock request: ${action} %j`, params);
|
|
458
|
+
if (typeof mock === "function") return normalizeMockResponse(await mock(action, params, options));
|
|
459
|
+
return normalizeMockResponse(mock);
|
|
460
|
+
}
|
|
461
|
+
function toResponseHeaders(headers) {
|
|
462
|
+
const responseHeaders = {};
|
|
463
|
+
for (const [key, value] of headers) responseHeaders[key] = value;
|
|
464
|
+
return responseHeaders;
|
|
465
|
+
}
|
|
466
|
+
function parseSuccessfulResponse(status, headers, text) {
|
|
467
|
+
if (!text) return new Response({
|
|
468
|
+
status,
|
|
469
|
+
headers
|
|
470
|
+
});
|
|
471
|
+
const body = JSON.parse(text);
|
|
472
|
+
if (body.error?.message) throw new ResponseError({
|
|
473
|
+
message: body.error.message,
|
|
474
|
+
status,
|
|
475
|
+
headers,
|
|
476
|
+
body
|
|
477
|
+
});
|
|
478
|
+
return new Response({
|
|
479
|
+
status,
|
|
480
|
+
headers,
|
|
481
|
+
body,
|
|
482
|
+
data: body.data
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
function parseFailedResponse(status, headers, text) {
|
|
486
|
+
try {
|
|
487
|
+
const body = JSON.parse(text);
|
|
488
|
+
if (body.error?.message) throw new ResponseError({
|
|
489
|
+
message: body.error.message,
|
|
490
|
+
status,
|
|
491
|
+
headers,
|
|
492
|
+
body
|
|
493
|
+
});
|
|
494
|
+
throw new ResponseError({
|
|
495
|
+
message: text,
|
|
496
|
+
status,
|
|
497
|
+
headers,
|
|
498
|
+
body
|
|
499
|
+
});
|
|
500
|
+
} catch (error) {
|
|
501
|
+
if (error instanceof ResponseError) throw error;
|
|
502
|
+
throw new ResponseError({
|
|
503
|
+
message: text,
|
|
504
|
+
status,
|
|
505
|
+
headers,
|
|
506
|
+
body: text
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
async function parseFetchResponse(response) {
|
|
511
|
+
const headers = toResponseHeaders(response.headers);
|
|
512
|
+
const text = await response.text();
|
|
513
|
+
if (response.status >= 200 && response.status < 300) return parseSuccessfulResponse(response.status, headers, text);
|
|
514
|
+
return parseFailedResponse(response.status, headers, text);
|
|
515
|
+
}
|
|
405
516
|
/**
|
|
406
517
|
* Browser client for FaasJS - provides HTTP client functionality for making API requests from web applications.
|
|
407
518
|
*
|
|
@@ -655,86 +766,15 @@ var FaasBrowserClient = class {
|
|
|
655
766
|
*/
|
|
656
767
|
async action(action, params, options) {
|
|
657
768
|
if (!action) throw Error("[FaasJS] action required");
|
|
658
|
-
const id = `F-${generateId()}`;
|
|
659
|
-
const url = `${(options?.baseUrl || this.baseUrl) + action.toLowerCase()}?_=${id}`;
|
|
660
769
|
if (!params) params = Object.create(null);
|
|
661
|
-
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
...options
|
|
670
|
-
};
|
|
671
|
-
if (!parsedOptions.headers["X-FaasJS-Request-Id"] && !parsedOptions.headers["x-faasjs-request-id"]) parsedOptions.headers["X-FaasJS-Request-Id"] = id;
|
|
672
|
-
if (parsedOptions.beforeRequest) await parsedOptions.beforeRequest({
|
|
673
|
-
action,
|
|
674
|
-
params,
|
|
675
|
-
options: parsedOptions,
|
|
676
|
-
headers: parsedOptions.headers
|
|
677
|
-
});
|
|
678
|
-
if (mock) {
|
|
679
|
-
console.debug(`[FaasJS] Mock request: ${action} %j`, params);
|
|
680
|
-
if (typeof mock === "function") {
|
|
681
|
-
const response = await mock(action, params, parsedOptions);
|
|
682
|
-
if (response instanceof Error) return Promise.reject(new ResponseError(response));
|
|
683
|
-
if (response instanceof Response) return response;
|
|
684
|
-
return new Response(response || {});
|
|
685
|
-
}
|
|
686
|
-
if (mock instanceof Response) return mock;
|
|
687
|
-
return new Response(mock || {});
|
|
688
|
-
}
|
|
689
|
-
if (parsedOptions.request) return parsedOptions.request(url, parsedOptions);
|
|
690
|
-
if (parsedOptions.stream) return fetch(url, parsedOptions);
|
|
691
|
-
return fetch(url, parsedOptions).then(async (response) => {
|
|
692
|
-
const headers = {};
|
|
693
|
-
for (const values of response.headers) headers[values[0]] = values[1];
|
|
694
|
-
return response.text().then((res) => {
|
|
695
|
-
if (response.status >= 200 && response.status < 300) {
|
|
696
|
-
if (!res) return new Response({
|
|
697
|
-
status: response.status,
|
|
698
|
-
headers
|
|
699
|
-
});
|
|
700
|
-
const body = JSON.parse(res);
|
|
701
|
-
if (body.error?.message) return Promise.reject(new ResponseError({
|
|
702
|
-
message: body.error.message,
|
|
703
|
-
status: response.status,
|
|
704
|
-
headers,
|
|
705
|
-
body
|
|
706
|
-
}));
|
|
707
|
-
return new Response({
|
|
708
|
-
status: response.status,
|
|
709
|
-
headers,
|
|
710
|
-
body,
|
|
711
|
-
data: body.data
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
try {
|
|
715
|
-
const body = JSON.parse(res);
|
|
716
|
-
if (body.error?.message) return Promise.reject(new ResponseError({
|
|
717
|
-
message: body.error.message,
|
|
718
|
-
status: response.status,
|
|
719
|
-
headers,
|
|
720
|
-
body
|
|
721
|
-
}));
|
|
722
|
-
return Promise.reject(new ResponseError({
|
|
723
|
-
message: res,
|
|
724
|
-
status: response.status,
|
|
725
|
-
headers,
|
|
726
|
-
body
|
|
727
|
-
}));
|
|
728
|
-
} catch {
|
|
729
|
-
return Promise.reject(new ResponseError({
|
|
730
|
-
message: res,
|
|
731
|
-
status: response.status,
|
|
732
|
-
headers,
|
|
733
|
-
body: res
|
|
734
|
-
}));
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
});
|
|
770
|
+
const requestId = `F-${generateId()}`;
|
|
771
|
+
const url = buildActionUrl(action, this.baseUrl, options, requestId);
|
|
772
|
+
const resolvedOptions = buildActionOptions(this.defaultOptions, options, params, requestId);
|
|
773
|
+
await runBeforeRequest(action, params, resolvedOptions);
|
|
774
|
+
if (mock) return resolveMockResponse(action, params, resolvedOptions);
|
|
775
|
+
if (resolvedOptions.request) return resolvedOptions.request(url, resolvedOptions);
|
|
776
|
+
if (resolvedOptions.stream) return fetch(url, resolvedOptions);
|
|
777
|
+
return parseFetchResponse(await fetch(url, resolvedOptions));
|
|
738
778
|
}
|
|
739
779
|
};
|
|
740
780
|
//#endregion
|
|
@@ -1132,6 +1172,7 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
|
|
|
1132
1172
|
const failedOnceRef = useRef(false);
|
|
1133
1173
|
const pendingReloadsRef = useRef(/* @__PURE__ */ new Map());
|
|
1134
1174
|
const reloadCounterRef = useRef(0);
|
|
1175
|
+
const requestVersionRef = useRef(0);
|
|
1135
1176
|
const beforeSendRef = useRef(beforeSend);
|
|
1136
1177
|
const onSuccessRef = useRef(onSuccess);
|
|
1137
1178
|
const sendRef = useRef(send);
|
|
@@ -1153,6 +1194,7 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
|
|
|
1153
1194
|
beforeSendRef.current?.();
|
|
1154
1195
|
failedOnceRef.current = false;
|
|
1155
1196
|
const controller = new AbortController();
|
|
1197
|
+
const requestVersion = ++requestVersionRef.current;
|
|
1156
1198
|
controllerRef.current = controller;
|
|
1157
1199
|
const client = getClient(options.baseUrl);
|
|
1158
1200
|
const requestParams = options.params || params;
|
|
@@ -1164,6 +1206,7 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
|
|
|
1164
1206
|
for (const { resolve } of pendingReloadsRef.current.values()) resolve(value);
|
|
1165
1207
|
pendingReloadsRef.current.clear();
|
|
1166
1208
|
};
|
|
1209
|
+
const isCurrentRequest = () => requestVersion === requestVersionRef.current && controllerRef.current === controller;
|
|
1167
1210
|
const run = () => {
|
|
1168
1211
|
sendRef.current({
|
|
1169
1212
|
action,
|
|
@@ -1174,12 +1217,14 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
|
|
|
1174
1217
|
promiseRef.current = promise;
|
|
1175
1218
|
}
|
|
1176
1219
|
}).then((result) => {
|
|
1220
|
+
if (!isCurrentRequest()) return;
|
|
1177
1221
|
failedOnceRef.current = false;
|
|
1178
1222
|
setError(null);
|
|
1179
1223
|
onSuccessRef.current?.(result);
|
|
1180
1224
|
setLoading(false);
|
|
1181
1225
|
resolvePending(result);
|
|
1182
1226
|
}).catch(async (e) => {
|
|
1227
|
+
if (!isCurrentRequest()) return;
|
|
1183
1228
|
if (typeof e?.message === "string" && e.message.toLowerCase().includes("aborted")) return;
|
|
1184
1229
|
if (!failedOnceRef.current && typeof e?.message === "string" && e.message.includes("Failed to fetch")) {
|
|
1185
1230
|
failedOnceRef.current = true;
|
|
@@ -1193,6 +1238,7 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
|
|
|
1193
1238
|
} catch (newError) {
|
|
1194
1239
|
nextError = newError;
|
|
1195
1240
|
}
|
|
1241
|
+
if (!isCurrentRequest()) return;
|
|
1196
1242
|
setError(nextError);
|
|
1197
1243
|
setLoading(false);
|
|
1198
1244
|
rejectPending(nextError);
|
|
@@ -1202,13 +1248,15 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
|
|
|
1202
1248
|
const timeout = setTimeout(run, options.debounce);
|
|
1203
1249
|
return () => {
|
|
1204
1250
|
clearTimeout(timeout);
|
|
1205
|
-
controllerRef.current
|
|
1251
|
+
if (controllerRef.current === controller) controllerRef.current = null;
|
|
1252
|
+
controller.abort();
|
|
1206
1253
|
setLoading(false);
|
|
1207
1254
|
};
|
|
1208
1255
|
}
|
|
1209
1256
|
run();
|
|
1210
1257
|
return () => {
|
|
1211
|
-
controllerRef.current
|
|
1258
|
+
if (controllerRef.current === controller) controllerRef.current = null;
|
|
1259
|
+
controller.abort();
|
|
1212
1260
|
setLoading(false);
|
|
1213
1261
|
};
|
|
1214
1262
|
}, [
|
|
@@ -1712,12 +1760,13 @@ function createSplittingContext(defaultValue) {
|
|
|
1712
1760
|
* ```
|
|
1713
1761
|
*/
|
|
1714
1762
|
function useFaasStream(action, defaultParams, options = {}) {
|
|
1715
|
-
const [data, setData] = useState(options.data
|
|
1763
|
+
const [data, setData] = useState(options.data ?? "");
|
|
1764
|
+
const updateData = options.setData ?? setData;
|
|
1716
1765
|
const request = useFaasRequest({
|
|
1717
1766
|
action,
|
|
1718
1767
|
defaultParams,
|
|
1719
1768
|
options,
|
|
1720
|
-
beforeSend: () =>
|
|
1769
|
+
beforeSend: () => updateData(""),
|
|
1721
1770
|
send: async ({ action, params, signal, client }) => {
|
|
1722
1771
|
const response = await client.browserClient.action(action, params, {
|
|
1723
1772
|
signal,
|
|
@@ -1727,17 +1776,32 @@ function useFaasStream(action, defaultParams, options = {}) {
|
|
|
1727
1776
|
const reader = response.body.getReader();
|
|
1728
1777
|
const decoder = new TextDecoder();
|
|
1729
1778
|
let accumulatedText = "";
|
|
1779
|
+
const onAbort = () => {
|
|
1780
|
+
reader.cancel().catch(() => void 0);
|
|
1781
|
+
};
|
|
1782
|
+
if (signal.aborted) {
|
|
1783
|
+
onAbort();
|
|
1784
|
+
throw new Error("Request aborted");
|
|
1785
|
+
}
|
|
1786
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1730
1787
|
try {
|
|
1731
1788
|
while (true) {
|
|
1789
|
+
if (signal.aborted) throw new Error("Request aborted");
|
|
1732
1790
|
const { done, value } = await reader.read();
|
|
1733
1791
|
if (done) break;
|
|
1734
1792
|
accumulatedText += decoder.decode(value, { stream: true });
|
|
1735
|
-
|
|
1793
|
+
updateData(accumulatedText);
|
|
1736
1794
|
}
|
|
1795
|
+
accumulatedText += decoder.decode();
|
|
1737
1796
|
return accumulatedText;
|
|
1738
1797
|
} catch (error) {
|
|
1739
|
-
|
|
1798
|
+
if (signal.aborted) throw new Error("Request aborted");
|
|
1740
1799
|
throw error;
|
|
1800
|
+
} finally {
|
|
1801
|
+
signal.removeEventListener("abort", onAbort);
|
|
1802
|
+
try {
|
|
1803
|
+
reader.releaseLock();
|
|
1804
|
+
} catch {}
|
|
1741
1805
|
}
|
|
1742
1806
|
}
|
|
1743
1807
|
});
|
|
@@ -1746,10 +1810,10 @@ function useFaasStream(action, defaultParams, options = {}) {
|
|
|
1746
1810
|
params: request.params,
|
|
1747
1811
|
loading: request.loading,
|
|
1748
1812
|
reloadTimes: request.reloadTimes,
|
|
1749
|
-
data: options.data
|
|
1813
|
+
data: options.data ?? data,
|
|
1750
1814
|
error: request.error,
|
|
1751
1815
|
reload: request.reload,
|
|
1752
|
-
setData:
|
|
1816
|
+
setData: updateData,
|
|
1753
1817
|
setLoading: request.setLoading,
|
|
1754
1818
|
setError: request.setError
|
|
1755
1819
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/react",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.25",
|
|
4
4
|
"homepage": "https://faasjs.com/doc/react/",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/faasjs/faasjs/issues"
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
29
|
+
"@faasjs/types": ">=8.0.0-beta.25",
|
|
30
30
|
"@types/react": "^19.0.0",
|
|
31
31
|
"react": "^19.0.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@faasjs/types": ">=8.0.0-beta.
|
|
34
|
+
"@faasjs/types": ">=8.0.0-beta.25"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=24.0.0",
|