@squide/firefly 10.0.0 → 11.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/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @squide/firefly
2
2
 
3
+ ## 11.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#247](https://github.com/workleap/wl-squide/pull/247) [`ddcb106`](https://github.com/workleap/wl-squide/commit/ddcb106a6b3522e09d1ab92c417725185ffc64e6) Thanks [@patricklafrance](https://github.com/patricklafrance)! - The `bootstrap` function is not async anymore.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`ddcb106`](https://github.com/workleap/wl-squide/commit/ddcb106a6b3522e09d1ab92c417725185ffc64e6), [`ddcb106`](https://github.com/workleap/wl-squide/commit/ddcb106a6b3522e09d1ab92c417725185ffc64e6)]:
12
+ - @squide/core@5.4.4
13
+ - @squide/module-federation@6.2.4
14
+ - @squide/msw@3.2.4
15
+ - @squide/react-router@7.0.2
16
+
17
+ ## 10.0.1
18
+
19
+ ### Patch Changes
20
+
21
+ - [#244](https://github.com/workleap/wl-squide/pull/244) [`5d13eb0`](https://github.com/workleap/wl-squide/commit/5d13eb038a724b499b820d7e1dc864c87954510b) Thanks [@patricklafrance](https://github.com/patricklafrance)! - Updated dependencies.
22
+
23
+ - Updated dependencies [[`5d13eb0`](https://github.com/workleap/wl-squide/commit/5d13eb038a724b499b820d7e1dc864c87954510b)]:
24
+ - @squide/module-federation@6.2.3
25
+ - @squide/react-router@7.0.1
26
+ - @squide/core@5.4.3
27
+ - @squide/msw@3.2.3
28
+
3
29
  ## 10.0.0
4
30
 
5
31
  ### Major Changes
@@ -1,6 +1,7 @@
1
1
  import { type Route } from "@squide/react-router";
2
2
  import { type ReactElement } from "react";
3
3
  import type { RouterProviderProps } from "react-router/dom";
4
+ import { type AppRouterState } from "./AppRouterReducer.ts";
4
5
  export interface AppRouterRenderFunctionArgs {
5
6
  routes: Route[];
6
7
  }
@@ -10,6 +11,7 @@ export interface RenderRouterProviderFunctionArgs {
10
11
  routerProviderProps: Omit<RouterProviderProps, "router">;
11
12
  }
12
13
  export type RenderRouterProviderFunction = (args: RenderRouterProviderFunctionArgs) => ReactElement;
14
+ export declare function useCanRenderRouter({ areModulesRegistered, areModulesReady: areModulesReadyValue }: AppRouterState): boolean;
13
15
  export interface AppRouterProps {
14
16
  waitForMsw: boolean;
15
17
  waitForPublicData?: boolean;
package/dist/AppRouter.js CHANGED
@@ -32,11 +32,35 @@ import * as __WEBPACK_EXTERNAL_MODULE__useStrictRegistrationMode_js_f67d8785__ f
32
32
 
33
33
 
34
34
 
35
+ function useCanRenderRouter({ areModulesRegistered, areModulesReady: areModulesReadyValue }) {
36
+ return(// Wait until the modules has been registered, but do not wait for the deferred registrations to be registered has they will probably
37
+ // depends on the protected data.
38
+ areModulesRegistered || areModulesReadyValue);
39
+ }
40
+ function useRenderRouterProvider(state, renderRouterProvider) {
41
+ const routes = (0,__WEBPACK_EXTERNAL_MODULE__squide_react_router_299a4bef__.useRoutes)();
42
+ // The value is computed outside of the router provider memo to prevent
43
+ // rendering a new router provider everytime the app router state change.
44
+ const canRenderRouter = useCanRenderRouter(state);
45
+ return (0,__WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
46
+ if (canRenderRouter) {
47
+ return renderRouterProvider({
48
+ rootRoute: /*#__PURE__*/ (0,__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__RootRoute_js_5c2fbb69__.RootRoute, {}),
49
+ registeredRoutes: routes,
50
+ routerProviderProps: {}
51
+ });
52
+ }
53
+ return null;
54
+ }, [
55
+ canRenderRouter,
56
+ routes,
57
+ renderRouterProvider
58
+ ]);
59
+ }
35
60
  function AppRouter(props) {
36
61
  const { waitForMsw, waitForPublicData = false, waitForProtectedData = false, children: renderRouterProvider } = props;
37
62
  const [state, dispatch] = (0,__WEBPACK_EXTERNAL_MODULE__AppRouterReducer_js_6fa81ecc__.useAppRouterReducer)(waitForMsw, waitForPublicData, waitForProtectedData);
38
63
  const logger = (0,__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.useLogger)();
39
- const routes = (0,__WEBPACK_EXTERNAL_MODULE__squide_react_router_299a4bef__.useRoutes)();
40
64
  (0,__WEBPACK_EXTERNAL_MODULE__useStrictRegistrationMode_js_f67d8785__.useStrictRegistrationMode)();
41
65
  (0,__WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
42
66
  logger.debug("[squide] AppRouter state updated:", state);
@@ -44,16 +68,7 @@ function AppRouter(props) {
44
68
  state,
45
69
  logger
46
70
  ]);
47
- const routerProvider = (0,__WEBPACK_EXTERNAL_MODULE_react__.useMemo)(()=>{
48
- return renderRouterProvider({
49
- rootRoute: /*#__PURE__*/ (0,__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__RootRoute_js_5c2fbb69__.RootRoute, {}),
50
- registeredRoutes: routes,
51
- routerProviderProps: {}
52
- });
53
- }, [
54
- routes,
55
- renderRouterProvider
56
- ]);
71
+ const routerProvider = useRenderRouterProvider(state, renderRouterProvider);
57
72
  return /*#__PURE__*/ (0,__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__AppRouterContext_js_3c4a3c33__.AppRouterDispatcherContext.Provider, {
58
73
  value: dispatch,
59
74
  children: /*#__PURE__*/ (0,__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__AppRouterContext_js_3c4a3c33__.AppRouterStateContext.Provider, {
@@ -63,6 +78,6 @@ function AppRouter(props) {
63
78
  });
64
79
  }
65
80
 
66
- export { AppRouter };
81
+ export { AppRouter, useCanRenderRouter };
67
82
 
68
83
  //# sourceMappingURL=AppRouter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppRouter.js","sources":["webpack://@squide/firefly/./src/AppRouter.tsx"],"sourcesContent":["import { useLogger } from \"@squide/core\";\nimport { useRoutes, type Route } from \"@squide/react-router\";\nimport { useEffect, useMemo, type ReactElement } from \"react\";\nimport type { RouterProviderProps } from \"react-router/dom\";\nimport { AppRouterDispatcherContext, AppRouterStateContext } from \"./AppRouterContext.ts\";\nimport { useAppRouterReducer } from \"./AppRouterReducer.ts\";\nimport { RootRoute } from \"./RootRoute.tsx\";\nimport { useStrictRegistrationMode } from \"./useStrictRegistrationMode.ts\";\n\nexport interface AppRouterRenderFunctionArgs {\n routes: Route[];\n}\n\nexport interface RenderRouterProviderFunctionArgs {\n rootRoute: ReactElement;\n registeredRoutes: Route[];\n routerProviderProps: Omit<RouterProviderProps, \"router\">;\n}\n\nexport type RenderRouterProviderFunction = (args: RenderRouterProviderFunctionArgs) => ReactElement;\n\nexport interface AppRouterProps {\n waitForMsw: boolean;\n waitForPublicData?: boolean;\n waitForProtectedData?: boolean;\n children: RenderRouterProviderFunction;\n}\n\nexport function AppRouter(props: AppRouterProps) {\n const {\n waitForMsw,\n waitForPublicData = false,\n waitForProtectedData = false,\n children: renderRouterProvider\n } = props;\n\n const [state, dispatch] = useAppRouterReducer(waitForMsw, waitForPublicData, waitForProtectedData);\n\n const logger = useLogger();\n const routes = useRoutes();\n\n useStrictRegistrationMode();\n\n useEffect(() => {\n logger.debug(\"[squide] AppRouter state updated:\", state);\n }, [state, logger]);\n\n const routerProvider = useMemo(() => {\n return renderRouterProvider({\n rootRoute: <RootRoute />,\n registeredRoutes: routes,\n routerProviderProps: {}\n });\n }, [routes, renderRouterProvider]);\n\n return (\n <AppRouterDispatcherContext.Provider value={dispatch}>\n <AppRouterStateContext.Provider value={state}>\n {routerProvider}\n </AppRouterStateContext.Provider>\n </AppRouterDispatcherContext.Provider>\n );\n}\n"],"names":["useLogger","useRoutes","useEffect","useMemo","AppRouterDispatcherContext","AppRouterStateContext","useAppRouterReducer","RootRoute","useStrictRegistrationMode","AppRouter","props","waitForMsw","waitForPublicData","waitForProtectedData","renderRouterProvider","state","dispatch","logger","routes","routerProvider"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAyC;AACoB;AACC;AAE4B;AAC9B;AAChB;AAC+B;AAqBpE,SAASS,UAAUC,KAAqB;IAC3C,MAAM,EACFC,UAAU,EACVC,oBAAoB,KAAK,EACzBC,uBAAuB,KAAK,EAC5B,UAAUC,oBAAoB,EACjC,GAAGJ;IAEJ,MAAM,CAACK,OAAOC,SAAS,GAAGV,iFAAmBA,CAACK,YAAYC,mBAAmBC;IAE7E,MAAMI,SAASjB,+DAASA;IACxB,MAAMkB,SAASjB,uEAASA;IAExBO,gGAAyBA;IAEzBN,+CAASA,CAAC;QACNe,OAAO,KAAK,CAAC,qCAAqCF;IACtD,GAAG;QAACA;QAAOE;KAAO;IAElB,MAAME,iBAAiBhB,6CAAOA,CAAC;QAC3B,OAAOW,qBAAqB;YACxB,yBAAW,+DAACP,4DAASA;YACrB,kBAAkBW;YAClB,qBAAqB,CAAC;QAC1B;IACJ,GAAG;QAACA;QAAQJ;KAAqB;IAEjC,qBACI,+DAACV,6FAAmC;QAAC,OAAOY;kBACxC,6EAACX,wFAA8B;YAAC,OAAOU;sBAClCI;;;AAIjB"}
1
+ {"version":3,"file":"AppRouter.js","sources":["webpack://@squide/firefly/./src/AppRouter.tsx"],"sourcesContent":["import { useLogger } from \"@squide/core\";\nimport { useRoutes, type Route } from \"@squide/react-router\";\nimport { useEffect, useMemo, type ReactElement } from \"react\";\nimport type { RouterProviderProps } from \"react-router/dom\";\nimport { AppRouterDispatcherContext, AppRouterStateContext } from \"./AppRouterContext.ts\";\nimport { useAppRouterReducer, type AppRouterState } from \"./AppRouterReducer.ts\";\nimport { RootRoute } from \"./RootRoute.tsx\";\nimport { useStrictRegistrationMode } from \"./useStrictRegistrationMode.ts\";\n\nexport interface AppRouterRenderFunctionArgs {\n routes: Route[];\n}\n\nexport interface RenderRouterProviderFunctionArgs {\n rootRoute: ReactElement;\n registeredRoutes: Route[];\n routerProviderProps: Omit<RouterProviderProps, \"router\">;\n}\n\nexport type RenderRouterProviderFunction = (args: RenderRouterProviderFunctionArgs) => ReactElement;\n\nexport function useCanRenderRouter({ areModulesRegistered, areModulesReady: areModulesReadyValue }: AppRouterState) {\n return (\n // Wait until the modules has been registered, but do not wait for the deferred registrations to be registered has they will probably\n // depends on the protected data.\n (areModulesRegistered || areModulesReadyValue)\n );\n}\n\nfunction useRenderRouterProvider(state: AppRouterState, renderRouterProvider: RenderRouterProviderFunction) {\n const routes = useRoutes();\n\n // The value is computed outside of the router provider memo to prevent\n // rendering a new router provider everytime the app router state change.\n const canRenderRouter = useCanRenderRouter(state);\n\n return useMemo(() => {\n if (canRenderRouter) {\n return renderRouterProvider({\n rootRoute: <RootRoute />,\n registeredRoutes: routes,\n routerProviderProps: {}\n });\n }\n\n return null;\n }, [canRenderRouter, routes, renderRouterProvider]);\n}\n\nexport interface AppRouterProps {\n waitForMsw: boolean;\n waitForPublicData?: boolean;\n waitForProtectedData?: boolean;\n children: RenderRouterProviderFunction;\n}\n\nexport function AppRouter(props: AppRouterProps) {\n const {\n waitForMsw,\n waitForPublicData = false,\n waitForProtectedData = false,\n children: renderRouterProvider\n } = props;\n\n const [state, dispatch] = useAppRouterReducer(waitForMsw, waitForPublicData, waitForProtectedData);\n\n const logger = useLogger();\n\n useStrictRegistrationMode();\n\n useEffect(() => {\n logger.debug(\"[squide] AppRouter state updated:\", state);\n }, [state, logger]);\n\n const routerProvider = useRenderRouterProvider(state, renderRouterProvider);\n\n return (\n <AppRouterDispatcherContext.Provider value={dispatch}>\n <AppRouterStateContext.Provider value={state}>\n {routerProvider}\n </AppRouterStateContext.Provider>\n </AppRouterDispatcherContext.Provider>\n );\n}\n"],"names":["useLogger","useRoutes","useEffect","useMemo","AppRouterDispatcherContext","AppRouterStateContext","useAppRouterReducer","RootRoute","useStrictRegistrationMode","useCanRenderRouter","areModulesRegistered","areModulesReadyValue","useRenderRouterProvider","state","renderRouterProvider","routes","canRenderRouter","AppRouter","props","waitForMsw","waitForPublicData","waitForProtectedData","dispatch","logger","routerProvider"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAyC;AACoB;AACC;AAE4B;AACT;AACrC;AAC+B;AAcpE,SAASS,mBAAmB,EAAEC,oBAAoB,EAAE,iBAAiBC,oBAAoB,EAAkB;IAC9G,OACI,qIAAqI;IACrI,iCAAiC;IAChCD,wBAAwBC;AAEjC;AAEA,SAASC,wBAAwBC,KAAqB,EAAEC,oBAAkD;IACtG,MAAMC,SAASd,uEAASA;IAExB,uEAAuE;IACvE,yEAAyE;IACzE,MAAMe,kBAAkBP,mBAAmBI;IAE3C,OAAOV,6CAAOA,CAAC;QACX,IAAIa,iBAAiB;YACjB,OAAOF,qBAAqB;gBACxB,yBAAW,+DAACP,4DAASA;gBACrB,kBAAkBQ;gBAClB,qBAAqB,CAAC;YAC1B;QACJ;QAEA,OAAO;IACX,GAAG;QAACC;QAAiBD;QAAQD;KAAqB;AACtD;AASO,SAASG,UAAUC,KAAqB;IAC3C,MAAM,EACFC,UAAU,EACVC,oBAAoB,KAAK,EACzBC,uBAAuB,KAAK,EAC5B,UAAUP,oBAAoB,EACjC,GAAGI;IAEJ,MAAM,CAACL,OAAOS,SAAS,GAAGhB,iFAAmBA,CAACa,YAAYC,mBAAmBC;IAE7E,MAAME,SAASvB,+DAASA;IAExBQ,gGAAyBA;IAEzBN,+CAASA,CAAC;QACNqB,OAAO,KAAK,CAAC,qCAAqCV;IACtD,GAAG;QAACA;QAAOU;KAAO;IAElB,MAAMC,iBAAiBZ,wBAAwBC,OAAOC;IAEtD,qBACI,+DAACV,6FAAmC;QAAC,OAAOkB;kBACxC,6EAACjB,wFAA8B;YAAC,OAAOQ;sBAClCW;;;AAIjB"}
@@ -227,7 +227,7 @@ function useMswStatusDispatcher(isMswReadyValue, dispatch) {
227
227
  function useBootstrappingCompletedDispatcher(state) {
228
228
  const eventBus = (0,__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.useEventBus)();
229
229
  const areModulesRegisteredValue = state.areModulesRegistered;
230
- const isBoostrapping = (0,__WEBPACK_EXTERNAL_MODULE__useIsBootstrapping_js_642a9b43__.isApplicationBootstrapping)(state);
230
+ const isBoostrapping = (0,__WEBPACK_EXTERNAL_MODULE__useIsBootstrapping_js_642a9b43__.isBootstrapping)(state);
231
231
  (0,__WEBPACK_EXTERNAL_MODULE__useExecuteOnce_js_e1f8f91b__.useExecuteOnce)((0,__WEBPACK_EXTERNAL_MODULE_react__.useCallback)(()=>{
232
232
  if (areModulesRegisteredValue && !isBoostrapping) {
233
233
  eventBus.dispatch(ApplicationBoostrappedEvent);
@@ -1 +1 @@
1
- {"version":3,"file":"AppRouterReducer.js","sources":["webpack://@squide/firefly/./src/AppRouterReducer.ts"],"sourcesContent":["import { addLocalModuleRegistrationStatusChangedListener, getLocalModuleRegistrationStatus, removeLocalModuleRegistrationStatusChangedListener, useEventBus, useLogger } from \"@squide/core\";\nimport { addRemoteModuleRegistrationStatusChangedListener, areModulesReady, areModulesRegistered, getRemoteModuleRegistrationStatus, removeRemoteModuleRegistrationStatusChangedListener } from \"@squide/module-federation\";\nimport { addMswStateChangedListener, isMswReady, removeMswStateChangedListener } from \"@squide/msw\";\nimport { useCallback, useEffect, useMemo, useReducer, type Dispatch } from \"react\";\nimport { useExecuteOnce } from \"./useExecuteOnce.ts\";\nimport { isApplicationBootstrapping } from \"./useIsBootstrapping.ts\";\n\nexport type ActiveRouteVisiblity = \"unknown\" | \"public\" | \"protected\";\n\nexport interface AppRouterState {\n waitForMsw: boolean;\n waitForPublicData: boolean;\n waitForProtectedData: boolean;\n areModulesRegistered: boolean;\n areModulesReady: boolean;\n isMswReady: boolean;\n isPublicDataReady: boolean;\n isProtectedDataReady: boolean;\n publicDataUpdatedAt?: number;\n protectedDataUpdatedAt?: number;\n deferredRegistrationsUpdatedAt?: number;\n activeRouteVisibility: ActiveRouteVisiblity;\n isUnauthorized: boolean;\n}\n\nexport type AppRouterActionType =\n| \"modules-registered\"\n| \"modules-ready\"\n| \"msw-ready\"\n| \"public-data-ready\"\n| \"protected-data-ready\"\n| \"public-data-updated\"\n| \"protected-data-updated\"\n| \"deferred-registrations-updated\"\n| \"active-route-is-public\"\n| \"active-route-is-protected\"\n| \"is-unauthorized\";\n\n// The followings event const are a concatenation of \"squide-\" with AppRouterActionType.\n// They are dispatched by the useEnhancedReducerDispatch hook.\nexport const ModulesRegisteredEvent = \"squide-modules-registered\";\nexport const ModulesReadyEvent = \"squide-modules-ready\";\nexport const MswReadyEvent = \"squide-msw-ready\";\nexport const PublicDataReadyEvent = \"squide-public-data-ready\";\nexport const ProtectedDataReadyEvent = \"squide-protected-data-ready\";\nexport const PublicDataUpdatedEvent = \"squide-public-data-updated\";\nexport const ProtectedDataUpdatedEvent = \"squide-protected-data-updated\";\nexport const DeferredRegistrationsUpdatedEvent = \"squide-deferred-registrations-updated\";\nexport const ApplicationBoostrappedEvent = \"squide-app-boostrapped\";\n\nexport interface AppRouterAction {\n type: AppRouterActionType;\n}\n\nexport type AppRouterDispatch = Dispatch<AppRouterAction>;\n\nfunction reducer(state: AppRouterState, action: AppRouterAction) {\n let newState = state;\n\n switch (action.type) {\n case \"modules-registered\": {\n newState = {\n ...newState,\n areModulesRegistered: true\n };\n\n break;\n }\n case \"modules-ready\": {\n newState = {\n ...newState,\n areModulesReady: true,\n // Will be set even if the app is not using deferred registrations.\n deferredRegistrationsUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"msw-ready\": {\n newState = {\n ...newState,\n isMswReady: true\n };\n\n break;\n }\n case \"public-data-ready\": {\n newState = {\n ...newState,\n isPublicDataReady: true,\n publicDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"protected-data-ready\": {\n newState = {\n ...newState,\n isProtectedDataReady: true,\n protectedDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"public-data-updated\": {\n newState = {\n ...newState,\n publicDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"protected-data-updated\": {\n newState = {\n ...newState,\n protectedDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"deferred-registrations-updated\": {\n newState = {\n ...newState,\n deferredRegistrationsUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"active-route-is-public\": {\n newState = {\n ...newState,\n activeRouteVisibility: \"public\"\n };\n\n break;\n }\n case \"active-route-is-protected\": {\n newState = {\n ...newState,\n activeRouteVisibility: \"protected\"\n };\n\n break;\n }\n case \"is-unauthorized\": {\n newState = {\n ...newState,\n isUnauthorized: true\n };\n\n break;\n }\n default: {\n throw new Error(`[squide] The AppRouter component state reducer doesn't support action type \"${action.type}\".`);\n }\n }\n\n return newState;\n}\n\nexport function getAreModulesRegistered() {\n const localModuleStatus = getLocalModuleRegistrationStatus();\n const remoteModuleStatus = getRemoteModuleRegistrationStatus();\n\n return areModulesRegistered(localModuleStatus, remoteModuleStatus);\n}\n\nexport function getAreModulesReady() {\n const localModuleStatus = getLocalModuleRegistrationStatus();\n const remoteModuleStatus = getRemoteModuleRegistrationStatus();\n\n return areModulesReady(localModuleStatus, remoteModuleStatus);\n}\n\nexport function useModuleRegistrationStatusDispatcher(areModulesRegisteredValue: boolean, areModulesReadyValue: boolean, dispatch: AppRouterDispatch) {\n const logger = useLogger();\n\n const dispatchModulesRegistered = useExecuteOnce(useCallback(() => {\n if (getAreModulesRegistered()) {\n dispatch({ type: \"modules-registered\" });\n\n logger.debug(\"[squide] %cModules are registered%c.\", \"color: white; background-color: green;\", \"\");\n\n return true;\n }\n\n return false;\n }, [dispatch, logger]));\n\n const dispatchModulesReady = useExecuteOnce(useCallback(() => {\n if (getAreModulesReady()) {\n dispatch({ type: \"modules-ready\" });\n\n logger.debug(\"[squide] %cModules are ready%c.\", \"color: white; background-color: green;\", \"\");\n\n return true;\n }\n\n return false;\n }, [dispatch, logger]));\n\n return useEffect(() => {\n if (!areModulesRegisteredValue) {\n addLocalModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n addRemoteModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n }\n\n if (!areModulesReadyValue) {\n addLocalModuleRegistrationStatusChangedListener(dispatchModulesReady);\n addRemoteModuleRegistrationStatusChangedListener(dispatchModulesReady);\n }\n\n return () => {\n removeLocalModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n removeRemoteModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n\n removeLocalModuleRegistrationStatusChangedListener(dispatchModulesReady);\n removeRemoteModuleRegistrationStatusChangedListener(dispatchModulesReady);\n };\n }, [areModulesRegisteredValue, areModulesReadyValue, dispatchModulesRegistered, dispatchModulesReady]);\n}\n\nexport function useMswStatusDispatcher(isMswReadyValue: boolean, dispatch: AppRouterDispatch) {\n const logger = useLogger();\n\n const dispatchMswReady = useExecuteOnce(useCallback(() => {\n if (isMswReady()) {\n dispatch({ type: \"msw-ready\" });\n\n logger.debug(\"[squide] %cMSW is ready%c.\", \"color: white; background-color: green;\", \"\");\n\n return true;\n }\n\n return false;\n }, [dispatch, logger]));\n\n useEffect(() => {\n if (!isMswReadyValue) {\n addMswStateChangedListener(dispatchMswReady);\n }\n\n return () => {\n removeMswStateChangedListener(dispatchMswReady);\n };\n }, [isMswReadyValue, dispatchMswReady]);\n}\n\nexport function useBootstrappingCompletedDispatcher(state: AppRouterState) {\n const eventBus = useEventBus();\n\n const areModulesRegisteredValue = state.areModulesRegistered;\n const isBoostrapping = isApplicationBootstrapping(state);\n\n useExecuteOnce(useCallback(() => {\n if (areModulesRegisteredValue && !isBoostrapping) {\n eventBus.dispatch(ApplicationBoostrappedEvent);\n\n return true;\n }\n\n return false;\n }, [areModulesRegisteredValue, isBoostrapping, eventBus]), true);\n}\n\nlet dispatchProxyFactory: ((reactDispatch: AppRouterDispatch) => AppRouterDispatch) | undefined;\n\n// This function should only be used by tests.\nexport function __setAppReducerDispatchProxyFactory(factory: (reactDispatch: AppRouterDispatch) => AppRouterDispatch) {\n dispatchProxyFactory = factory;\n}\n\n// This function should only be used by tests.\nexport function __clearAppReducerDispatchProxy() {\n dispatchProxyFactory = undefined;\n}\n\nfunction useReducerDispatchProxy(reactDispatch: AppRouterDispatch) {\n return useMemo(() => {\n return dispatchProxyFactory ? dispatchProxyFactory(reactDispatch) : reactDispatch;\n }, [reactDispatch]);\n}\n\nfunction useEnhancedReducerDispatch(reducerDispatch: AppRouterDispatch) {\n const logger = useLogger();\n const eventBus = useEventBus();\n\n return useCallback((action: AppRouterAction) => {\n logger.debug(\"[squide] The following action has been dispatched to the AppRouter reducer:\", action);\n eventBus.dispatch(`squide-${action.type}`);\n\n reducerDispatch(action);\n }, [reducerDispatch, logger, eventBus]);\n}\n\nexport function useAppRouterReducer(waitForMsw: boolean, waitForPublicData: boolean, waitForProtectedData: boolean): [AppRouterState, AppRouterDispatch] {\n const areModulesInitiallyRegistered = getAreModulesRegistered();\n const areModulesInitiallyReady = getAreModulesReady();\n const isMswInitiallyReady = isMswReady();\n\n const eventBus = useEventBus();\n\n // When modules are initially registered, the reducer action will never be dispatched, therefore the event would not be dispatched as well.\n // To ensure the bootstrapping events sequencing, the event is manually dispatched when the modules are initially registered.\n useExecuteOnce(useCallback(() => {\n if (areModulesInitiallyRegistered) {\n eventBus.dispatch(ModulesRegisteredEvent);\n }\n\n return true;\n }, [areModulesInitiallyRegistered, eventBus]), true);\n\n // When modules are initially registered, the reducer action will never be dispatched, therefore the event would not be dispatched as well.\n // To ensure the bootstrapping events sequencing, the event is manually dispatched when the modules are initially registered.\n useExecuteOnce(useCallback(() => {\n if (areModulesInitiallyReady) {\n eventBus.dispatch(ModulesReadyEvent);\n }\n\n return true;\n }, [areModulesInitiallyReady, eventBus]), true);\n\n // When modules are initially registered, the reducer action will never be dispatched, therefore the event would not be dispatched as well.\n // To ensure the bootstrapping events sequencing, the event is manually dispatched when the modules are initially registered.\n useExecuteOnce(useCallback(() => {\n if (isMswInitiallyReady) {\n eventBus.dispatch(MswReadyEvent);\n }\n\n return true;\n }, [isMswInitiallyReady, eventBus]), true);\n\n const [state, reactDispatch] = useReducer(reducer, {\n waitForMsw,\n waitForPublicData,\n waitForProtectedData,\n // When the modules registration functions are awaited, the event listeners are registered after the modules are registered.\n areModulesRegistered: areModulesInitiallyRegistered,\n areModulesReady: areModulesInitiallyReady,\n isMswReady: isMswInitiallyReady,\n isPublicDataReady: false,\n isProtectedDataReady: false,\n activeRouteVisibility: \"unknown\",\n isUnauthorized: false\n });\n\n const {\n areModulesRegistered: areModulesRegisteredValue,\n areModulesReady: areModulesReadyValue,\n isMswReady: isMswReadyValue\n } = state;\n\n // The dispatch proxy is strictly an utility allowing tests to mock the useReducer dispatch function. It's easier\n // than mocking the import from React.\n const dispatchProxy = useReducerDispatchProxy(reactDispatch);\n const dispatch = useEnhancedReducerDispatch(dispatchProxy);\n\n useModuleRegistrationStatusDispatcher(areModulesRegisteredValue, areModulesReadyValue, dispatch);\n useMswStatusDispatcher(isMswReadyValue, dispatch);\n useBootstrappingCompletedDispatcher(state);\n\n return [state, dispatch];\n}\n"],"names":["addLocalModuleRegistrationStatusChangedListener","getLocalModuleRegistrationStatus","removeLocalModuleRegistrationStatusChangedListener","useEventBus","useLogger","addRemoteModuleRegistrationStatusChangedListener","areModulesReady","areModulesRegistered","getRemoteModuleRegistrationStatus","removeRemoteModuleRegistrationStatusChangedListener","addMswStateChangedListener","isMswReady","removeMswStateChangedListener","useCallback","useEffect","useMemo","useReducer","useExecuteOnce","isApplicationBootstrapping","ModulesRegisteredEvent","ModulesReadyEvent","MswReadyEvent","PublicDataReadyEvent","ProtectedDataReadyEvent","PublicDataUpdatedEvent","ProtectedDataUpdatedEvent","DeferredRegistrationsUpdatedEvent","ApplicationBoostrappedEvent","reducer","state","action","newState","Date","Error","getAreModulesRegistered","localModuleStatus","remoteModuleStatus","getAreModulesReady","useModuleRegistrationStatusDispatcher","areModulesRegisteredValue","areModulesReadyValue","dispatch","logger","dispatchModulesRegistered","dispatchModulesReady","useMswStatusDispatcher","isMswReadyValue","dispatchMswReady","useBootstrappingCompletedDispatcher","eventBus","isBoostrapping","dispatchProxyFactory","__setAppReducerDispatchProxyFactory","factory","__clearAppReducerDispatchProxy","undefined","useReducerDispatchProxy","reactDispatch","useEnhancedReducerDispatch","reducerDispatch","useAppRouterReducer","waitForMsw","waitForPublicData","waitForProtectedData","areModulesInitiallyRegistered","areModulesInitiallyReady","isMswInitiallyReady","dispatchProxy"],"mappings":"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"}
1
+ {"version":3,"file":"AppRouterReducer.js","sources":["webpack://@squide/firefly/./src/AppRouterReducer.ts"],"sourcesContent":["import { addLocalModuleRegistrationStatusChangedListener, getLocalModuleRegistrationStatus, removeLocalModuleRegistrationStatusChangedListener, useEventBus, useLogger } from \"@squide/core\";\nimport { addRemoteModuleRegistrationStatusChangedListener, areModulesReady, areModulesRegistered, getRemoteModuleRegistrationStatus, removeRemoteModuleRegistrationStatusChangedListener } from \"@squide/module-federation\";\nimport { addMswStateChangedListener, isMswReady, removeMswStateChangedListener } from \"@squide/msw\";\nimport { useCallback, useEffect, useMemo, useReducer, type Dispatch } from \"react\";\nimport { useExecuteOnce } from \"./useExecuteOnce.ts\";\nimport { isBootstrapping } from \"./useIsBootstrapping.ts\";\n\nexport type ActiveRouteVisiblity = \"unknown\" | \"public\" | \"protected\";\n\nexport interface AppRouterState {\n waitForMsw: boolean;\n waitForPublicData: boolean;\n waitForProtectedData: boolean;\n areModulesRegistered: boolean;\n areModulesReady: boolean;\n isMswReady: boolean;\n isPublicDataReady: boolean;\n isProtectedDataReady: boolean;\n publicDataUpdatedAt?: number;\n protectedDataUpdatedAt?: number;\n deferredRegistrationsUpdatedAt?: number;\n activeRouteVisibility: ActiveRouteVisiblity;\n isUnauthorized: boolean;\n}\n\nexport type AppRouterActionType =\n| \"modules-registered\"\n| \"modules-ready\"\n| \"msw-ready\"\n| \"public-data-ready\"\n| \"protected-data-ready\"\n| \"public-data-updated\"\n| \"protected-data-updated\"\n| \"deferred-registrations-updated\"\n| \"active-route-is-public\"\n| \"active-route-is-protected\"\n| \"is-unauthorized\";\n\n// The followings event const are a concatenation of \"squide-\" with AppRouterActionType.\n// They are dispatched by the useEnhancedReducerDispatch hook.\nexport const ModulesRegisteredEvent = \"squide-modules-registered\";\nexport const ModulesReadyEvent = \"squide-modules-ready\";\nexport const MswReadyEvent = \"squide-msw-ready\";\nexport const PublicDataReadyEvent = \"squide-public-data-ready\";\nexport const ProtectedDataReadyEvent = \"squide-protected-data-ready\";\nexport const PublicDataUpdatedEvent = \"squide-public-data-updated\";\nexport const ProtectedDataUpdatedEvent = \"squide-protected-data-updated\";\nexport const DeferredRegistrationsUpdatedEvent = \"squide-deferred-registrations-updated\";\nexport const ApplicationBoostrappedEvent = \"squide-app-boostrapped\";\n\nexport interface AppRouterAction {\n type: AppRouterActionType;\n}\n\nexport type AppRouterDispatch = Dispatch<AppRouterAction>;\n\nfunction reducer(state: AppRouterState, action: AppRouterAction) {\n let newState = state;\n\n switch (action.type) {\n case \"modules-registered\": {\n newState = {\n ...newState,\n areModulesRegistered: true\n };\n\n break;\n }\n case \"modules-ready\": {\n newState = {\n ...newState,\n areModulesReady: true,\n // Will be set even if the app is not using deferred registrations.\n deferredRegistrationsUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"msw-ready\": {\n newState = {\n ...newState,\n isMswReady: true\n };\n\n break;\n }\n case \"public-data-ready\": {\n newState = {\n ...newState,\n isPublicDataReady: true,\n publicDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"protected-data-ready\": {\n newState = {\n ...newState,\n isProtectedDataReady: true,\n protectedDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"public-data-updated\": {\n newState = {\n ...newState,\n publicDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"protected-data-updated\": {\n newState = {\n ...newState,\n protectedDataUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"deferred-registrations-updated\": {\n newState = {\n ...newState,\n deferredRegistrationsUpdatedAt: Date.now()\n };\n\n break;\n }\n case \"active-route-is-public\": {\n newState = {\n ...newState,\n activeRouteVisibility: \"public\"\n };\n\n break;\n }\n case \"active-route-is-protected\": {\n newState = {\n ...newState,\n activeRouteVisibility: \"protected\"\n };\n\n break;\n }\n case \"is-unauthorized\": {\n newState = {\n ...newState,\n isUnauthorized: true\n };\n\n break;\n }\n default: {\n throw new Error(`[squide] The AppRouter component state reducer doesn't support action type \"${action.type}\".`);\n }\n }\n\n return newState;\n}\n\nexport function getAreModulesRegistered() {\n const localModuleStatus = getLocalModuleRegistrationStatus();\n const remoteModuleStatus = getRemoteModuleRegistrationStatus();\n\n return areModulesRegistered(localModuleStatus, remoteModuleStatus);\n}\n\nexport function getAreModulesReady() {\n const localModuleStatus = getLocalModuleRegistrationStatus();\n const remoteModuleStatus = getRemoteModuleRegistrationStatus();\n\n return areModulesReady(localModuleStatus, remoteModuleStatus);\n}\n\nexport function useModuleRegistrationStatusDispatcher(areModulesRegisteredValue: boolean, areModulesReadyValue: boolean, dispatch: AppRouterDispatch) {\n const logger = useLogger();\n\n const dispatchModulesRegistered = useExecuteOnce(useCallback(() => {\n if (getAreModulesRegistered()) {\n dispatch({ type: \"modules-registered\" });\n\n logger.debug(\"[squide] %cModules are registered%c.\", \"color: white; background-color: green;\", \"\");\n\n return true;\n }\n\n return false;\n }, [dispatch, logger]));\n\n const dispatchModulesReady = useExecuteOnce(useCallback(() => {\n if (getAreModulesReady()) {\n dispatch({ type: \"modules-ready\" });\n\n logger.debug(\"[squide] %cModules are ready%c.\", \"color: white; background-color: green;\", \"\");\n\n return true;\n }\n\n return false;\n }, [dispatch, logger]));\n\n return useEffect(() => {\n if (!areModulesRegisteredValue) {\n addLocalModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n addRemoteModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n }\n\n if (!areModulesReadyValue) {\n addLocalModuleRegistrationStatusChangedListener(dispatchModulesReady);\n addRemoteModuleRegistrationStatusChangedListener(dispatchModulesReady);\n }\n\n return () => {\n removeLocalModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n removeRemoteModuleRegistrationStatusChangedListener(dispatchModulesRegistered);\n\n removeLocalModuleRegistrationStatusChangedListener(dispatchModulesReady);\n removeRemoteModuleRegistrationStatusChangedListener(dispatchModulesReady);\n };\n }, [areModulesRegisteredValue, areModulesReadyValue, dispatchModulesRegistered, dispatchModulesReady]);\n}\n\nexport function useMswStatusDispatcher(isMswReadyValue: boolean, dispatch: AppRouterDispatch) {\n const logger = useLogger();\n\n const dispatchMswReady = useExecuteOnce(useCallback(() => {\n if (isMswReady()) {\n dispatch({ type: \"msw-ready\" });\n\n logger.debug(\"[squide] %cMSW is ready%c.\", \"color: white; background-color: green;\", \"\");\n\n return true;\n }\n\n return false;\n }, [dispatch, logger]));\n\n useEffect(() => {\n if (!isMswReadyValue) {\n addMswStateChangedListener(dispatchMswReady);\n }\n\n return () => {\n removeMswStateChangedListener(dispatchMswReady);\n };\n }, [isMswReadyValue, dispatchMswReady]);\n}\n\nexport function useBootstrappingCompletedDispatcher(state: AppRouterState) {\n const eventBus = useEventBus();\n\n const areModulesRegisteredValue = state.areModulesRegistered;\n const isBoostrapping = isBootstrapping(state);\n\n useExecuteOnce(useCallback(() => {\n if (areModulesRegisteredValue && !isBoostrapping) {\n eventBus.dispatch(ApplicationBoostrappedEvent);\n\n return true;\n }\n\n return false;\n }, [areModulesRegisteredValue, isBoostrapping, eventBus]), true);\n}\n\nlet dispatchProxyFactory: ((reactDispatch: AppRouterDispatch) => AppRouterDispatch) | undefined;\n\n// This function should only be used by tests.\nexport function __setAppReducerDispatchProxyFactory(factory: (reactDispatch: AppRouterDispatch) => AppRouterDispatch) {\n dispatchProxyFactory = factory;\n}\n\n// This function should only be used by tests.\nexport function __clearAppReducerDispatchProxy() {\n dispatchProxyFactory = undefined;\n}\n\nfunction useReducerDispatchProxy(reactDispatch: AppRouterDispatch) {\n return useMemo(() => {\n return dispatchProxyFactory ? dispatchProxyFactory(reactDispatch) : reactDispatch;\n }, [reactDispatch]);\n}\n\nfunction useEnhancedReducerDispatch(reducerDispatch: AppRouterDispatch) {\n const logger = useLogger();\n const eventBus = useEventBus();\n\n return useCallback((action: AppRouterAction) => {\n logger.debug(\"[squide] The following action has been dispatched to the AppRouter reducer:\", action);\n eventBus.dispatch(`squide-${action.type}`);\n\n reducerDispatch(action);\n }, [reducerDispatch, logger, eventBus]);\n}\n\nexport function useAppRouterReducer(waitForMsw: boolean, waitForPublicData: boolean, waitForProtectedData: boolean): [AppRouterState, AppRouterDispatch] {\n const areModulesInitiallyRegistered = getAreModulesRegistered();\n const areModulesInitiallyReady = getAreModulesReady();\n const isMswInitiallyReady = isMswReady();\n\n const eventBus = useEventBus();\n\n // When modules are initially registered, the reducer action will never be dispatched, therefore the event would not be dispatched as well.\n // To ensure the bootstrapping events sequencing, the event is manually dispatched when the modules are initially registered.\n useExecuteOnce(useCallback(() => {\n if (areModulesInitiallyRegistered) {\n eventBus.dispatch(ModulesRegisteredEvent);\n }\n\n return true;\n }, [areModulesInitiallyRegistered, eventBus]), true);\n\n // When modules are initially registered, the reducer action will never be dispatched, therefore the event would not be dispatched as well.\n // To ensure the bootstrapping events sequencing, the event is manually dispatched when the modules are initially registered.\n useExecuteOnce(useCallback(() => {\n if (areModulesInitiallyReady) {\n eventBus.dispatch(ModulesReadyEvent);\n }\n\n return true;\n }, [areModulesInitiallyReady, eventBus]), true);\n\n // When modules are initially registered, the reducer action will never be dispatched, therefore the event would not be dispatched as well.\n // To ensure the bootstrapping events sequencing, the event is manually dispatched when the modules are initially registered.\n useExecuteOnce(useCallback(() => {\n if (isMswInitiallyReady) {\n eventBus.dispatch(MswReadyEvent);\n }\n\n return true;\n }, [isMswInitiallyReady, eventBus]), true);\n\n const [state, reactDispatch] = useReducer(reducer, {\n waitForMsw,\n waitForPublicData,\n waitForProtectedData,\n // When the modules registration functions are awaited, the event listeners are registered after the modules are registered.\n areModulesRegistered: areModulesInitiallyRegistered,\n areModulesReady: areModulesInitiallyReady,\n isMswReady: isMswInitiallyReady,\n isPublicDataReady: false,\n isProtectedDataReady: false,\n activeRouteVisibility: \"unknown\",\n isUnauthorized: false\n });\n\n const {\n areModulesRegistered: areModulesRegisteredValue,\n areModulesReady: areModulesReadyValue,\n isMswReady: isMswReadyValue\n } = state;\n\n // The dispatch proxy is strictly an utility allowing tests to mock the useReducer dispatch function. It's easier\n // than mocking the import from React.\n const dispatchProxy = useReducerDispatchProxy(reactDispatch);\n const dispatch = useEnhancedReducerDispatch(dispatchProxy);\n\n useModuleRegistrationStatusDispatcher(areModulesRegisteredValue, areModulesReadyValue, dispatch);\n useMswStatusDispatcher(isMswReadyValue, dispatch);\n useBootstrappingCompletedDispatcher(state);\n\n return [state, dispatch];\n}\n"],"names":["addLocalModuleRegistrationStatusChangedListener","getLocalModuleRegistrationStatus","removeLocalModuleRegistrationStatusChangedListener","useEventBus","useLogger","addRemoteModuleRegistrationStatusChangedListener","areModulesReady","areModulesRegistered","getRemoteModuleRegistrationStatus","removeRemoteModuleRegistrationStatusChangedListener","addMswStateChangedListener","isMswReady","removeMswStateChangedListener","useCallback","useEffect","useMemo","useReducer","useExecuteOnce","isBootstrapping","ModulesRegisteredEvent","ModulesReadyEvent","MswReadyEvent","PublicDataReadyEvent","ProtectedDataReadyEvent","PublicDataUpdatedEvent","ProtectedDataUpdatedEvent","DeferredRegistrationsUpdatedEvent","ApplicationBoostrappedEvent","reducer","state","action","newState","Date","Error","getAreModulesRegistered","localModuleStatus","remoteModuleStatus","getAreModulesReady","useModuleRegistrationStatusDispatcher","areModulesRegisteredValue","areModulesReadyValue","dispatch","logger","dispatchModulesRegistered","dispatchModulesReady","useMswStatusDispatcher","isMswReadyValue","dispatchMswReady","useBootstrappingCompletedDispatcher","eventBus","isBoostrapping","dispatchProxyFactory","__setAppReducerDispatchProxyFactory","factory","__clearAppReducerDispatchProxy","undefined","useReducerDispatchProxy","reactDispatch","useEnhancedReducerDispatch","reducerDispatch","useAppRouterReducer","waitForMsw","waitForPublicData","waitForProtectedData","areModulesInitiallyRegistered","areModulesInitiallyReady","isMswInitiallyReady","dispatchProxy"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type Runtime } from "@squide/core";
2
+ import type { PropsWithChildren } from "react";
3
+ export interface FireflyProviderProps extends PropsWithChildren {
4
+ runtime: Runtime;
5
+ }
6
+ export declare function FireflyProvider(props: FireflyProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,21 @@
1
+ import * as __WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__ from "react/jsx-runtime";
2
+ import * as __WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__ from "@squide/core";
3
+
4
+ ;// CONCATENATED MODULE: external "react/jsx-runtime"
5
+
6
+ ;// CONCATENATED MODULE: external "@squide/core"
7
+
8
+ ;// CONCATENATED MODULE: ./src/FireflyProvider.tsx?__rslib_entry__
9
+
10
+
11
+ function FireflyProvider(props) {
12
+ const { runtime, children } = props;
13
+ return /*#__PURE__*/ (0,__WEBPACK_EXTERNAL_MODULE_react_jsx_runtime_225474f2__.jsx)(__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.RuntimeContext.Provider, {
14
+ value: runtime,
15
+ children: children
16
+ });
17
+ }
18
+
19
+ export { FireflyProvider };
20
+
21
+ //# sourceMappingURL=FireflyProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FireflyProvider.js","sources":["webpack://@squide/firefly/./src/FireflyProvider.tsx"],"sourcesContent":["import { type Runtime, RuntimeContext } from \"@squide/core\";\nimport type { PropsWithChildren } from \"react\";\n\nexport interface FireflyProviderProps extends PropsWithChildren {\n runtime: Runtime;\n}\n\nexport function FireflyProvider(props: FireflyProviderProps) {\n const {\n runtime,\n children\n } = props;\n\n return (\n <RuntimeContext.Provider value={runtime}>\n {children}\n </RuntimeContext.Provider>\n );\n}\n"],"names":["RuntimeContext","FireflyProvider","props","runtime","children"],"mappings":";;;;;;;;;AAA4D;AAOrD,SAASC,gBAAgBC,KAA2B;IACvD,MAAM,EACFC,OAAO,EACPC,QAAQ,EACX,GAAGF;IAEJ,qBACI,+DAACF,yEAAuB;QAAC,OAAOG;kBAC3BC;;AAGb"}
@@ -1,15 +1,14 @@
1
- import { type ModuleRegisterFunction, type ModuleRegistrationError, type RegisterModulesOptions } from "@squide/core";
2
- import { type RemoteDefinition, type RemoteModuleRegistrationError } from "@squide/module-federation";
1
+ import { type ModuleRegisterFunction, type RegisterModulesOptions } from "@squide/core";
2
+ import { type RemoteDefinition } from "@squide/module-federation";
3
3
  import type { FireflyRuntime } from "./FireflyRuntime.tsx";
4
4
  export declare const ApplicationBootstrappingStartedEvent = "squide-app-bootstrapping-started";
5
5
  export type StartMswFunction<TRuntime = FireflyRuntime> = (runtime: TRuntime) => Promise<void>;
6
+ export type OnBootstrapErrorFunction = (error: unknown) => void;
6
7
  export interface BootstrapAppOptions<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown> extends RegisterModulesOptions<TContext> {
7
8
  localModules?: ModuleRegisterFunction<TRuntime, TContext, TData>[];
8
9
  remotes?: RemoteDefinition[];
9
10
  startMsw?: StartMswFunction<TRuntime>;
11
+ onError?: OnBootstrapErrorFunction;
10
12
  }
11
- export declare function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options?: BootstrapAppOptions<TRuntime, TContext, TData>): Promise<{
12
- localModuleErrors: ModuleRegistrationError[];
13
- remoteModuleErrors: RemoteModuleRegistrationError[];
14
- }>;
13
+ export declare function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options?: BootstrapAppOptions<TRuntime, TContext, TData>): void;
15
14
  export declare function __resetHasExecuteGuard(): void;
package/dist/boostrap.js CHANGED
@@ -13,37 +13,46 @@ import * as __WEBPACK_EXTERNAL_MODULE__squide_msw_9f7e76df__ from "@squide/msw";
13
13
 
14
14
 
15
15
  const ApplicationBootstrappingStartedEvent = "squide-app-bootstrapping-started";
16
+ function propagateRegistrationErrors(results, onError) {
17
+ if (results) {
18
+ if (results.status === "fulfilled") {
19
+ results.value.forEach((x)=>{
20
+ onError(x);
21
+ });
22
+ }
23
+ }
24
+ }
16
25
  let hasExecuted = false;
17
- async function bootstrap(runtime, options = {}) {
18
- const { localModules = [], remotes = [], context, startMsw } = options;
26
+ function bootstrap(runtime, options = {}) {
27
+ const { localModules = [], remotes = [], context, startMsw, onError } = options;
19
28
  if (hasExecuted) {
20
29
  throw new Error("[squide] A squide application can only be bootstrapped once. Did you call the \"bootstrap\" function twice?");
21
30
  }
22
31
  hasExecuted = true;
23
32
  runtime.eventBus.dispatch(ApplicationBootstrappingStartedEvent);
24
- let localModuleErrors = [];
25
- let remoteModuleErrors = [];
26
- localModuleErrors = await (0,__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.registerLocalModules)(localModules, runtime, {
27
- context
28
- });
29
- remoteModuleErrors = await (0,__WEBPACK_EXTERNAL_MODULE__squide_module_federation_054d2ec6__.registerRemoteModules)(remotes, runtime, {
30
- context
31
- });
32
- if (runtime.isMswEnabled) {
33
- if (!(0,__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.isFunction)(startMsw)) {
34
- throw new Error("[squide] When MSW is enabled, the \"startMsw\" function must be provided.");
33
+ Promise.allSettled([
34
+ (0,__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.registerLocalModules)(localModules, runtime, {
35
+ context
36
+ }),
37
+ (0,__WEBPACK_EXTERNAL_MODULE__squide_module_federation_054d2ec6__.registerRemoteModules)(remotes, runtime, {
38
+ context
39
+ })
40
+ ]).then((results)=>{
41
+ if (runtime.isMswEnabled) {
42
+ if (!(0,__WEBPACK_EXTERNAL_MODULE__squide_core_7a405b8f__.isFunction)(startMsw)) {
43
+ throw new Error("[squide] When MSW is enabled, the \"startMsw\" function must be provided.");
44
+ }
45
+ startMsw(runtime).then(()=>{
46
+ (0,__WEBPACK_EXTERNAL_MODULE__squide_msw_9f7e76df__.setMswAsReady)();
47
+ }).catch((error)=>{
48
+ runtime.logger.debug("[squide] An error occured while starting MSW.", error);
49
+ });
35
50
  }
36
- try {
37
- await startMsw(runtime);
38
- (0,__WEBPACK_EXTERNAL_MODULE__squide_msw_9f7e76df__.setMswAsReady)();
39
- } catch (error) {
40
- runtime.logger.debug("[squide] An error occured while starting MSW.", error);
51
+ if (onError) {
52
+ propagateRegistrationErrors(results[0], onError);
53
+ propagateRegistrationErrors(results[1], onError);
41
54
  }
42
- }
43
- return {
44
- localModuleErrors,
45
- remoteModuleErrors
46
- };
55
+ });
47
56
  }
48
57
  function __resetHasExecuteGuard() {
49
58
  hasExecuted = false;
@@ -1 +1 @@
1
- {"version":3,"file":"boostrap.js","sources":["webpack://@squide/firefly/./src/boostrap.ts"],"sourcesContent":["import { isFunction, registerLocalModules, type ModuleRegisterFunction, type ModuleRegistrationError, type RegisterModulesOptions } from \"@squide/core\";\nimport { registerRemoteModules, type RemoteDefinition, type RemoteModuleRegistrationError } from \"@squide/module-federation\";\nimport { setMswAsReady } from \"@squide/msw\";\nimport type { FireflyRuntime } from \"./FireflyRuntime.tsx\";\n\nexport const ApplicationBootstrappingStartedEvent = \"squide-app-bootstrapping-started\";\n\nexport type StartMswFunction<TRuntime = FireflyRuntime> = (runtime: TRuntime) => Promise<void>;\n\nexport interface BootstrapAppOptions<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown> extends RegisterModulesOptions<TContext> {\n localModules?: ModuleRegisterFunction<TRuntime, TContext, TData>[];\n remotes?: RemoteDefinition[];\n startMsw?: StartMswFunction<TRuntime>;\n}\n\nlet hasExecuted = false;\n\nexport async function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options: BootstrapAppOptions<TRuntime, TContext, TData> = {}) {\n const {\n localModules = [],\n remotes = [],\n context,\n startMsw\n } = options;\n\n if (hasExecuted) {\n throw new Error(\"[squide] A squide application can only be bootstrapped once. Did you call the \\\"bootstrap\\\" function twice?\");\n }\n\n hasExecuted = true;\n\n runtime.eventBus.dispatch(ApplicationBootstrappingStartedEvent);\n\n let localModuleErrors: ModuleRegistrationError[] = [];\n let remoteModuleErrors: RemoteModuleRegistrationError[] = [];\n\n localModuleErrors = await registerLocalModules<TRuntime, TContext, TData>(localModules, runtime, { context });\n remoteModuleErrors = await registerRemoteModules(remotes, runtime, { context });\n\n if (runtime.isMswEnabled) {\n if (!isFunction(startMsw)) {\n throw new Error(\"[squide] When MSW is enabled, the \\\"startMsw\\\" function must be provided.\");\n }\n\n try {\n await startMsw(runtime);\n\n setMswAsReady();\n } catch (error: unknown) {\n runtime.logger.debug(\"[squide] An error occured while starting MSW.\", error);\n }\n }\n\n return {\n localModuleErrors,\n remoteModuleErrors\n };\n}\n\nexport function __resetHasExecuteGuard() {\n hasExecuted = false;\n}\n"],"names":["isFunction","registerLocalModules","registerRemoteModules","setMswAsReady","ApplicationBootstrappingStartedEvent","hasExecuted","bootstrap","runtime","options","localModules","remotes","context","startMsw","Error","localModuleErrors","remoteModuleErrors","error","__resetHasExecuteGuard"],"mappings":";;;;;;;;;;;AAAwJ;AAC3B;AACjF;AAGrC,MAAMI,uCAAuC,mCAAmC;AAUvF,IAAIC,cAAc;AAEX,eAAeC,UAAiGC,OAAiB,EAAEC,UAA0D,CAAC,CAAC;IAClM,MAAM,EACFC,eAAe,EAAE,EACjBC,UAAU,EAAE,EACZC,OAAO,EACPC,QAAQ,EACX,GAAGJ;IAEJ,IAAIH,aAAa;QACb,MAAM,IAAIQ,MAAM;IACpB;IAEAR,cAAc;IAEdE,QAAQ,QAAQ,CAAC,QAAQ,CAACH;IAE1B,IAAIU,oBAA+C,EAAE;IACrD,IAAIC,qBAAsD,EAAE;IAE5DD,oBAAoB,MAAMb,0EAAoBA,CAA4BQ,cAAcF,SAAS;QAAEI;IAAQ;IAC3GI,qBAAqB,MAAMb,wFAAqBA,CAACQ,SAASH,SAAS;QAAEI;IAAQ;IAE7E,IAAIJ,QAAQ,YAAY,EAAE;QACtB,IAAI,CAACP,gEAAUA,CAACY,WAAW;YACvB,MAAM,IAAIC,MAAM;QACpB;QAEA,IAAI;YACA,MAAMD,SAASL;YAEfJ,kEAAaA;QACjB,EAAE,OAAOa,OAAgB;YACrBT,QAAQ,MAAM,CAAC,KAAK,CAAC,iDAAiDS;QAC1E;IACJ;IAEA,OAAO;QACHF;QACAC;IACJ;AACJ;AAEO,SAASE;IACZZ,cAAc;AAClB"}
1
+ {"version":3,"file":"boostrap.js","sources":["webpack://@squide/firefly/./src/boostrap.ts"],"sourcesContent":["import { isFunction, registerLocalModules, type ModuleRegisterFunction, type RegisterModulesOptions } from \"@squide/core\";\nimport { registerRemoteModules, type RemoteDefinition } from \"@squide/module-federation\";\nimport { setMswAsReady } from \"@squide/msw\";\nimport type { FireflyRuntime } from \"./FireflyRuntime.tsx\";\n\nexport const ApplicationBootstrappingStartedEvent = \"squide-app-bootstrapping-started\";\n\nexport type StartMswFunction<TRuntime = FireflyRuntime> = (runtime: TRuntime) => Promise<void>;\n\nexport type OnBootstrapErrorFunction = (error: unknown) => void;\n\nexport interface BootstrapAppOptions<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown> extends RegisterModulesOptions<TContext> {\n localModules?: ModuleRegisterFunction<TRuntime, TContext, TData>[];\n remotes?: RemoteDefinition[];\n startMsw?: StartMswFunction<TRuntime>;\n onError?: OnBootstrapErrorFunction;\n}\n\nfunction propagateRegistrationErrors(results: PromiseSettledResult<unknown[]>, onError: OnBootstrapErrorFunction) {\n if (results) {\n if (results.status === \"fulfilled\") {\n results.value.forEach(x => {\n onError(x);\n });\n }\n }\n}\n\nlet hasExecuted = false;\n\nexport function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options: BootstrapAppOptions<TRuntime, TContext, TData> = {}) {\n const {\n localModules = [],\n remotes = [],\n context,\n startMsw,\n onError\n } = options;\n\n if (hasExecuted) {\n throw new Error(\"[squide] A squide application can only be bootstrapped once. Did you call the \\\"bootstrap\\\" function twice?\");\n }\n\n hasExecuted = true;\n\n runtime.eventBus.dispatch(ApplicationBootstrappingStartedEvent);\n\n Promise.allSettled([\n registerLocalModules<TRuntime, TContext, TData>(localModules, runtime, { context }),\n registerRemoteModules(remotes, runtime, { context })\n ]).then(results => {\n if (runtime.isMswEnabled) {\n if (!isFunction(startMsw)) {\n throw new Error(\"[squide] When MSW is enabled, the \\\"startMsw\\\" function must be provided.\");\n }\n\n startMsw(runtime)\n .then(() => {\n setMswAsReady();\n })\n .catch((error: unknown) => {\n runtime.logger.debug(\"[squide] An error occured while starting MSW.\", error);\n });\n }\n\n if (onError) {\n propagateRegistrationErrors(results[0], onError);\n propagateRegistrationErrors(results[1], onError);\n }\n });\n}\n\nexport function __resetHasExecuteGuard() {\n hasExecuted = false;\n}\n"],"names":["isFunction","registerLocalModules","registerRemoteModules","setMswAsReady","ApplicationBootstrappingStartedEvent","propagateRegistrationErrors","results","onError","x","hasExecuted","bootstrap","runtime","options","localModules","remotes","context","startMsw","Error","Promise","error","__resetHasExecuteGuard"],"mappings":";;;;;;;;;;;AAA0H;AACjC;AAC7C;AAGrC,MAAMI,uCAAuC,mCAAmC;AAavF,SAASC,4BAA4BC,OAAwC,EAAEC,OAAiC;IAC5G,IAAID,SAAS;QACT,IAAIA,QAAQ,MAAM,KAAK,aAAa;YAChCA,QAAQ,KAAK,CAAC,OAAO,CAACE,CAAAA;gBAClBD,QAAQC;YACZ;QACJ;IACJ;AACJ;AAEA,IAAIC,cAAc;AAEX,SAASC,UAAiGC,OAAiB,EAAEC,UAA0D,CAAC,CAAC;IAC5L,MAAM,EACFC,eAAe,EAAE,EACjBC,UAAU,EAAE,EACZC,OAAO,EACPC,QAAQ,EACRT,OAAO,EACV,GAAGK;IAEJ,IAAIH,aAAa;QACb,MAAM,IAAIQ,MAAM;IACpB;IAEAR,cAAc;IAEdE,QAAQ,QAAQ,CAAC,QAAQ,CAACP;IAE1Bc,QAAQ,UAAU,CAAC;QACfjB,0EAAoBA,CAA4BY,cAAcF,SAAS;YAAEI;QAAQ;QACjFb,wFAAqBA,CAACY,SAASH,SAAS;YAAEI;QAAQ;KACrD,EAAE,IAAI,CAACT,CAAAA;QACJ,IAAIK,QAAQ,YAAY,EAAE;YACtB,IAAI,CAACX,gEAAUA,CAACgB,WAAW;gBACvB,MAAM,IAAIC,MAAM;YACpB;YAEAD,SAASL,SACJ,IAAI,CAAC;gBACFR,kEAAaA;YACjB,GACC,KAAK,CAAC,CAACgB;gBACJR,QAAQ,MAAM,CAAC,KAAK,CAAC,iDAAiDQ;YAC1E;QACR;QAEA,IAAIZ,SAAS;YACTF,4BAA4BC,OAAO,CAAC,EAAE,EAAEC;YACxCF,4BAA4BC,OAAO,CAAC,EAAE,EAAEC;QAC5C;IACJ;AACJ;AAEO,SAASa;IACZX,cAAc;AAClB"}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export * from "@squide/core";
2
2
  export * from "@squide/module-federation";
3
3
  export * from "@squide/msw";
4
4
  export * from "@squide/react-router";
5
+ export * from "./FireflyProvider.tsx";
5
6
  export * from "./FireflyRuntime.tsx";
6
7
  export * from "./AppRouter.tsx";
7
8
  export * from "./AppRouterContext.ts";
@@ -15,7 +16,9 @@ export * from "./useDeferredRegistrations.ts";
15
16
  export * from "./useIsActiveRouteProtected.ts";
16
17
  export * from "./useIsBootstrapping.ts";
17
18
  export * from "./useNavigationItems.ts";
19
+ export * from "./useProtectedDataHandler.ts";
18
20
  export * from "./useProtectedDataQueries.ts";
21
+ export * from "./usePublicDataHandler.ts";
19
22
  export * from "./usePublicDataQueries.ts";
20
23
  export * from "./useRegisterDeferredRegistrations.ts";
21
24
  export * from "./useStrictRegistrationMode.ts";
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ export * from "@squide/core";
2
2
  export * from "@squide/module-federation";
3
3
  export * from "@squide/msw";
4
4
  export * from "@squide/react-router";
5
+ export * from "./FireflyProvider.js";
5
6
  export * from "./FireflyRuntime.js";
6
7
  export * from "./AppRouter.js";
7
8
  export * from "./AppRouterContext.js";
@@ -15,7 +16,9 @@ export * from "./useDeferredRegistrations.js";
15
16
  export * from "./useIsActiveRouteProtected.js";
16
17
  export * from "./useIsBootstrapping.js";
17
18
  export * from "./useNavigationItems.js";
19
+ export * from "./useProtectedDataHandler.js";
18
20
  export * from "./useProtectedDataQueries.js";
21
+ export * from "./usePublicDataHandler.js";
19
22
  export * from "./usePublicDataQueries.js";
20
23
  export * from "./useRegisterDeferredRegistrations.js";
21
24
  export * from "./useStrictRegistrationMode.js";
@@ -44,6 +47,9 @@ export * from "./boostrap.js";
44
47
 
45
48
 
46
49
 
50
+
51
+
52
+
47
53
 
48
54
 
49
55
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["webpack://@squide/firefly/./src/index.ts"],"sourcesContent":["export * from \"@squide/core\";\nexport * from \"@squide/module-federation\";\nexport * from \"@squide/msw\";\nexport * from \"@squide/react-router\";\n\nexport * from \"./FireflyRuntime.tsx\";\n\nexport * from \"./AppRouter.tsx\";\nexport * from \"./AppRouterContext.ts\";\nexport * from \"./AppRouterReducer.ts\";\n\nexport * from \"./GlobalDataQueriesError.ts\";\nexport * from \"./useCanFetchProtectedData.ts\";\nexport * from \"./useCanFetchPublicData.ts\";\nexport * from \"./useCanRegisterDeferredRegistrations.ts\";\nexport * from \"./useCanUpdateDeferredRegistrations.ts\";\nexport * from \"./useDeferredRegistrations.ts\";\nexport * from \"./useIsActiveRouteProtected.ts\";\nexport * from \"./useIsBootstrapping.ts\";\nexport * from \"./useNavigationItems.ts\";\nexport * from \"./useProtectedDataQueries.ts\";\nexport * from \"./usePublicDataQueries.ts\";\nexport * from \"./useRegisterDeferredRegistrations.ts\";\nexport * from \"./useStrictRegistrationMode.ts\";\nexport * from \"./useUpdateDeferredRegistrations.ts\";\n\nexport * from \"./boostrap.ts\";\n\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAA6B;AACa;AACd;AACS;AAEA;AAEL;AACM;AACA;AAEM;AACE;AACH;AACc;AACF;AACT;AACC;AACP;AACA;AACK;AACH;AACY;AACP;AACK;AAEtB"}
1
+ {"version":3,"file":"index.js","sources":["webpack://@squide/firefly/./src/index.ts"],"sourcesContent":["export * from \"@squide/core\";\nexport * from \"@squide/module-federation\";\nexport * from \"@squide/msw\";\nexport * from \"@squide/react-router\";\n\nexport * from \"./FireflyProvider.tsx\";\nexport * from \"./FireflyRuntime.tsx\";\n\nexport * from \"./AppRouter.tsx\";\nexport * from \"./AppRouterContext.ts\";\nexport * from \"./AppRouterReducer.ts\";\n\nexport * from \"./GlobalDataQueriesError.ts\";\nexport * from \"./useCanFetchProtectedData.ts\";\nexport * from \"./useCanFetchPublicData.ts\";\nexport * from \"./useCanRegisterDeferredRegistrations.ts\";\nexport * from \"./useCanUpdateDeferredRegistrations.ts\";\nexport * from \"./useDeferredRegistrations.ts\";\nexport * from \"./useIsActiveRouteProtected.ts\";\nexport * from \"./useIsBootstrapping.ts\";\nexport * from \"./useNavigationItems.ts\";\nexport * from \"./useProtectedDataHandler.ts\";\nexport * from \"./useProtectedDataQueries.ts\";\nexport * from \"./usePublicDataHandler.ts\";\nexport * from \"./usePublicDataQueries.ts\";\nexport * from \"./useRegisterDeferredRegistrations.ts\";\nexport * from \"./useStrictRegistrationMode.ts\";\nexport * from \"./useUpdateDeferredRegistrations.ts\";\n\nexport * from \"./boostrap.ts\";\n\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAA6B;AACa;AACd;AACS;AAEC;AACD;AAEL;AACM;AACA;AAEM;AACE;AACH;AACc;AACF;AACT;AACC;AACP;AACA;AACK;AACA;AACH;AACA;AACY;AACP;AACK;AAEtB"}
@@ -1,3 +1,3 @@
1
1
  import type { AppRouterState } from "./AppRouterReducer.ts";
2
2
  export declare function useIsBootstrapping(): boolean;
3
- export declare function isApplicationBootstrapping(state: AppRouterState): boolean;
3
+ export declare function isBootstrapping(state: AppRouterState): boolean;
@@ -6,9 +6,9 @@ import * as __WEBPACK_EXTERNAL_MODULE__AppRouterContext_js_3c4a3c33__ from "./Ap
6
6
 
7
7
  function useIsBootstrapping() {
8
8
  const state = (0,__WEBPACK_EXTERNAL_MODULE__AppRouterContext_js_3c4a3c33__.useAppRouterState)();
9
- return isApplicationBootstrapping(state);
9
+ return isBootstrapping(state);
10
10
  }
11
- function isApplicationBootstrapping(state) {
11
+ function isBootstrapping(state) {
12
12
  const { waitForMsw, waitForPublicData, waitForProtectedData, areModulesReady, isMswReady, isPublicDataReady, isProtectedDataReady, activeRouteVisibility, isUnauthorized } = state;
13
13
  const isAppReady = !isUnauthorized && areModulesReady && (!waitForMsw || isMswReady) && (!waitForPublicData || isPublicDataReady) && (!waitForProtectedData || activeRouteVisibility === "public" || isProtectedDataReady);
14
14
  // When an API request returns a 401, the bootstrapping should be bypassed to render the login page.
@@ -17,6 +17,6 @@ function isApplicationBootstrapping(state) {
17
17
  return !isAppReady && !flush;
18
18
  }
19
19
 
20
- export { isApplicationBootstrapping, useIsBootstrapping };
20
+ export { isBootstrapping, useIsBootstrapping };
21
21
 
22
22
  //# sourceMappingURL=useIsBootstrapping.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useIsBootstrapping.js","sources":["webpack://@squide/firefly/./src/useIsBootstrapping.ts"],"sourcesContent":["import { useAppRouterState } from \"./AppRouterContext.ts\";\nimport type { AppRouterState } from \"./AppRouterReducer.ts\";\n\nexport function useIsBootstrapping() {\n const state = useAppRouterState();\n\n return isApplicationBootstrapping(state);\n}\n\nexport function isApplicationBootstrapping(state: AppRouterState) {\n const {\n waitForMsw,\n waitForPublicData,\n waitForProtectedData,\n areModulesReady,\n isMswReady,\n isPublicDataReady,\n isProtectedDataReady,\n activeRouteVisibility,\n isUnauthorized\n } = state;\n\n const isAppReady = (\n !isUnauthorized\n // Wait until the modules has been registered and the deferred registrations has been registered if any.\n && areModulesReady\n // Not required but can sometimes prevent a re-render when the state value is somehow updated after the initial data is ready.\n && (!waitForMsw || isMswReady)\n // Wait for the initial data to be ready.\n && (!waitForPublicData || isPublicDataReady)\n && (!waitForProtectedData || activeRouteVisibility === \"public\" || isProtectedDataReady)\n );\n\n // When an API request returns a 401, the bootstrapping should be bypassed to render the login page.\n const flush = (\n // Only applicable when there's a unauthorized request while fetching the initial data.\n isUnauthorized\n // Not required but can sometimes prevent a re-render when the state value is somehow updated after the public data is ready.\n && (!waitForMsw || isMswReady)\n // If the application is loading public data, we want to wait for this data to be ready to prevent a re-render.\n && (!waitForPublicData || isPublicDataReady)\n );\n\n return !isAppReady && !flush;\n}\n"],"names":["useAppRouterState","useIsBootstrapping","state","isApplicationBootstrapping","waitForMsw","waitForPublicData","waitForProtectedData","areModulesReady","isMswReady","isPublicDataReady","isProtectedDataReady","activeRouteVisibility","isUnauthorized","isAppReady","flush"],"mappings":";;;;;AAA0D;AAGnD,SAASC;IACZ,MAAMC,QAAQF,+EAAiBA;IAE/B,OAAOG,2BAA2BD;AACtC;AAEO,SAASC,2BAA2BD,KAAqB;IAC5D,MAAM,EACFE,UAAU,EACVC,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,UAAU,EACVC,iBAAiB,EACjBC,oBAAoB,EACpBC,qBAAqB,EACrBC,cAAc,EACjB,GAAGV;IAEJ,MAAMW,aACF,CAACD,kBAEEL,mBAEC,EAACH,cAAcI,UAAS,KAExB,EAACH,qBAAqBI,iBAAgB,KACtC,EAACH,wBAAwBK,0BAA0B,YAAYD,oBAAmB;IAG1F,oGAAoG;IACpG,MAAMI,QACF,uFAAuF;IACvFF,kBAEI,EAACR,cAAcI,UAAS,KAExB,EAACH,qBAAqBI,iBAAgB;IAG9C,OAAO,CAACI,cAAc,CAACC;AAC3B"}
1
+ {"version":3,"file":"useIsBootstrapping.js","sources":["webpack://@squide/firefly/./src/useIsBootstrapping.ts"],"sourcesContent":["import { useAppRouterState } from \"./AppRouterContext.ts\";\nimport type { AppRouterState } from \"./AppRouterReducer.ts\";\n\nexport function useIsBootstrapping() {\n const state = useAppRouterState();\n\n return isBootstrapping(state);\n}\n\nexport function isBootstrapping(state: AppRouterState) {\n const {\n waitForMsw,\n waitForPublicData,\n waitForProtectedData,\n areModulesReady,\n isMswReady,\n isPublicDataReady,\n isProtectedDataReady,\n activeRouteVisibility,\n isUnauthorized\n } = state;\n\n const isAppReady = (\n !isUnauthorized\n // Wait until the modules has been registered and the deferred registrations has been registered if any.\n && areModulesReady\n // Not required but can sometimes prevent a re-render when the state value is somehow updated after the initial data is ready.\n && (!waitForMsw || isMswReady)\n // Wait for the initial data to be ready.\n && (!waitForPublicData || isPublicDataReady)\n && (!waitForProtectedData || activeRouteVisibility === \"public\" || isProtectedDataReady)\n );\n\n // When an API request returns a 401, the bootstrapping should be bypassed to render the login page.\n const flush = (\n // Only applicable when there's a unauthorized request while fetching the initial data.\n isUnauthorized\n // Not required but can sometimes prevent a re-render when the state value is somehow updated after the public data is ready.\n && (!waitForMsw || isMswReady)\n // If the application is loading public data, we want to wait for this data to be ready to prevent a re-render.\n && (!waitForPublicData || isPublicDataReady)\n );\n\n return !isAppReady && !flush;\n}\n"],"names":["useAppRouterState","useIsBootstrapping","state","isBootstrapping","waitForMsw","waitForPublicData","waitForProtectedData","areModulesReady","isMswReady","isPublicDataReady","isProtectedDataReady","activeRouteVisibility","isUnauthorized","isAppReady","flush"],"mappings":";;;;;AAA0D;AAGnD,SAASC;IACZ,MAAMC,QAAQF,+EAAiBA;IAE/B,OAAOG,gBAAgBD;AAC3B;AAEO,SAASC,gBAAgBD,KAAqB;IACjD,MAAM,EACFE,UAAU,EACVC,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,UAAU,EACVC,iBAAiB,EACjBC,oBAAoB,EACpBC,qBAAqB,EACrBC,cAAc,EACjB,GAAGV;IAEJ,MAAMW,aACF,CAACD,kBAEEL,mBAEC,EAACH,cAAcI,UAAS,KAExB,EAACH,qBAAqBI,iBAAgB,KACtC,EAACH,wBAAwBK,0BAA0B,YAAYD,oBAAmB;IAG1F,oGAAoG;IACpG,MAAMI,QACF,uFAAuF;IACvFF,kBAEI,EAACR,cAAcI,UAAS,KAExB,EAACH,qBAAqBI,iBAAgB;IAG9C,OAAO,CAACI,cAAc,CAACC;AAC3B"}
@@ -0,0 +1 @@
1
+ export declare function useProtectedDataHandler(handler: () => void): void;
@@ -0,0 +1,25 @@
1
+ import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
2
+ import * as __WEBPACK_EXTERNAL_MODULE__useCanFetchProtectedData_js_52158d16__ from "./useCanFetchProtectedData.js";
3
+
4
+ ;// CONCATENATED MODULE: external "react"
5
+
6
+ ;// CONCATENATED MODULE: external "./useCanFetchProtectedData.js"
7
+
8
+ ;// CONCATENATED MODULE: ./src/useProtectedDataHandler.ts?__rslib_entry__
9
+
10
+
11
+ function useProtectedDataHandler(handler) {
12
+ const canFetchProtectedData = (0,__WEBPACK_EXTERNAL_MODULE__useCanFetchProtectedData_js_52158d16__.useCanFetchProtectedData)();
13
+ (0,__WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
14
+ if (canFetchProtectedData) {
15
+ handler();
16
+ }
17
+ }, [
18
+ canFetchProtectedData,
19
+ handler
20
+ ]);
21
+ }
22
+
23
+ export { useProtectedDataHandler };
24
+
25
+ //# sourceMappingURL=useProtectedDataHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useProtectedDataHandler.js","sources":["webpack://@squide/firefly/./src/useProtectedDataHandler.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useCanFetchProtectedData } from \"./useCanFetchProtectedData.ts\";\n\nexport function useProtectedDataHandler(handler: () => void) {\n const canFetchProtectedData = useCanFetchProtectedData();\n\n useEffect(() => {\n if (canFetchProtectedData) {\n handler();\n }\n }, [canFetchProtectedData, handler]);\n}\n"],"names":["useEffect","useCanFetchProtectedData","useProtectedDataHandler","handler","canFetchProtectedData"],"mappings":";;;;;;;;AAAkC;AACuC;AAElE,SAASE,wBAAwBC,OAAmB;IACvD,MAAMC,wBAAwBH,8FAAwBA;IAEtDD,+CAASA,CAAC;QACN,IAAII,uBAAuB;YACvBD;QACJ;IACJ,GAAG;QAACC;QAAuBD;KAAQ;AACvC"}
@@ -0,0 +1 @@
1
+ export declare function usePublicDataHandler(handler: () => void): void;
@@ -0,0 +1,25 @@
1
+ import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
2
+ import * as __WEBPACK_EXTERNAL_MODULE__useCanFetchPublicData_js_b8d90132__ from "./useCanFetchPublicData.js";
3
+
4
+ ;// CONCATENATED MODULE: external "react"
5
+
6
+ ;// CONCATENATED MODULE: external "./useCanFetchPublicData.js"
7
+
8
+ ;// CONCATENATED MODULE: ./src/usePublicDataHandler.ts?__rslib_entry__
9
+
10
+
11
+ function usePublicDataHandler(handler) {
12
+ const canFetchPublicData = (0,__WEBPACK_EXTERNAL_MODULE__useCanFetchPublicData_js_b8d90132__.useCanFetchPublicData)();
13
+ (0,__WEBPACK_EXTERNAL_MODULE_react__.useEffect)(()=>{
14
+ if (canFetchPublicData) {
15
+ handler();
16
+ }
17
+ }, [
18
+ canFetchPublicData,
19
+ handler
20
+ ]);
21
+ }
22
+
23
+ export { usePublicDataHandler };
24
+
25
+ //# sourceMappingURL=usePublicDataHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePublicDataHandler.js","sources":["webpack://@squide/firefly/./src/usePublicDataHandler.ts"],"sourcesContent":["import { useEffect } from \"react\";\nimport { useCanFetchPublicData } from \"./useCanFetchPublicData.ts\";\n\nexport function usePublicDataHandler(handler: () => void) {\n const canFetchPublicData = useCanFetchPublicData();\n\n useEffect(() => {\n if (canFetchPublicData) {\n handler();\n }\n }, [canFetchPublicData, handler]);\n}\n"],"names":["useEffect","useCanFetchPublicData","usePublicDataHandler","handler","canFetchPublicData"],"mappings":";;;;;;;;AAAkC;AACiC;AAE5D,SAASE,qBAAqBC,OAAmB;IACpD,MAAMC,qBAAqBH,wFAAqBA;IAEhDD,+CAASA,CAAC;QACN,IAAII,oBAAoB;YACpBD;QACJ;IACJ,GAAG;QAACC;QAAoBD;KAAQ;AACpC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@squide/firefly",
3
3
  "author": "Workleap",
4
- "version": "10.0.0",
4
+ "version": "11.0.0",
5
5
  "description": "Helpers to facilitate the creation of an application with the Squide firefly technology stack.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -37,33 +37,28 @@
37
37
  "dependencies": {
38
38
  "@types/react": "19.0.10",
39
39
  "@types/react-dom": "19.0.4",
40
- "@squide/core": "5.4.2",
41
- "@squide/module-federation": "6.2.2",
42
- "@squide/msw": "3.2.2",
43
- "@squide/react-router": "7.0.0"
40
+ "@squide/module-federation": "6.2.4",
41
+ "@squide/core": "5.4.4",
42
+ "@squide/msw": "3.2.4",
43
+ "@squide/react-router": "7.0.2"
44
44
  },
45
45
  "devDependencies": {
46
- "@rsbuild/core": "1.2.18",
46
+ "@rsbuild/core": "1.2.19",
47
47
  "@rslib/core": "0.5.4",
48
- "@swc/core": "1.11.9",
49
- "@swc/jest": "0.2.37",
50
- "@testing-library/jest-dom": "6.6.3",
51
48
  "@testing-library/react": "16.2.0",
52
- "@types/jest": "29.5.14",
53
49
  "@typescript-eslint/parser": "8.26.1",
50
+ "@vitejs/plugin-react": "4.3.4",
54
51
  "@workleap/eslint-plugin": "3.3.0",
55
52
  "@workleap/rslib-configs": "1.0.2",
56
- "@workleap/swc-configs": "2.2.4",
57
53
  "@workleap/typescript-configs": "3.0.2",
58
54
  "eslint": "8.57.0",
59
- "jest": "29.7.0",
60
- "jest-environment-jsdom": "29.7.0",
55
+ "happy-dom": "17.4.4",
61
56
  "msw": "2.7.3",
62
57
  "react": "19.0.0",
63
58
  "react-dom": "19.0.0",
64
59
  "react-router": "7.3.0",
65
- "ts-node": "10.9.2",
66
- "typescript": "5.5.4"
60
+ "typescript": "5.8.2",
61
+ "vitest": "3.0.8"
67
62
  },
68
63
  "sideEffects": false,
69
64
  "engines": {
@@ -73,6 +68,6 @@
73
68
  "build": "rslib build --config ./rslib.build.ts",
74
69
  "eslint": "eslint . --max-warnings=-0 --cache --cache-location node_modules/.cache/eslint",
75
70
  "typecheck": "tsc",
76
- "test": "jest"
71
+ "test": "vitest --config vitest.config.ts --no-watch"
77
72
  }
78
73
  }
package/src/AppRouter.tsx CHANGED
@@ -3,7 +3,7 @@ import { useRoutes, type Route } from "@squide/react-router";
3
3
  import { useEffect, useMemo, type ReactElement } from "react";
4
4
  import type { RouterProviderProps } from "react-router/dom";
5
5
  import { AppRouterDispatcherContext, AppRouterStateContext } from "./AppRouterContext.ts";
6
- import { useAppRouterReducer } from "./AppRouterReducer.ts";
6
+ import { useAppRouterReducer, type AppRouterState } from "./AppRouterReducer.ts";
7
7
  import { RootRoute } from "./RootRoute.tsx";
8
8
  import { useStrictRegistrationMode } from "./useStrictRegistrationMode.ts";
9
9
 
@@ -19,6 +19,34 @@ export interface RenderRouterProviderFunctionArgs {
19
19
 
20
20
  export type RenderRouterProviderFunction = (args: RenderRouterProviderFunctionArgs) => ReactElement;
21
21
 
22
+ export function useCanRenderRouter({ areModulesRegistered, areModulesReady: areModulesReadyValue }: AppRouterState) {
23
+ return (
24
+ // Wait until the modules has been registered, but do not wait for the deferred registrations to be registered has they will probably
25
+ // depends on the protected data.
26
+ (areModulesRegistered || areModulesReadyValue)
27
+ );
28
+ }
29
+
30
+ function useRenderRouterProvider(state: AppRouterState, renderRouterProvider: RenderRouterProviderFunction) {
31
+ const routes = useRoutes();
32
+
33
+ // The value is computed outside of the router provider memo to prevent
34
+ // rendering a new router provider everytime the app router state change.
35
+ const canRenderRouter = useCanRenderRouter(state);
36
+
37
+ return useMemo(() => {
38
+ if (canRenderRouter) {
39
+ return renderRouterProvider({
40
+ rootRoute: <RootRoute />,
41
+ registeredRoutes: routes,
42
+ routerProviderProps: {}
43
+ });
44
+ }
45
+
46
+ return null;
47
+ }, [canRenderRouter, routes, renderRouterProvider]);
48
+ }
49
+
22
50
  export interface AppRouterProps {
23
51
  waitForMsw: boolean;
24
52
  waitForPublicData?: boolean;
@@ -37,7 +65,6 @@ export function AppRouter(props: AppRouterProps) {
37
65
  const [state, dispatch] = useAppRouterReducer(waitForMsw, waitForPublicData, waitForProtectedData);
38
66
 
39
67
  const logger = useLogger();
40
- const routes = useRoutes();
41
68
 
42
69
  useStrictRegistrationMode();
43
70
 
@@ -45,13 +72,7 @@ export function AppRouter(props: AppRouterProps) {
45
72
  logger.debug("[squide] AppRouter state updated:", state);
46
73
  }, [state, logger]);
47
74
 
48
- const routerProvider = useMemo(() => {
49
- return renderRouterProvider({
50
- rootRoute: <RootRoute />,
51
- registeredRoutes: routes,
52
- routerProviderProps: {}
53
- });
54
- }, [routes, renderRouterProvider]);
75
+ const routerProvider = useRenderRouterProvider(state, renderRouterProvider);
55
76
 
56
77
  return (
57
78
  <AppRouterDispatcherContext.Provider value={dispatch}>
@@ -3,7 +3,7 @@ import { addRemoteModuleRegistrationStatusChangedListener, areModulesReady, areM
3
3
  import { addMswStateChangedListener, isMswReady, removeMswStateChangedListener } from "@squide/msw";
4
4
  import { useCallback, useEffect, useMemo, useReducer, type Dispatch } from "react";
5
5
  import { useExecuteOnce } from "./useExecuteOnce.ts";
6
- import { isApplicationBootstrapping } from "./useIsBootstrapping.ts";
6
+ import { isBootstrapping } from "./useIsBootstrapping.ts";
7
7
 
8
8
  export type ActiveRouteVisiblity = "unknown" | "public" | "protected";
9
9
 
@@ -250,7 +250,7 @@ export function useBootstrappingCompletedDispatcher(state: AppRouterState) {
250
250
  const eventBus = useEventBus();
251
251
 
252
252
  const areModulesRegisteredValue = state.areModulesRegistered;
253
- const isBoostrapping = isApplicationBootstrapping(state);
253
+ const isBoostrapping = isBootstrapping(state);
254
254
 
255
255
  useExecuteOnce(useCallback(() => {
256
256
  if (areModulesRegisteredValue && !isBoostrapping) {
@@ -0,0 +1,19 @@
1
+ import { type Runtime, RuntimeContext } from "@squide/core";
2
+ import type { PropsWithChildren } from "react";
3
+
4
+ export interface FireflyProviderProps extends PropsWithChildren {
5
+ runtime: Runtime;
6
+ }
7
+
8
+ export function FireflyProvider(props: FireflyProviderProps) {
9
+ const {
10
+ runtime,
11
+ children
12
+ } = props;
13
+
14
+ return (
15
+ <RuntimeContext.Provider value={runtime}>
16
+ {children}
17
+ </RuntimeContext.Provider>
18
+ );
19
+ }
package/src/boostrap.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { isFunction, registerLocalModules, type ModuleRegisterFunction, type ModuleRegistrationError, type RegisterModulesOptions } from "@squide/core";
2
- import { registerRemoteModules, type RemoteDefinition, type RemoteModuleRegistrationError } from "@squide/module-federation";
1
+ import { isFunction, registerLocalModules, type ModuleRegisterFunction, type RegisterModulesOptions } from "@squide/core";
2
+ import { registerRemoteModules, type RemoteDefinition } from "@squide/module-federation";
3
3
  import { setMswAsReady } from "@squide/msw";
4
4
  import type { FireflyRuntime } from "./FireflyRuntime.tsx";
5
5
 
@@ -7,20 +7,34 @@ export const ApplicationBootstrappingStartedEvent = "squide-app-bootstrapping-st
7
7
 
8
8
  export type StartMswFunction<TRuntime = FireflyRuntime> = (runtime: TRuntime) => Promise<void>;
9
9
 
10
+ export type OnBootstrapErrorFunction = (error: unknown) => void;
11
+
10
12
  export interface BootstrapAppOptions<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown> extends RegisterModulesOptions<TContext> {
11
13
  localModules?: ModuleRegisterFunction<TRuntime, TContext, TData>[];
12
14
  remotes?: RemoteDefinition[];
13
15
  startMsw?: StartMswFunction<TRuntime>;
16
+ onError?: OnBootstrapErrorFunction;
17
+ }
18
+
19
+ function propagateRegistrationErrors(results: PromiseSettledResult<unknown[]>, onError: OnBootstrapErrorFunction) {
20
+ if (results) {
21
+ if (results.status === "fulfilled") {
22
+ results.value.forEach(x => {
23
+ onError(x);
24
+ });
25
+ }
26
+ }
14
27
  }
15
28
 
16
29
  let hasExecuted = false;
17
30
 
18
- export async function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options: BootstrapAppOptions<TRuntime, TContext, TData> = {}) {
31
+ export function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options: BootstrapAppOptions<TRuntime, TContext, TData> = {}) {
19
32
  const {
20
33
  localModules = [],
21
34
  remotes = [],
22
35
  context,
23
- startMsw
36
+ startMsw,
37
+ onError
24
38
  } = options;
25
39
 
26
40
  if (hasExecuted) {
@@ -31,30 +45,29 @@ export async function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime
31
45
 
32
46
  runtime.eventBus.dispatch(ApplicationBootstrappingStartedEvent);
33
47
 
34
- let localModuleErrors: ModuleRegistrationError[] = [];
35
- let remoteModuleErrors: RemoteModuleRegistrationError[] = [];
48
+ Promise.allSettled([
49
+ registerLocalModules<TRuntime, TContext, TData>(localModules, runtime, { context }),
50
+ registerRemoteModules(remotes, runtime, { context })
51
+ ]).then(results => {
52
+ if (runtime.isMswEnabled) {
53
+ if (!isFunction(startMsw)) {
54
+ throw new Error("[squide] When MSW is enabled, the \"startMsw\" function must be provided.");
55
+ }
36
56
 
37
- localModuleErrors = await registerLocalModules<TRuntime, TContext, TData>(localModules, runtime, { context });
38
- remoteModuleErrors = await registerRemoteModules(remotes, runtime, { context });
39
-
40
- if (runtime.isMswEnabled) {
41
- if (!isFunction(startMsw)) {
42
- throw new Error("[squide] When MSW is enabled, the \"startMsw\" function must be provided.");
57
+ startMsw(runtime)
58
+ .then(() => {
59
+ setMswAsReady();
60
+ })
61
+ .catch((error: unknown) => {
62
+ runtime.logger.debug("[squide] An error occured while starting MSW.", error);
63
+ });
43
64
  }
44
65
 
45
- try {
46
- await startMsw(runtime);
47
-
48
- setMswAsReady();
49
- } catch (error: unknown) {
50
- runtime.logger.debug("[squide] An error occured while starting MSW.", error);
66
+ if (onError) {
67
+ propagateRegistrationErrors(results[0], onError);
68
+ propagateRegistrationErrors(results[1], onError);
51
69
  }
52
- }
53
-
54
- return {
55
- localModuleErrors,
56
- remoteModuleErrors
57
- };
70
+ });
58
71
  }
59
72
 
60
73
  export function __resetHasExecuteGuard() {
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from "@squide/module-federation";
3
3
  export * from "@squide/msw";
4
4
  export * from "@squide/react-router";
5
5
 
6
+ export * from "./FireflyProvider.tsx";
6
7
  export * from "./FireflyRuntime.tsx";
7
8
 
8
9
  export * from "./AppRouter.tsx";
@@ -18,7 +19,9 @@ export * from "./useDeferredRegistrations.ts";
18
19
  export * from "./useIsActiveRouteProtected.ts";
19
20
  export * from "./useIsBootstrapping.ts";
20
21
  export * from "./useNavigationItems.ts";
22
+ export * from "./useProtectedDataHandler.ts";
21
23
  export * from "./useProtectedDataQueries.ts";
24
+ export * from "./usePublicDataHandler.ts";
22
25
  export * from "./usePublicDataQueries.ts";
23
26
  export * from "./useRegisterDeferredRegistrations.ts";
24
27
  export * from "./useStrictRegistrationMode.ts";
@@ -4,10 +4,10 @@ import type { AppRouterState } from "./AppRouterReducer.ts";
4
4
  export function useIsBootstrapping() {
5
5
  const state = useAppRouterState();
6
6
 
7
- return isApplicationBootstrapping(state);
7
+ return isBootstrapping(state);
8
8
  }
9
9
 
10
- export function isApplicationBootstrapping(state: AppRouterState) {
10
+ export function isBootstrapping(state: AppRouterState) {
11
11
  const {
12
12
  waitForMsw,
13
13
  waitForPublicData,
@@ -0,0 +1,12 @@
1
+ import { useEffect } from "react";
2
+ import { useCanFetchProtectedData } from "./useCanFetchProtectedData.ts";
3
+
4
+ export function useProtectedDataHandler(handler: () => void) {
5
+ const canFetchProtectedData = useCanFetchProtectedData();
6
+
7
+ useEffect(() => {
8
+ if (canFetchProtectedData) {
9
+ handler();
10
+ }
11
+ }, [canFetchProtectedData, handler]);
12
+ }
@@ -0,0 +1,12 @@
1
+ import { useEffect } from "react";
2
+ import { useCanFetchPublicData } from "./useCanFetchPublicData.ts";
3
+
4
+ export function usePublicDataHandler(handler: () => void) {
5
+ const canFetchPublicData = useCanFetchPublicData();
6
+
7
+ useEffect(() => {
8
+ if (canFetchPublicData) {
9
+ handler();
10
+ }
11
+ }, [canFetchPublicData, handler]);
12
+ }