@faasjs/react 8.0.0-beta.14 → 8.0.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,46 +1,5 @@
1
1
  # @faasjs/react
2
2
 
3
- React plugin for FaasJS.
4
-
5
- [![License: MIT](https://img.shields.io/npm/l/@faasjs/react.svg)](https://github.com/faasjs/faasjs/blob/main/packages/react/LICENSE)
6
- [![NPM Version](https://img.shields.io/npm/v/@faasjs/react.svg)](https://www.npmjs.com/package/@faasjs/react)
7
-
8
- Includes browser client utilities (`FaasBrowserClient`, `ResponseError`, `setMock`) and React helpers.
9
-
10
- ## Features
11
-
12
- - Support [FaasJS Request Specifications](https://faasjs.com/guide/request-spec.html).
13
- - Support global and per-request configurations.
14
- - Compatible with [why-did-you-render](https://github.com/welldone-software/why-did-you-render).
15
- - Additional React functions:
16
- - Utils:
17
- - `equal`: Compare two values for deep equality.
18
- - `createSplittingContext`: Create a context for code splitting.
19
- - `useSplittingState`: Create splitting states.
20
- - Hooks:
21
- - `useEqualMemoize`: Memoize a value with deep equality.
22
- - `useEqualEffect`: Run an effect with deep equality.
23
- - `useEqualMemo`: Memoize a value with deep equality.
24
- - `useEqualCallback`: Memoize a callback with deep equality.
25
- - `useConstant`: Create a constant value with hooks.
26
- - `usePrevious`: Get the previous value of a state.
27
- - `useStateRef`: Create a state with a ref.
28
- - Components:
29
- - `OptionalWrapper`: Render a component optionally.
30
- - `ErrorBoundary`: Catch errors in the component tree.
31
- - Fetch Data:
32
- - `faas`: Fetch data from FaasJS.
33
- - `useFaas`: Fetch data from FaasJS with hooks.
34
- - `useFaasStream`: Fetch streaming data from FaasJS with hooks.
35
- - `FaasDataWrapper`: Fetch data from FaasJS with a wrapper component.
36
- - `withFaasData`: Fetch data from FaasJS using a higher-order component (HOC).
37
-
38
- ## Install
39
-
40
- ```sh
41
- npm install @faasjs/react react
42
- ```
43
-
44
3
  ## Functions
45
4
 
46
5
  - [createSplittingContext](functions/createSplittingContext.md)
package/dist/index.cjs CHANGED
@@ -36,10 +36,7 @@ function generateId(prefix = "", length = 18) {
36
36
  * @property {T} [data] - The parsed JSON data from the response.
37
37
  * Optional property that contains the response payload when JSON is provided.
38
38
  *
39
- * @param {ResponseProps<T>} [props] - Response properties including status, headers, body, and data.
40
- * All properties are optional with sensible defaults.
41
- *
42
- * @remarks
39
+ * Notes:
43
40
  * - status defaults to 200 if data or body is present, 204 otherwise
44
41
  * - body is automatically populated from data if not explicitly provided
45
42
  * - headers defaults to an empty object if not provided
@@ -142,6 +139,12 @@ var Response = class {
142
139
  headers;
143
140
  body;
144
141
  data;
142
+ /**
143
+ * Create a wrapped response object.
144
+ *
145
+ * @param props - Response properties including status, headers, body, and data.
146
+ * @returns Wrapped response instance.
147
+ */
145
148
  constructor(props = {}) {
146
149
  this.status = props.status || (props.data || props.body ? 200 : 204);
147
150
  this.headers = props.headers || {};
@@ -156,17 +159,13 @@ var Response = class {
156
159
  * Extends the built-in Error class to provide additional information about failed requests,
157
160
  * including HTTP status code, response headers, response body, and the original error.
158
161
  *
159
- * @class ResponseError
160
- * @extends {Error}
162
+ * @augments Error
161
163
  *
162
164
  * @property {number} status - The HTTP status code of the failed response. Defaults to 500 if not provided.
163
165
  * @property {ResponseHeaders} headers - The response headers from the failed request.
164
166
  * @property {any} body - The response body containing error details or the original error if available.
165
167
  * @property {Error} [originalError] - The original Error object if this ResponseError was created from another Error.
166
168
  *
167
- * @param {string | Error | ResponseErrorProps} data - The error message, an Error object, or a ResponseErrorProps object.
168
- * @param {Omit<ResponseErrorProps, 'message' | 'originalError'>} [options] - Additional options for the error (status, headers, body).
169
- *
170
169
  * @example Basic error with message
171
170
  * ```ts
172
171
  * throw new ResponseError('User not found')
@@ -238,7 +237,7 @@ var Response = class {
238
237
  * })
239
238
  * ```
240
239
  *
241
- * @remarks
240
+ * Notes:
242
241
  * - ResponseError is automatically thrown by the action method when the server returns an error (status >= 400)
243
242
  * - The error message from server responses is extracted from body.error.message if available
244
243
  * - When created from an Error object, the original error is preserved in the originalError property
@@ -255,13 +254,20 @@ var ResponseError = class extends Error {
255
254
  headers;
256
255
  body;
257
256
  originalError;
257
+ /**
258
+ * Create a ResponseError from a message, Error, or structured response error payload.
259
+ *
260
+ * @param data - Error message, Error object, or structured response error props.
261
+ * @param options - Additional options such as status, headers, and body.
262
+ * @returns ResponseError instance.
263
+ */
258
264
  constructor(data, options) {
259
265
  let props;
260
266
  if (typeof data === "string") props = {
261
267
  message: data,
262
268
  ...options
263
269
  };
264
- else if (data instanceof Error || data?.constructor?.name?.includes("Error")) props = {
270
+ else if (data instanceof Error || typeof data === "object" && data !== null && typeof data.constructor?.name === "string" && data.constructor.name.includes("Error")) props = {
265
271
  message: data.message,
266
272
  originalError: data,
267
273
  ...options
@@ -344,7 +350,7 @@ function setMock(handler) {
344
350
  * - Streaming support for large responses
345
351
  * - Multiple instance support with unique IDs
346
352
  *
347
- * @remarks
353
+ * Notes:
348
354
  * - All requests are POST requests by default
349
355
  * - Automatically adds X-FaasJS-Request-Id header for request tracking
350
356
  * - baseUrl must end with '/' (will throw Error if not)
@@ -406,11 +412,8 @@ var FaasBrowserClient = class {
406
412
  /**
407
413
  * Creates a new FaasBrowserClient instance.
408
414
  *
409
- * @param baseUrl - Base URL for all API requests. Must end with '/'. Defaults to '/' for relative requests.
410
- * @throws {Error} If baseUrl does not end with '/'
411
- * @param options - Configuration options for the client.
412
- * Supports default headers, beforeRequest hook, custom request function,
413
- * baseUrl override, and streaming mode.
415
+ * @param baseUrl - Base URL for all API requests. Must end with `/`. Defaults to `/` for relative requests.
416
+ * @param options - Default request options such as headers, hooks, request override, or stream mode.
414
417
  *
415
418
  * @example Basic initialization
416
419
  * ```ts
@@ -461,7 +464,7 @@ var FaasBrowserClient = class {
461
464
  * })
462
465
  * ```
463
466
  *
464
- * @throws {Error} When baseUrl does not end with '/'
467
+ * @throws {Error} When `baseUrl` does not end with `/`
465
468
  */
466
469
  constructor(baseUrl = "/", options = Object.create(null)) {
467
470
  if (baseUrl && !baseUrl.endsWith("/")) throw Error("[FaasJS] baseUrl should end with /");
@@ -486,9 +489,9 @@ var FaasBrowserClient = class {
486
489
  *
487
490
  * @throws {Error} When action is not provided or is empty
488
491
  * @throws {ResponseError} When the server returns an error response (status >= 400 or body.error exists)
489
- * @throws {NetworkError} When network request fails
492
+ * @throws {Error} When the request fails before a response is received
490
493
  *
491
- * @remarks
494
+ * Notes:
492
495
  * - All requests are POST requests by default
493
496
  * - Action path is automatically converted to lowercase
494
497
  * - A unique request ID is generated for each request and sent in X-FaasJS-Request-Id header
@@ -540,11 +543,7 @@ var FaasBrowserClient = class {
540
543
  * email: string
541
544
  * }
542
545
  *
543
- * const response = await client.action<{
544
- * action: 'user'
545
- * params: { id: number }
546
- * data: UserData
547
- * }>('user', { id: 123 })
546
+ * const response = await client.action<UserData>('user', { id: 123 })
548
547
  * console.log(response.data.name) // TypeScript knows it's a string
549
548
  * ```
550
549
  *
@@ -556,7 +555,7 @@ var FaasBrowserClient = class {
556
555
  * } catch (error) {
557
556
  * if (error instanceof ResponseError) {
558
557
  * console.error(`Server error: ${error.message}`, error.status)
559
- * if (error.data) console.error('Error details:', error.data)
558
+ * if (error.body) console.error('Error details:', error.body)
560
559
  * } else {
561
560
  * console.error('Network error:', error)
562
561
  * }
@@ -647,7 +646,7 @@ var FaasBrowserClient = class {
647
646
  headers,
648
647
  body
649
648
  }));
650
- } catch (_) {
649
+ } catch {
651
650
  return Promise.reject(new ResponseError({
652
651
  message: res,
653
652
  status: response.status,
@@ -662,17 +661,20 @@ var FaasBrowserClient = class {
662
661
  //#endregion
663
662
  //#region src/faas.ts
664
663
  /**
665
- * Request faas server
664
+ * Call the currently configured FaasReactClient.
666
665
  *
667
- * @param action {string} action name
668
- * @param params {object} action params
669
- * @returns {Promise<Response<any>>}
666
+ * @param action - Action path to invoke.
667
+ * @param params - Parameters sent to the action.
668
+ * @param options - Optional per-request overrides such as headers or base URL.
669
+ * @returns Response returned by the active browser client.
670
670
  *
671
671
  * @example
672
672
  * ```ts
673
- * faas<{ title: string }>('post/get', { id: 1 }).then(res => {
674
- * console.log(res.data.title)
675
- * })
673
+ * import { faas } from '@faasjs/react'
674
+ *
675
+ * const response = await faas<{ title: string }>('post/get', { id: 1 })
676
+ *
677
+ * console.log(response.data.title)
676
678
  * ```
677
679
  */
678
680
  async function faas(action, params, options) {
@@ -733,13 +735,18 @@ function equal(a, b) {
733
735
  * @returns The memoized value.
734
736
  */
735
737
  function useEqualMemoize(value) {
738
+ const ref = (0, react.useRef)(value);
739
+ if (!equal(value, ref.current)) ref.current = value;
740
+ return ref.current;
741
+ }
742
+ function useEqualSignal(value) {
736
743
  const ref = (0, react.useRef)(value);
737
744
  const signalRef = (0, react.useRef)(0);
738
745
  if (!equal(value, ref.current)) {
739
746
  ref.current = value;
740
747
  signalRef.current += 1;
741
748
  }
742
- return (0, react.useMemo)(() => ref.current, [signalRef.current]);
749
+ return signalRef.current;
743
750
  }
744
751
  /**
745
752
  * Custom hook that works like `useEffect` but uses deep comparison on dependencies.
@@ -749,7 +756,7 @@ function useEqualMemoize(value) {
749
756
  * @returns The result of the `useEffect` hook with memoized dependencies.
750
757
  */
751
758
  function useEqualEffect(callback, dependencies) {
752
- return (0, react.useEffect)(callback, useEqualMemoize(dependencies));
759
+ return (0, react.useEffect)(callback, [useEqualSignal(dependencies)]);
753
760
  }
754
761
  /**
755
762
  * Custom hook that works like `useMemo` but uses deep comparison on dependencies.
@@ -759,7 +766,12 @@ function useEqualEffect(callback, dependencies) {
759
766
  * @returns The result of the `useMemo` hook with memoized dependencies.
760
767
  */
761
768
  function useEqualMemo(callback, dependencies) {
762
- return (0, react.useMemo)(callback, useEqualMemoize(dependencies));
769
+ const signal = useEqualSignal(dependencies);
770
+ const callbackRef = (0, react.useRef)(callback);
771
+ callbackRef.current = callback;
772
+ return (0, react.useMemo)(() => {
773
+ return callbackRef.current();
774
+ }, [signal]);
763
775
  }
764
776
  /**
765
777
  * Custom hook that works like `useCallback` but uses deep comparison on dependencies.
@@ -769,7 +781,7 @@ function useEqualMemo(callback, dependencies) {
769
781
  * @returns The result of the `useCallback` hook with memoized dependencies.
770
782
  */
771
783
  function useEqualCallback(callback, dependencies) {
772
- return (0, react.useCallback)((...args) => callback(...args), useEqualMemoize(dependencies));
784
+ return (0, react.useCallback)((...args) => callback(...args), [useEqualSignal(dependencies)]);
773
785
  }
774
786
  //#endregion
775
787
  //#region src/FaasDataWrapper.tsx
@@ -821,16 +833,23 @@ function withFaasData(Component, faasProps) {
821
833
  //#endregion
822
834
  //#region src/useFaas.tsx
823
835
  /**
824
- * Request faas server with React hook
836
+ * Request FaasJS data and keep request state in React state.
837
+ *
838
+ * `useFaas` sends an initial request unless `skip` is enabled, and returns
839
+ * request state plus helpers for reloading, updating data, and handling errors.
825
840
  *
826
- * @param action {string} action name
827
- * @param defaultParams {object} initial action params
828
- * @returns {FaasDataInjection<any>}
841
+ * @param action - Action path to invoke.
842
+ * @param defaultParams - Params used for the initial request and future reloads.
843
+ * @param options - Optional hook configuration such as controlled data, debounce, and skip logic.
844
+ * @returns Request state and helper methods for the action.
829
845
  *
830
846
  * @example
831
847
  * ```tsx
832
- * function Post ({ id }) {
848
+ * import { useFaas } from '@faasjs/react'
849
+ *
850
+ * function Post({ id }: { id: number }) {
833
851
  * const { data } = useFaas<{ title: string }>('post/get', { id })
852
+ *
834
853
  * return <h1>{data.title}</h1>
835
854
  * }
836
855
  * ```
@@ -871,7 +890,8 @@ function useFaas(action, defaultParams, options = {}) {
871
890
  const nextData = r.data;
872
891
  setFails(0);
873
892
  setError(null);
874
- options.setData ? options.setData(nextData) : localSetData(nextData);
893
+ if (options.setData) options.setData(nextData);
894
+ else localSetData(nextData);
875
895
  setLoading(false);
876
896
  for (const { resolve } of pendingReloadsRef.current.values()) resolve(nextData);
877
897
  pendingReloadsRef.current.clear();
@@ -949,14 +969,20 @@ function useFaas(action, defaultParams, options = {}) {
949
969
  //#region src/client.tsx
950
970
  const clients = {};
951
971
  /**
952
- * Before use faas, you should initialize a FaasReactClient.
972
+ * Create and register a FaasReactClient instance.
973
+ *
974
+ * The returned client is stored by `baseUrl` and becomes the default client
975
+ * used by helpers such as {@link faas} and {@link useFaas}.
953
976
  *
954
- * @returns FaasReactClient instance.
977
+ * @param options - Client configuration including base URL, default request options, and error hooks.
978
+ * @returns Registered FaasReactClient instance.
955
979
  *
956
980
  * @example
957
981
  * ```ts
982
+ * import { FaasReactClient } from '@faasjs/react'
983
+ *
958
984
  * const client = FaasReactClient({
959
- * baseUrl: 'localhost:8080/api/'
985
+ * baseUrl: 'http://localhost:8080/api/',
960
986
  * })
961
987
  * ```
962
988
  */
@@ -985,16 +1011,20 @@ function FaasReactClient({ baseUrl, options: clientOptions, onError } = { baseUr
985
1011
  return reactClient;
986
1012
  }
987
1013
  /**
988
- * Get FaasReactClient instance
1014
+ * Get a registered FaasReactClient instance.
1015
+ *
1016
+ * When `host` is omitted, the first registered client is returned. If no client
1017
+ * has been created yet, a default client is initialized automatically.
989
1018
  *
990
- * @param host {string} empty string for default host
991
- * @returns {FaasReactClientInstance}
1019
+ * @param host - Registered base URL to look up. Omit it to use the default client.
1020
+ * @returns Registered or newly created FaasReactClient instance.
992
1021
  *
993
1022
  * @example
994
1023
  * ```ts
1024
+ * import { getClient } from '@faasjs/react'
1025
+ *
995
1026
  * getClient()
996
- * // or
997
- * getClient('another-host')
1027
+ * getClient('http://localhost:8080/api/')
998
1028
  * ```
999
1029
  */
1000
1030
  function getClient(host) {
@@ -1055,23 +1085,25 @@ var ErrorBoundary = class extends react.Component {
1055
1085
  * Custom hook that returns a stateful value and a ref to that value.
1056
1086
  *
1057
1087
  * @template T - The type of the value.
1058
- * @param {T} initialValue - The initial value of the state.
1059
- * @returns {[T, (value: T) => void, RefObject<T>]} - The stateful value, a function to set the value, and a ref to the value.
1088
+ * @param initialValue - Initial state value. When omitted, state starts as `null`.
1089
+ * @returns Tuple containing the current state, the state setter, and a ref that always points at the latest state.
1060
1090
  *
1061
1091
  * @example
1062
1092
  * ```tsx
1063
1093
  * import { useStateRef } from '@faasjs/react'
1064
1094
  *
1065
1095
  * function MyComponent() {
1066
- * const [value, setValue, ref] = useStateRef(0)
1067
- *
1068
- * return (
1069
- * <div>
1070
- * <p>Value: {value}</p>
1071
- * <button onClick={() => setValue(value + 1)}>Increment</button>
1072
- * <button onClick={() => console.log(ref.current)}>Submit</button>
1073
- * </div>
1074
- * )
1096
+ * const [value, setValue, ref] = useStateRef(0)
1097
+ *
1098
+ * return (
1099
+ * <div>
1100
+ * <p>Value: {value}</p>
1101
+ * <button onClick={() => setValue(value + 1)}>Increment</button>
1102
+ * <button onClick={() => console.log(ref.current)}>Submit</button>
1103
+ * </div>
1104
+ * )
1105
+ * }
1106
+ * ```
1075
1107
  */
1076
1108
  function useStateRef(initialValue) {
1077
1109
  const [state, setState] = (0, react.useState)(initialValue ?? null);
@@ -1088,15 +1120,16 @@ function useStateRef(initialValue) {
1088
1120
  //#endregion
1089
1121
  //#region src/splittingState.tsx
1090
1122
  /**
1091
- * A hook that initializes and splits state variables and their corresponding setters.
1123
+ * Create local state entries and matching setters for each key in an object.
1092
1124
  *
1093
1125
  * @template T - A generic type that extends a record with string keys and any values.
1094
- * @param {T} initialStates - An object containing the initial states.
1126
+ * @param initialStates - Object whose keys become state values and `setXxx` setters.
1127
+ * @returns Object containing the original keys plus generated setter functions.
1095
1128
  *
1096
1129
  * @example
1097
1130
  * ```tsx
1098
1131
  * function Counter() {
1099
- * const { count, setCount, name, setName } = useSplittingState({ count: 0, name: 'John' });
1132
+ * const { count, setCount, name, setName } = useSplittingState({ count: 0, name: 'John' })
1100
1133
  *
1101
1134
  * return <>{name}: {count}</>
1102
1135
  * }
@@ -1349,34 +1382,30 @@ async function validValues(rules, items, values, lang) {
1349
1382
  //#region src/Form/Footer.tsx
1350
1383
  function FormFooter() {
1351
1384
  const { submitting, setSubmitting, onSubmit, valuesRef, Elements, items, setErrors, lang, rules } = useFormContext();
1352
- const handleSubmit = (0, react.useCallback)(async () => {
1353
- setSubmitting(true);
1354
- setErrors({});
1355
- const errors = await validValues(rules, items, valuesRef.current, lang);
1356
- if (Object.keys(errors).length) {
1357
- setErrors(errors);
1358
- setSubmitting(false);
1359
- return;
1360
- }
1361
- onSubmit(valuesRef.current).finally(() => setSubmitting(false));
1362
- }, [
1363
- setSubmitting,
1364
- setErrors,
1365
- rules,
1366
- items,
1367
- lang,
1368
- onSubmit
1369
- ]);
1370
- return (0, react.useMemo)(() => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Elements.Button, {
1385
+ const Button = Elements.Button;
1386
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
1371
1387
  submitting,
1372
- submit: handleSubmit,
1388
+ submit: (0, react.useCallback)(async () => {
1389
+ setSubmitting(true);
1390
+ setErrors({});
1391
+ const errors = await validValues(rules, items, valuesRef.current, lang);
1392
+ if (Object.keys(errors).length) {
1393
+ setErrors(errors);
1394
+ setSubmitting(false);
1395
+ return;
1396
+ }
1397
+ onSubmit(valuesRef.current).finally(() => setSubmitting(false));
1398
+ }, [
1399
+ setSubmitting,
1400
+ setErrors,
1401
+ rules,
1402
+ items,
1403
+ valuesRef,
1404
+ lang,
1405
+ onSubmit
1406
+ ]),
1373
1407
  children: lang.submit
1374
- }), [
1375
- submitting,
1376
- handleSubmit,
1377
- lang.submit,
1378
- Elements.Button
1379
- ]);
1408
+ });
1380
1409
  }
1381
1410
  FormFooter.displayName = "FormFooter";
1382
1411
  //#endregion
@@ -1395,32 +1424,29 @@ function mergeValues(items, defaultValues = {}) {
1395
1424
  return values;
1396
1425
  }
1397
1426
  /**
1398
- * FormContainer component is a wrapper that provides context and state management for form elements.
1399
- * It initializes form states such as values, errors, submitting status, elements, language, and rules.
1427
+ * Render a form with context, default elements, and validation state.
1428
+ *
1429
+ * `FormContainer` merges provided elements, language strings, and rules with
1430
+ * the package defaults, then exposes them through form context.
1400
1431
  *
1401
1432
  * @template Values - The type of form values, defaults to Record<string, any>.
1402
1433
  * @template FormElements - The type of form elements, defaults to FormElementTypes.
1403
1434
  * @template Rules - The type of form rules, defaults to FormDefaultRules.
1404
- *
1405
- * @param {FormProps<Values, FormElements, Rules>} props - The properties for the FormContainer component.
1406
- * @param {Values} props.defaultValues - The default values for the form fields.
1407
- * @param {FormElements} props.Elements - The form elements to be used in the form.
1408
- * @param {Rules} props.rules - The validation rules for the form fields.
1409
- * @param {FormLang} props.lang - The language settings for the form.
1410
- * @param {Partial<FormContextProps>} props - Additional properties for the form context.
1411
- *
1412
- * @returns {JSX.Element} The FormContainer component.
1435
+ * @param props - Form items and optional overrides for defaults, language, rules, and submit behavior.
1436
+ * @returns React form container with shared form context.
1413
1437
  *
1414
1438
  * @example
1415
1439
  * ```tsx
1416
1440
  * import { Form } from '@faasjs/react'
1417
1441
  *
1418
1442
  * function MyForm() {
1419
- * return <Form
1420
- * items={[
1421
- * { name: 'name' },
1422
- * ]}
1423
- * />
1443
+ * return (
1444
+ * <Form
1445
+ * items={[
1446
+ * { name: 'name' },
1447
+ * ]}
1448
+ * />
1449
+ * )
1424
1450
  * }
1425
1451
  * ```
1426
1452
  */
@@ -1477,14 +1503,21 @@ OptionalWrapper.displayName = "OptionalWrapper";
1477
1503
  //#endregion
1478
1504
  //#region src/useFaasStream.tsx
1479
1505
  /**
1480
- * Stream faas server response with React hook
1506
+ * Stream a FaasJS response into React state.
1481
1507
  *
1482
- * @param action {string} action name
1483
- * @param defaultParams {object} initial action params
1484
- * @returns {UseFaasStreamResult}
1508
+ * The hook sends a streaming request, appends decoded text chunks to `data`,
1509
+ * and exposes reload helpers for retrying the same action.
1510
+ *
1511
+ * @param action - Action path to invoke.
1512
+ * @param defaultParams - Params used for the initial request and future reloads.
1513
+ * @param options - Optional hook configuration such as controlled data, debounce, and skip logic.
1514
+ * @returns Streaming request state and helper methods.
1485
1515
  *
1486
1516
  * @example
1487
1517
  * ```tsx
1518
+ * import { useState } from 'react'
1519
+ * import { useFaasStream } from '@faasjs/react'
1520
+ *
1488
1521
  * function Chat() {
1489
1522
  * const [prompt, setPrompt] = useState('')
1490
1523
  * const { data, loading, reload } = useFaasStream('chat', { prompt })
@@ -1625,8 +1658,8 @@ function useFaasStream(action, defaultParams, options = {}) {
1625
1658
  * Hook to store the previous value of a state or prop.
1626
1659
  *
1627
1660
  * @template T - The type of the value.
1628
- * @param {T} value - The current value to be stored.
1629
- * @returns {T | undefined} - The previous value, or undefined if there is no previous value.
1661
+ * @param value - The current value to track.
1662
+ * @returns Previous value from the prior render, or `undefined` on the first render.
1630
1663
  */
1631
1664
  function usePrevious(value) {
1632
1665
  const ref = (0, react.useRef)(void 0);