@faasjs/react 8.0.0-beta.25 → 8.0.0-beta.27

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 CHANGED
@@ -3,7 +3,7 @@ import { Component, ComponentProps, ComponentType, Dispatch, ErrorInfo, JSX, Rea
3
3
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
4
4
  import { FaasAction, FaasAction as FaasAction$1, FaasActionUnionType, FaasActionUnionType as FaasActionUnionType$1, FaasData, FaasData as FaasData$1, FaasParams, FaasParams as FaasParams$1 } from "@faasjs/types";
5
5
 
6
- //#region src/generateId.d.ts
6
+ //#region src/generateId/index.d.ts
7
7
  /**
8
8
  * Generate a random identifier with an optional prefix.
9
9
  *
@@ -23,7 +23,7 @@ import { FaasAction, FaasAction as FaasAction$1, FaasActionUnionType, FaasAction
23
23
  */
24
24
  declare function generateId(prefix?: string, length?: number): string;
25
25
  //#endregion
26
- //#region src/browser.d.ts
26
+ //#region src/browser/index.d.ts
27
27
  /**
28
28
  * Template literal type for URL strings that must end with a forward slash.
29
29
  *
@@ -111,7 +111,7 @@ type Options = RequestInit & {
111
111
  *
112
112
  * Notes:
113
113
  * - Headers are case-insensitive in HTTP but stored with exact casing in this object
114
- * - Common headers include: Content-Type, Authorization, X-Request-Id, X-Custom-Header
114
+ * - Common headers include: Content-Type, Authorization, x-faasjs-request-id, X-Custom-Header
115
115
  * - No support for multi-value headers (use comma-separated values instead)
116
116
  * - Used in Response, ResponseError, and Options types
117
117
  * - Simplified model compared to browser's Headers interface (no .get(), .set() methods)
@@ -250,7 +250,7 @@ type ResponseProps<T = any> = {
250
250
  * data: { created: true },
251
251
  * headers: {
252
252
  * 'Content-Type': 'application/json',
253
- * 'X-Request-Id': 'req-123',
253
+ * 'x-faasjs-request-id': 'req-123',
254
254
  * 'X-Cache-Key': 'user-123'
255
255
  * }
256
256
  * })
@@ -401,8 +401,8 @@ type ResponseErrorProps = {
401
401
  * if (error.body) {
402
402
  * console.error('Error details:', error.body)
403
403
  * }
404
- * if (error.headers['X-Request-Id']) {
405
- * console.error('Request ID:', error.headers['X-Request-Id'])
404
+ * if (error.headers['x-faasjs-request-id']) {
405
+ * console.error('Request ID:', error.headers['x-faasjs-request-id'])
406
406
  * }
407
407
  * }
408
408
  * }
@@ -848,7 +848,7 @@ declare class FaasBrowserClient {
848
848
  action<PathOrData extends FaasActionUnionType$1>(action: FaasAction$1<PathOrData>, params?: FaasParams$1<PathOrData>, options?: Options): Promise<Response<FaasData$1<PathOrData>>>;
849
849
  }
850
850
  //#endregion
851
- //#region src/faas.d.ts
851
+ //#region src/faas/index.d.ts
852
852
  /**
853
853
  * Call the currently configured FaasReactClient.
854
854
  *
@@ -876,7 +876,7 @@ declare class FaasBrowserClient {
876
876
  */
877
877
  declare function faas<PathOrData extends FaasActionUnionType$1>(action: FaasAction$1<PathOrData>, params: FaasParams$1<PathOrData>, options?: Options): Promise<Response<FaasData$1<PathOrData>>>;
878
878
  //#endregion
879
- //#region src/FaasDataWrapper.d.ts
879
+ //#region src/FaasDataWrapper/index.d.ts
880
880
  /**
881
881
  * Request state injected by {@link useFaas}, {@link FaasDataWrapper}, and {@link withFaasData}.
882
882
  *
@@ -884,8 +884,9 @@ declare function faas<PathOrData extends FaasActionUnionType$1>(action: FaasActi
884
884
  */
885
885
  type FaasDataInjection<PathOrData extends FaasActionUnionType$1 = any> = {
886
886
  /** Action path associated with the current request state. */action: FaasAction$1<PathOrData>; /** Params used for the most recent request attempt. */
887
- params: FaasParams$1<PathOrData>; /** Whether the request is currently in flight. */
888
- loading: boolean; /** Number of times `reload()` has triggered a new request. */
887
+ params: FaasParams$1<PathOrData>; /** Whether the request is currently in flight and should block the main UI. */
888
+ loading: boolean; /** Whether a background refresh request is currently in flight. */
889
+ refreshing: boolean; /** Number of times `reload()` or polling has triggered a new request. */
889
890
  reloadTimes: number; /** Current resolved data value. */
890
891
  data: FaasData$1<PathOrData>; /** Last request error, if one occurred. */
891
892
  error: any; /** Promise representing the latest request. */
@@ -896,7 +897,9 @@ type FaasDataInjection<PathOrData extends FaasActionUnionType$1 = any> = {
896
897
  * When the source hook is currently skipped, calling `reload` clears the skip
897
898
  * flag before starting the next request.
898
899
  */
899
- reload(params?: Record<string, any>): Promise<FaasData$1<PathOrData>>; /** Controlled or internal setter for the resolved data value. */
900
+ reload(params?: Record<string, any>, options?: {
901
+ silent?: boolean;
902
+ }): Promise<FaasData$1<PathOrData>>; /** Controlled or internal setter for the resolved data value. */
900
903
  setData: React.Dispatch<React.SetStateAction<FaasData$1<PathOrData>>>; /** Setter for the loading flag. */
901
904
  setLoading: React.Dispatch<React.SetStateAction<boolean>>; /** Setter for the latest request promise. */
902
905
  setPromise: React.Dispatch<React.SetStateAction<Promise<Response<FaasData$1<PathOrData>>>>>; /** Setter for the last request error. */
@@ -912,7 +915,8 @@ type FaasDataWrapperProps<PathOrData extends FaasActionUnionType$1> = {
912
915
  children?: React.ReactElement<Partial<FaasDataInjection<PathOrData>>>; /** Element rendered before the first successful load. */
913
916
  fallback?: JSX.Element | false; /** Action path to request. */
914
917
  action: FaasAction$1<PathOrData>; /** Params sent to the action. */
915
- params?: FaasParams$1<PathOrData>; /** Callback invoked whenever the resolved data value changes. */
918
+ params?: FaasParams$1<PathOrData>; /** Milliseconds to wait after each completed request before refreshing data in the background. */
919
+ polling?: number | false; /** Callback invoked whenever the resolved data value changes. */
916
920
  onDataChange?(args: FaasDataInjection<PathOrData>): void; /** Controlled data value used instead of internal state. */
917
921
  data?: FaasData$1<PathOrData>; /** Controlled setter used instead of internal state. */
918
922
  setData?: React.Dispatch<React.SetStateAction<FaasData$1<PathOrData>>>; /** Base URL override used for this wrapper instance. */
@@ -937,6 +941,7 @@ type FaasDataWrapperRef<PathOrData extends FaasActionUnionType$1 = any> = FaasDa
937
941
  * @param {JSX.Element | false} [props.fallback] - Element rendered before the first successful load.
938
942
  * @param {FaasAction<PathOrData>} props.action - Action path to request.
939
943
  * @param {FaasParams<PathOrData>} [props.params] - Params sent to the action.
944
+ * @param {number | false} [props.polling] - Milliseconds to wait after each completed request before refreshing data in the background.
940
945
  * @param {(args: FaasDataInjection<PathOrData>) => void} [props.onDataChange] - Callback invoked when the resolved data value changes.
941
946
  * @param {FaasData<PathOrData>} [props.data] - Controlled data value used instead of internal state.
942
947
  * @param {React.Dispatch<React.SetStateAction<FaasData<PathOrData>>>} [props.setData] - Controlled setter used instead of internal state.
@@ -1014,8 +1019,8 @@ declare const FaasDataWrapper: <PathOrData extends FaasActionUnionType$1 = any>(
1014
1019
  /**
1015
1020
  * Wrap a component with {@link FaasDataWrapper} and inject Faas request state as props.
1016
1021
  *
1017
- * `withFaasData` is most useful for wrapper-style exports or compatibility with
1018
- * an existing component boundary. For new code, prefer `useFaas` or
1022
+ * `withFaasData` is most useful for wrapper-style exports or when you want to
1023
+ * preserve an existing component boundary. For new code, prefer `useFaas` or
1019
1024
  * `FaasDataWrapper` when they express the request ownership more directly.
1020
1025
  *
1021
1026
  * @template PathOrData - Action path or response data type used for inference.
@@ -1055,6 +1060,7 @@ declare function withFaasData<PathOrData extends FaasActionUnionType$1, TCompone
1055
1060
  * @property {React.Dispatch<React.SetStateAction<Data>>} [setData] - Controlled setter paired with `data`.
1056
1061
  * @property {boolean | ((params: Params) => boolean)} [skip] - Boolean or predicate that suppresses the automatic request.
1057
1062
  * @property {number} [debounce] - Milliseconds to wait before sending the latest request.
1063
+ * @property {number | false} [polling] - Milliseconds to wait after each completed request before refreshing data in the background.
1058
1064
  * @property {BaseUrl} [baseUrl] - Base URL override used for this request lifecycle.
1059
1065
  */
1060
1066
  type SharedUseFaasOptions<Params, Data> = {
@@ -1063,10 +1069,11 @@ type SharedUseFaasOptions<Params, Data> = {
1063
1069
  setData?: React.Dispatch<React.SetStateAction<Data>>;
1064
1070
  skip?: boolean | ((params: Params) => boolean);
1065
1071
  debounce?: number;
1072
+ polling?: number | false;
1066
1073
  baseUrl?: BaseUrl;
1067
1074
  };
1068
1075
  //#endregion
1069
- //#region src/useFaas.d.ts
1076
+ //#region src/useFaas/index.d.ts
1070
1077
  /**
1071
1078
  * Options that customize the {@link useFaas} request lifecycle.
1072
1079
  *
@@ -1078,14 +1085,14 @@ type useFaasOptions<PathOrData extends FaasActionUnionType$1> = SharedUseFaasOpt
1078
1085
  *
1079
1086
  * `useFaas` is the default hook for standard FaasJS request-response flows in React.
1080
1087
  * It sends an initial request unless `skip` is enabled, and returns request state
1081
- * plus helpers for reloading, updating data, and handling errors.
1088
+ * plus helpers for reloading, background refreshing, updating data, and handling errors.
1082
1089
  *
1083
1090
  * @template PathOrData - Action path or response data type used for inference.
1084
1091
  *
1085
1092
  * @param {FaasAction<PathOrData>} action - Action path to invoke.
1086
1093
  * @param {FaasParams<PathOrData>} defaultParams - Params used for the initial request and future reloads.
1087
- * @param {useFaasOptions<PathOrData>} [options] - Optional hook configuration such as controlled data, skip logic, debounce timing, and base URL overrides.
1088
- * See the `useFaasOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, and `baseUrl`.
1094
+ * @param {useFaasOptions<PathOrData>} [options] - Optional hook configuration such as controlled data, skip logic, debounce timing, polling, and base URL overrides.
1095
+ * See the `useFaasOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, `polling`, and `baseUrl`.
1089
1096
  * @returns {FaasDataInjection<PathOrData>} Request state and helper methods described by {@link FaasDataInjection}.
1090
1097
  *
1091
1098
  * @example
@@ -1229,7 +1236,7 @@ declare function FaasReactClient(options?: FaasReactClientOptions): FaasReactCli
1229
1236
  */
1230
1237
  declare function getClient(host?: string): FaasReactClientInstance;
1231
1238
  //#endregion
1232
- //#region src/constant.d.ts
1239
+ //#region src/constant/index.d.ts
1233
1240
  /**
1234
1241
  * Returns a constant value that is created by the given function.
1235
1242
  *
@@ -1250,7 +1257,7 @@ declare function getClient(host?: string): FaasReactClientInstance;
1250
1257
  */
1251
1258
  declare function useConstant<T>(fn: () => T): T;
1252
1259
  //#endregion
1253
- //#region src/ErrorBoundary.d.ts
1260
+ //#region src/ErrorBoundary/index.d.ts
1254
1261
  /**
1255
1262
  * Props for the {@link ErrorBoundary} component.
1256
1263
  */
@@ -1318,10 +1325,10 @@ declare class ErrorBoundary extends Component<ErrorBoundaryProps, {
1318
1325
  /**
1319
1326
  * Render children or the configured fallback for the captured error.
1320
1327
  */
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;
1328
+ render(): string | number | bigint | boolean | _$react_jsx_runtime0.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | _$react.ReactPortal | ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null;
1322
1329
  }
1323
1330
  //#endregion
1324
- //#region src/equal.d.ts
1331
+ //#region src/equal/index.d.ts
1325
1332
  /**
1326
1333
  * Compares two values for deep equality.
1327
1334
  *
@@ -1426,7 +1433,7 @@ declare function useEqualMemo<T>(callback: () => T, dependencies: any[]): T;
1426
1433
  */
1427
1434
  declare function useEqualCallback<T extends (...args: any[]) => any>(callback: T, dependencies: any[]): T;
1428
1435
  //#endregion
1429
- //#region src/OptionalWrapper.d.ts
1436
+ //#region src/OptionalWrapper/index.d.ts
1430
1437
  /**
1431
1438
  * Props for the {@link OptionalWrapper} helper component.
1432
1439
  *
@@ -1465,12 +1472,12 @@ type OptionalWrapperProps<TWrapper extends ComponentType<{
1465
1472
  * )
1466
1473
  * ```
1467
1474
  */
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;
1475
+ declare function OptionalWrapper(props: OptionalWrapperProps): string | number | bigint | boolean | _$react_jsx_runtime0.JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | _$react.ReactPortal | _$react.ReactElement<unknown, string | _$react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
1469
1476
  declare namespace OptionalWrapper {
1470
1477
  var displayName: string;
1471
1478
  }
1472
1479
  //#endregion
1473
- //#region src/splittingContext.d.ts
1480
+ //#region src/splittingContext/index.d.ts
1474
1481
  /**
1475
1482
  * Create a context whose keys can be consumed independently.
1476
1483
  *
@@ -1586,7 +1593,7 @@ declare function createSplittingContext<T extends Record<string, any>>(defaultVa
1586
1593
  use: <NewT extends T = T>(this: void) => Readonly<NewT>;
1587
1594
  };
1588
1595
  //#endregion
1589
- //#region src/splittingState.d.ts
1596
+ //#region src/splittingState/index.d.ts
1590
1597
  /**
1591
1598
  * Setter map generated by {@link useSplittingState} for each state key.
1592
1599
  *
@@ -1617,7 +1624,7 @@ type StatesWithSetters<T> = T & StateSetters<T>;
1617
1624
  */
1618
1625
  declare function useSplittingState<T extends Record<string, unknown>>(initialStates: T): StatesWithSetters<T>;
1619
1626
  //#endregion
1620
- //#region src/useFaasStream.d.ts
1627
+ //#region src/useFaasStream/index.d.ts
1621
1628
  /**
1622
1629
  * Options that customize the {@link useFaasStream} request lifecycle.
1623
1630
  */
@@ -1627,12 +1634,15 @@ type UseFaasStreamOptions = SharedUseFaasOptions<Record<string, any>, string>;
1627
1634
  */
1628
1635
  type UseFaasStreamResult = {
1629
1636
  /** Action path currently associated with the stream request. */action: string; /** Params used for the most recent request attempt. */
1630
- params: Record<string, any>; /** Whether the hook is currently waiting for stream data. */
1631
- loading: boolean; /** Number of times `reload()` has triggered a new request. */
1637
+ params: Record<string, any>; /** Whether the hook is currently waiting for stream data and should block the main UI. */
1638
+ loading: boolean; /** Whether a background stream refresh is currently in flight. */
1639
+ refreshing: boolean; /** Number of times `reload()` or polling has triggered a new request. */
1632
1640
  reloadTimes: number; /** Accumulated text decoded from the stream response. */
1633
1641
  data: string; /** Last error raised while opening or consuming the stream. */
1634
1642
  error: any; /** Trigger a new streaming request with optional params. */
1635
- reload: (params?: Record<string, any>) => Promise<string>; /** Controlled or internal setter for the accumulated text. */
1643
+ reload: (params?: Record<string, any>, options?: {
1644
+ silent?: boolean;
1645
+ }) => Promise<string>; /** Controlled or internal setter for the accumulated text. */
1636
1646
  setData: React.Dispatch<React.SetStateAction<string>>; /** Setter for the loading flag. */
1637
1647
  setLoading: React.Dispatch<React.SetStateAction<boolean>>; /** Setter for the last stream error. */
1638
1648
  setError: React.Dispatch<React.SetStateAction<any>>;
@@ -1646,8 +1656,8 @@ type UseFaasStreamResult = {
1646
1656
  *
1647
1657
  * @param {string} action - Action path to invoke.
1648
1658
  * @param {Record<string, any>} defaultParams - Params used for the initial request and future reloads.
1649
- * @param {UseFaasStreamOptions} [options] - Optional hook configuration such as controlled stream text, skip logic, debounce timing, and base URL overrides.
1650
- * See the `UseFaasStreamOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, and `baseUrl`.
1659
+ * @param {UseFaasStreamOptions} [options] - Optional hook configuration such as controlled stream text, skip logic, debounce timing, polling, and base URL overrides.
1660
+ * See the `UseFaasStreamOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, `polling`, and `baseUrl`.
1651
1661
  * @returns {UseFaasStreamResult} Streaming request state and helper methods described by {@link UseFaasStreamResult}.
1652
1662
  *
1653
1663
  * @example
@@ -1676,7 +1686,7 @@ type UseFaasStreamResult = {
1676
1686
  */
1677
1687
  declare function useFaasStream(action: string, defaultParams: Record<string, any>, options?: UseFaasStreamOptions): UseFaasStreamResult;
1678
1688
  //#endregion
1679
- //#region src/usePrevious.d.ts
1689
+ //#region src/usePrevious/index.d.ts
1680
1690
  /**
1681
1691
  * Hook to store the previous value of a state or prop.
1682
1692
  *
@@ -1697,7 +1707,7 @@ declare function useFaasStream(action: string, defaultParams: Record<string, any
1697
1707
  */
1698
1708
  declare function usePrevious<T = any>(value: T): T | undefined;
1699
1709
  //#endregion
1700
- //#region src/useStateRef.d.ts
1710
+ //#region src/useStateRef/index.d.ts
1701
1711
  /**
1702
1712
  * Custom hook that returns a stateful value and a ref to that value.
1703
1713
  *
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Component, cloneElement, createContext, forwardRef, useCallback, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- //#region src/generateId.ts
3
+ //#region src/generateId/index.ts
4
4
  /**
5
5
  * Generate a random identifier with an optional prefix.
6
6
  *
@@ -23,7 +23,7 @@ function generateId(prefix = "", length = 18) {
23
23
  return `${prefix}${Date.now().toString(36).padStart(8, "0")}${Math.random().toString(36).substring(2, length - 6).padEnd(length - 8, "0")}`;
24
24
  }
25
25
  //#endregion
26
- //#region src/browser.ts
26
+ //#region src/browser/index.ts
27
27
  /**
28
28
  * Wrapper class for HTTP responses from FaasJS functions.
29
29
  *
@@ -88,7 +88,7 @@ function generateId(prefix = "", length = 18) {
88
88
  * data: { created: true },
89
89
  * headers: {
90
90
  * 'Content-Type': 'application/json',
91
- * 'X-Request-Id': 'req-123',
91
+ * 'x-faasjs-request-id': 'req-123',
92
92
  * 'X-Cache-Key': 'user-123'
93
93
  * }
94
94
  * })
@@ -235,8 +235,8 @@ var Response = class {
235
235
  * if (error.body) {
236
236
  * console.error('Error details:', error.body)
237
237
  * }
238
- * if (error.headers['X-Request-Id']) {
239
- * console.error('Request ID:', error.headers['X-Request-Id'])
238
+ * if (error.headers['x-faasjs-request-id']) {
239
+ * console.error('Request ID:', error.headers['x-faasjs-request-id'])
240
240
  * }
241
241
  * }
242
242
  * }
@@ -778,7 +778,7 @@ var FaasBrowserClient = class {
778
778
  }
779
779
  };
780
780
  //#endregion
781
- //#region src/faas.ts
781
+ //#region src/faas/index.ts
782
782
  /**
783
783
  * Call the currently configured FaasReactClient.
784
784
  *
@@ -814,7 +814,7 @@ async function faas(action, params, options) {
814
814
  return client.browserClient.action(action, params, options);
815
815
  }
816
816
  //#endregion
817
- //#region src/equal.ts
817
+ //#region src/equal/index.ts
818
818
  const AsyncFunction = (async () => {}).constructor;
819
819
  /**
820
820
  * Compares two values for deep equality.
@@ -982,6 +982,7 @@ function useEqualCallback(callback, dependencies) {
982
982
  * @param {JSX.Element | false} [props.fallback] - Element rendered before the first successful load.
983
983
  * @param {FaasAction<PathOrData>} props.action - Action path to request.
984
984
  * @param {FaasParams<PathOrData>} [props.params] - Params sent to the action.
985
+ * @param {number | false} [props.polling] - Milliseconds to wait after each completed request before refreshing data in the background.
985
986
  * @param {(args: FaasDataInjection<PathOrData>) => void} [props.onDataChange] - Callback invoked when the resolved data value changes.
986
987
  * @param {FaasData<PathOrData>} [props.data] - Controlled data value used instead of internal state.
987
988
  * @param {React.Dispatch<React.SetStateAction<FaasData<PathOrData>>>} [props.setData] - Controlled setter used instead of internal state.
@@ -1058,7 +1059,8 @@ function useEqualCallback(callback, dependencies) {
1058
1059
  const FaasDataWrapper = forwardRef((props, ref) => {
1059
1060
  const requestOptions = {
1060
1061
  ...props.data !== void 0 ? { data: props.data } : {},
1061
- ...props.setData ? { setData: props.setData } : {}
1062
+ ...props.setData ? { setData: props.setData } : {},
1063
+ ...props.polling !== void 0 ? { polling: props.polling } : {}
1062
1064
  };
1063
1065
  const request = getClient(props.baseUrl).useFaas(props.action, props.params ?? {}, requestOptions);
1064
1066
  const [loaded, setLoaded] = useState(false);
@@ -1081,15 +1083,16 @@ const FaasDataWrapper = forwardRef((props, ref) => {
1081
1083
  request.params,
1082
1084
  request.data,
1083
1085
  request.error,
1084
- request.loading
1086
+ request.loading,
1087
+ request.refreshing
1085
1088
  ]);
1086
1089
  });
1087
1090
  Object.assign(FaasDataWrapper, { displayName: "FaasDataWrapper" });
1088
1091
  /**
1089
1092
  * Wrap a component with {@link FaasDataWrapper} and inject Faas request state as props.
1090
1093
  *
1091
- * `withFaasData` is most useful for wrapper-style exports or compatibility with
1092
- * an existing component boundary. For new code, prefer `useFaas` or
1094
+ * `withFaasData` is most useful for wrapper-style exports or when you want to
1095
+ * preserve an existing component boundary. For new code, prefer `useFaas` or
1093
1096
  * `FaasDataWrapper` when they express the request ownership more directly.
1094
1097
  *
1095
1098
  * @template PathOrData - Action path or response data type used for inference.
@@ -1129,8 +1132,9 @@ function withFaasData(Component, faasProps) {
1129
1132
  /**
1130
1133
  * Run the shared request lifecycle used by the higher-level FaasJS React hooks.
1131
1134
  *
1132
- * It manages loading state, abort signals, debounce timing, retry-on-fetch-failure,
1133
- * and queued reload promises while delegating the actual transport to `send`.
1135
+ * It manages loading state, background refresh state, abort signals, debounce timing,
1136
+ * retry-on-fetch-failure, polling, and queued reload promises while delegating the
1137
+ * actual transport to `send`.
1134
1138
  *
1135
1139
  * @template Params - Request params type tracked by the lifecycle.
1136
1140
  * @template Result - Successful response payload type.
@@ -1138,8 +1142,8 @@ function withFaasData(Component, faasProps) {
1138
1142
  * @param {UseFaasRequestArgs<Params, Result, RequestPromise>} args - Request lifecycle configuration.
1139
1143
  * @param {string} args.action - Action path or request key used to trigger the lifecycle.
1140
1144
  * @param {Params} args.defaultParams - Initial params value stored by the lifecycle.
1141
- * @param {Pick<SharedUseFaasOptions<Params, Result>, 'params' | 'skip' | 'debounce' | 'baseUrl'>} args.options - Shared request options used by the lifecycle.
1142
- * @param {() => void} [args.beforeSend] - Optional callback invoked immediately before a request starts.
1145
+ * @param {Pick<SharedUseFaasOptions<Params, Result>, 'params' | 'skip' | 'debounce' | 'polling' | 'baseUrl'>} args.options - Shared request options used by the lifecycle.
1146
+ * @param {(args: { silent: boolean }) => void} [args.beforeSend] - Optional callback invoked immediately before a request starts.
1143
1147
  * @param {(result: Result) => void} [args.onSuccess] - Optional callback invoked after a successful response.
1144
1148
  * @param {UseFaasRequestArgs<Params, Result, RequestPromise>['send']} args.send - Transport function responsible for creating and resolving the request.
1145
1149
  * @returns Shared request state, reload helpers, and refs used by `useFaas` and `useFaasStream`.
@@ -1163,9 +1167,13 @@ function withFaasData(Component, faasProps) {
1163
1167
  */
1164
1168
  function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess, send }) {
1165
1169
  const [loading, setLoading] = useState(true);
1170
+ const [refreshing, setRefreshing] = useState(false);
1166
1171
  const [error, setError] = useState();
1167
1172
  const [params, setParams] = useState(defaultParams);
1168
- const [reloadTimes, setReloadTimes] = useState(0);
1173
+ const [requestTrigger, setRequestTrigger] = useState({
1174
+ times: 0,
1175
+ silent: false
1176
+ });
1169
1177
  const [skip, setSkip] = useState(typeof options.skip === "function" ? options.skip(defaultParams) : options.skip);
1170
1178
  const promiseRef = useRef(null);
1171
1179
  const controllerRef = useRef(null);
@@ -1173,6 +1181,9 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
1173
1181
  const pendingReloadsRef = useRef(/* @__PURE__ */ new Map());
1174
1182
  const reloadCounterRef = useRef(0);
1175
1183
  const requestVersionRef = useRef(0);
1184
+ const handledRequestTriggerTimesRef = useRef(-1);
1185
+ const pollingTimerRef = useRef(null);
1186
+ const hasLoadedRef = useRef(false);
1176
1187
  const beforeSendRef = useRef(beforeSend);
1177
1188
  const onSuccessRef = useRef(onSuccess);
1178
1189
  const sendRef = useRef(send);
@@ -1188,16 +1199,36 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
1188
1199
  useEqualEffect(() => {
1189
1200
  if (!action || skip) {
1190
1201
  setLoading(false);
1202
+ setRefreshing(false);
1191
1203
  return;
1192
1204
  }
1193
- setLoading(true);
1194
- beforeSendRef.current?.();
1205
+ const isSilentRequest = requestTrigger.times !== handledRequestTriggerTimesRef.current && requestTrigger.silent && hasLoadedRef.current;
1206
+ handledRequestTriggerTimesRef.current = requestTrigger.times;
1207
+ if (isSilentRequest) setRefreshing(true);
1208
+ else setLoading(true);
1209
+ beforeSendRef.current?.({ silent: isSilentRequest });
1195
1210
  failedOnceRef.current = false;
1196
1211
  const controller = new AbortController();
1197
1212
  const requestVersion = ++requestVersionRef.current;
1198
1213
  controllerRef.current = controller;
1199
1214
  const client = getClient(options.baseUrl);
1200
1215
  const requestParams = options.params || params;
1216
+ const clearPollingTimer = () => {
1217
+ if (!pollingTimerRef.current) return;
1218
+ clearTimeout(pollingTimerRef.current);
1219
+ pollingTimerRef.current = null;
1220
+ };
1221
+ const schedulePolling = () => {
1222
+ clearPollingTimer();
1223
+ if (!options.polling || options.polling <= 0 || !isCurrentRequest()) return;
1224
+ pollingTimerRef.current = setTimeout(() => {
1225
+ if (!isCurrentRequest()) return;
1226
+ setRequestTrigger((prev) => ({
1227
+ times: prev.times + 1,
1228
+ silent: true
1229
+ }));
1230
+ }, options.polling);
1231
+ };
1201
1232
  const rejectPending = (reason) => {
1202
1233
  for (const { reject } of pendingReloadsRef.current.values()) reject(reason);
1203
1234
  pendingReloadsRef.current.clear();
@@ -1221,8 +1252,11 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
1221
1252
  failedOnceRef.current = false;
1222
1253
  setError(null);
1223
1254
  onSuccessRef.current?.(result);
1255
+ hasLoadedRef.current = true;
1224
1256
  setLoading(false);
1257
+ setRefreshing(false);
1225
1258
  resolvePending(result);
1259
+ schedulePolling();
1226
1260
  }).catch(async (e) => {
1227
1261
  if (!isCurrentRequest()) return;
1228
1262
  if (typeof e?.message === "string" && e.message.toLowerCase().includes("aborted")) return;
@@ -1241,67 +1275,81 @@ function useFaasRequest({ action, defaultParams, options, beforeSend, onSuccess,
1241
1275
  if (!isCurrentRequest()) return;
1242
1276
  setError(nextError);
1243
1277
  setLoading(false);
1278
+ setRefreshing(false);
1244
1279
  rejectPending(nextError);
1280
+ schedulePolling();
1245
1281
  });
1246
1282
  };
1247
1283
  if (options.debounce) {
1248
1284
  const timeout = setTimeout(run, options.debounce);
1249
1285
  return () => {
1250
1286
  clearTimeout(timeout);
1287
+ clearPollingTimer();
1251
1288
  if (controllerRef.current === controller) controllerRef.current = null;
1252
1289
  controller.abort();
1253
1290
  setLoading(false);
1291
+ setRefreshing(false);
1254
1292
  };
1255
1293
  }
1256
1294
  run();
1257
1295
  return () => {
1296
+ clearPollingTimer();
1258
1297
  if (controllerRef.current === controller) controllerRef.current = null;
1259
1298
  controller.abort();
1260
1299
  setLoading(false);
1300
+ setRefreshing(false);
1261
1301
  };
1262
1302
  }, [
1263
1303
  action,
1264
1304
  options.params || params,
1265
- reloadTimes,
1266
- skip
1305
+ requestTrigger,
1306
+ skip,
1307
+ options.debounce,
1308
+ options.polling,
1309
+ options.baseUrl
1267
1310
  ]);
1311
+ const reload = useEqualCallback((nextParams, reloadOptions) => {
1312
+ if (skip) setSkip(false);
1313
+ if (nextParams) setParams(nextParams);
1314
+ const reloadCounter = ++reloadCounterRef.current;
1315
+ return new Promise((resolve, reject) => {
1316
+ pendingReloadsRef.current.set(reloadCounter, {
1317
+ resolve,
1318
+ reject
1319
+ });
1320
+ setRequestTrigger((prev) => ({
1321
+ times: prev.times + 1,
1322
+ silent: Boolean(reloadOptions?.silent)
1323
+ }));
1324
+ });
1325
+ }, [skip]);
1268
1326
  return {
1269
1327
  loading,
1328
+ refreshing,
1270
1329
  error,
1271
1330
  params,
1272
- reloadTimes,
1273
- reload: useEqualCallback((nextParams) => {
1274
- if (skip) setSkip(false);
1275
- if (nextParams) setParams(nextParams);
1276
- const reloadCounter = ++reloadCounterRef.current;
1277
- return new Promise((resolve, reject) => {
1278
- pendingReloadsRef.current.set(reloadCounter, {
1279
- resolve,
1280
- reject
1281
- });
1282
- setReloadTimes((prev) => prev + 1);
1283
- });
1284
- }, [skip]),
1331
+ reloadTimes: requestTrigger.times,
1332
+ reload,
1285
1333
  promiseRef,
1286
1334
  setError,
1287
1335
  setLoading
1288
1336
  };
1289
1337
  }
1290
1338
  //#endregion
1291
- //#region src/useFaas.tsx
1339
+ //#region src/useFaas/index.tsx
1292
1340
  /**
1293
1341
  * Request FaasJS data and keep request state in React state.
1294
1342
  *
1295
1343
  * `useFaas` is the default hook for standard FaasJS request-response flows in React.
1296
1344
  * It sends an initial request unless `skip` is enabled, and returns request state
1297
- * plus helpers for reloading, updating data, and handling errors.
1345
+ * plus helpers for reloading, background refreshing, updating data, and handling errors.
1298
1346
  *
1299
1347
  * @template PathOrData - Action path or response data type used for inference.
1300
1348
  *
1301
1349
  * @param {FaasAction<PathOrData>} action - Action path to invoke.
1302
1350
  * @param {FaasParams<PathOrData>} defaultParams - Params used for the initial request and future reloads.
1303
- * @param {useFaasOptions<PathOrData>} [options] - Optional hook configuration such as controlled data, skip logic, debounce timing, and base URL overrides.
1304
- * See the `useFaasOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, and `baseUrl`.
1351
+ * @param {useFaasOptions<PathOrData>} [options] - Optional hook configuration such as controlled data, skip logic, debounce timing, polling, and base URL overrides.
1352
+ * See the `useFaasOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, `polling`, and `baseUrl`.
1305
1353
  * @returns {FaasDataInjection<PathOrData>} Request state and helper methods described by {@link FaasDataInjection}.
1306
1354
  *
1307
1355
  * @example
@@ -1359,6 +1407,7 @@ function useFaas(action, defaultParams, options = {}) {
1359
1407
  action,
1360
1408
  params: request.params,
1361
1409
  loading: request.loading,
1410
+ refreshing: request.refreshing,
1362
1411
  data: currentData,
1363
1412
  reloadTimes: request.reloadTimes,
1364
1413
  error: request.error,
@@ -1469,7 +1518,7 @@ function getClient(host) {
1469
1518
  return client;
1470
1519
  }
1471
1520
  //#endregion
1472
- //#region src/constant.ts
1521
+ //#region src/constant/index.ts
1473
1522
  /**
1474
1523
  * Returns a constant value that is created by the given function.
1475
1524
  *
@@ -1494,7 +1543,7 @@ function useConstant(fn) {
1494
1543
  return ref.current.v;
1495
1544
  }
1496
1545
  //#endregion
1497
- //#region src/ErrorBoundary.tsx
1546
+ //#region src/ErrorBoundary/index.tsx
1498
1547
  /**
1499
1548
  * React error boundary with an optional custom fallback element.
1500
1549
  *
@@ -1568,7 +1617,7 @@ var ErrorBoundary = class extends Component {
1568
1617
  }
1569
1618
  };
1570
1619
  //#endregion
1571
- //#region src/OptionalWrapper.tsx
1620
+ //#region src/OptionalWrapper/index.tsx
1572
1621
  /**
1573
1622
  * Conditionally wrap children with another component.
1574
1623
  *
@@ -1604,7 +1653,7 @@ function OptionalWrapper(props) {
1604
1653
  }
1605
1654
  OptionalWrapper.displayName = "OptionalWrapper";
1606
1655
  //#endregion
1607
- //#region src/splittingState.tsx
1656
+ //#region src/splittingState/index.tsx
1608
1657
  /**
1609
1658
  * Create local state entries and matching setters for each key in an object.
1610
1659
  *
@@ -1633,7 +1682,7 @@ function useSplittingState(initialStates) {
1633
1682
  return states;
1634
1683
  }
1635
1684
  //#endregion
1636
- //#region src/splittingContext.tsx
1685
+ //#region src/splittingContext/index.tsx
1637
1686
  /**
1638
1687
  * Create a context whose keys can be consumed independently.
1639
1688
  *
@@ -1721,7 +1770,7 @@ function createSplittingContext(defaultValue) {
1721
1770
  };
1722
1771
  }
1723
1772
  //#endregion
1724
- //#region src/useFaasStream.tsx
1773
+ //#region src/useFaasStream/index.tsx
1725
1774
  /**
1726
1775
  * Stream a FaasJS response into React state.
1727
1776
  *
@@ -1731,8 +1780,8 @@ function createSplittingContext(defaultValue) {
1731
1780
  *
1732
1781
  * @param {string} action - Action path to invoke.
1733
1782
  * @param {Record<string, any>} defaultParams - Params used for the initial request and future reloads.
1734
- * @param {UseFaasStreamOptions} [options] - Optional hook configuration such as controlled stream text, skip logic, debounce timing, and base URL overrides.
1735
- * See the `UseFaasStreamOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, and `baseUrl`.
1783
+ * @param {UseFaasStreamOptions} [options] - Optional hook configuration such as controlled stream text, skip logic, debounce timing, polling, and base URL overrides.
1784
+ * See the `UseFaasStreamOptions` type for `params`, `data`, `setData`, `skip`, `debounce`, `polling`, and `baseUrl`.
1736
1785
  * @returns {UseFaasStreamResult} Streaming request state and helper methods described by {@link UseFaasStreamResult}.
1737
1786
  *
1738
1787
  * @example
@@ -1766,7 +1815,9 @@ function useFaasStream(action, defaultParams, options = {}) {
1766
1815
  action,
1767
1816
  defaultParams,
1768
1817
  options,
1769
- beforeSend: () => updateData(""),
1818
+ beforeSend: ({ silent }) => {
1819
+ if (!silent) updateData("");
1820
+ },
1770
1821
  send: async ({ action, params, signal, client }) => {
1771
1822
  const response = await client.browserClient.action(action, params, {
1772
1823
  signal,
@@ -1809,6 +1860,7 @@ function useFaasStream(action, defaultParams, options = {}) {
1809
1860
  action,
1810
1861
  params: request.params,
1811
1862
  loading: request.loading,
1863
+ refreshing: request.refreshing,
1812
1864
  reloadTimes: request.reloadTimes,
1813
1865
  data: options.data ?? data,
1814
1866
  error: request.error,
@@ -1819,7 +1871,7 @@ function useFaasStream(action, defaultParams, options = {}) {
1819
1871
  };
1820
1872
  }
1821
1873
  //#endregion
1822
- //#region src/usePrevious.ts
1874
+ //#region src/usePrevious/index.ts
1823
1875
  /**
1824
1876
  * Hook to store the previous value of a state or prop.
1825
1877
  *
@@ -1846,7 +1898,7 @@ function usePrevious(value) {
1846
1898
  return ref.current;
1847
1899
  }
1848
1900
  //#endregion
1849
- //#region src/useStateRef.ts
1901
+ //#region src/useStateRef/index.ts
1850
1902
  /**
1851
1903
  * Custom hook that returns a stateful value and a ref to that value.
1852
1904
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@faasjs/react",
3
- "version": "8.0.0-beta.25",
3
+ "version": "8.0.0-beta.27",
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.25",
29
+ "@faasjs/types": ">=8.0.0-beta.27",
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.25"
34
+ "@faasjs/types": ">=8.0.0-beta.27"
35
35
  },
36
36
  "engines": {
37
37
  "node": ">=24.0.0",