@squide/firefly 16.1.12 → 16.2.1

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,17 @@
1
1
  # @squide/firefly
2
2
 
3
+ ## 16.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#567](https://github.com/workleap/wl-squide/pull/567) [`5f16979`](https://github.com/workleap/wl-squide/commit/5f16979d9e922590fdca39be76e79dde54211efa) Thanks [@patricklafrance](https://github.com/patricklafrance)! - useDeferredRegistrations will now trigger a deferred registration update whenever the data object reference changes, even if no global data has been fetch or no feature flags changed.
8
+
9
+ ## 16.2.0
10
+
11
+ ### Minor Changes
12
+
13
+ - [#559](https://github.com/workleap/wl-squide/pull/559) [`33b1cd6`](https://github.com/workleap/wl-squide/commit/33b1cd639ef97e9d9fc892918ab6cbd08e6b91e9) Thanks [@patricklafrance](https://github.com/patricklafrance)! - React Router loaders execution is now delayed until MSW is ready.
14
+
3
15
  ## 16.1.12
4
16
 
5
17
  ### Patch Changes
@@ -1,17 +1,21 @@
1
1
  import { type Route } from "@squide/react-router";
2
2
  import { type ReactElement } from "react";
3
+ import { DataStrategyFunction, DataStrategyFunctionArgs, DOMRouterOpts } from "react-router";
3
4
  import type { RouterProviderProps } from "react-router/dom";
4
5
  import { type AppRouterState } from "./AppRouterReducer.ts";
6
+ import { FireflyRuntime } from "./FireflyRuntime.tsx";
5
7
  export interface AppRouterRenderFunctionArgs {
6
8
  routes: Route[];
7
9
  }
8
10
  export interface RenderRouterProviderFunctionArgs {
9
11
  rootRoute: ReactElement;
10
12
  registeredRoutes: Route[];
13
+ routerProps: DOMRouterOpts;
11
14
  routerProviderProps: Omit<RouterProviderProps, "router">;
12
15
  }
13
16
  export type RenderRouterProviderFunction = (args: RenderRouterProviderFunctionArgs) => ReactElement;
14
17
  export declare function useCanRenderRouter({ areModulesRegistered, areModulesReady: areModulesReadyValue }: AppRouterState): boolean;
18
+ export declare function createWaitForMswDataStrategy(runtime: FireflyRuntime): (args: DataStrategyFunctionArgs<unknown>) => ReturnType<DataStrategyFunction<unknown>>;
15
19
  export interface AppRouterProps {
16
20
  waitForPublicData?: boolean;
17
21
  waitForProtectedData?: boolean;
package/dist/AppRouter.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useLogger } from "@squide/core";
2
+ import { useLogger, useRuntime } from "@squide/core";
3
3
  import { useRoutes } from "@squide/react-router";
4
4
  import { useEffect, useMemo } from "react";
5
5
  import { AppRouterDispatcherContext, AppRouterStateContext } from "./AppRouterContext.js";
@@ -37,7 +37,34 @@ function useCanRenderRouter({ areModulesRegistered, areModulesReady: areModulesR
37
37
  // depends on the protected data.
38
38
  areModulesRegistered || areModulesReadyValue);
39
39
  }
40
+ // This is a custom React Router data strategy (https://reactrouter.com/api/data-routers/createMemoryRouter#optsdatastrategy)
41
+ // to delay the execution of React Router data browser loaders until MSW is ready.
42
+ // The data strategy implemention is copied from React Router default data strategy: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L5710.
43
+ function createWaitForMswDataStrategy(runtime) {
44
+ const strategy = async (args)=>{
45
+ await new Promise((resolve)=>{
46
+ if (runtime.mswState.isReady) {
47
+ resolve(null);
48
+ } else {
49
+ const handler = ()=>{
50
+ runtime.mswState.removeMswReadyListener(handler);
51
+ resolve(null);
52
+ };
53
+ runtime.mswState.addMswReadyListener(handler);
54
+ }
55
+ });
56
+ const matchesToLoad = args.matches.filter((m)=>m.shouldCallHandler);
57
+ const keyedResults = {};
58
+ const results = await Promise.all(matchesToLoad.map((m)=>m.resolve()));
59
+ results.forEach((result, i)=>{
60
+ keyedResults[matchesToLoad[i].route.id] = result;
61
+ });
62
+ return keyedResults;
63
+ };
64
+ return strategy;
65
+ }
40
66
  function useRenderRouterProvider(state, renderRouterProvider, strictMode) {
67
+ const runtime = useRuntime();
41
68
  const routes = useRoutes();
42
69
  // The value is computed outside of the router provider memo to prevent
43
70
  // rendering a new router provider everytime the app router state change.
@@ -49,11 +76,15 @@ function useRenderRouterProvider(state, renderRouterProvider, strictMode) {
49
76
  strictMode: strictMode
50
77
  }),
51
78
  registeredRoutes: routes,
79
+ routerProps: {
80
+ dataStrategy: runtime.isMswEnabled ? createWaitForMswDataStrategy(runtime) : undefined
81
+ },
52
82
  routerProviderProps: {}
53
83
  });
54
84
  }
55
85
  return null;
56
86
  }, [
87
+ runtime,
57
88
  canRenderRouter,
58
89
  routes,
59
90
  renderRouterProvider,
@@ -83,6 +114,6 @@ function AppRouter(props) {
83
114
  });
84
115
  }
85
116
 
86
- export { AppRouter, useCanRenderRouter };
117
+ export { AppRouter, createWaitForMswDataStrategy, useCanRenderRouter };
87
118
 
88
119
  //# sourceMappingURL=AppRouter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AppRouter.js","sources":["../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, strictMode: boolean) {\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 strictMode={strictMode} />,\n registeredRoutes: routes,\n routerProviderProps: {}\n });\n }\n\n return null;\n }, [canRenderRouter, routes, renderRouterProvider, strictMode]);\n}\n\nexport interface AppRouterProps {\n waitForPublicData?: boolean;\n waitForProtectedData?: boolean;\n strictMode?: boolean;\n children: RenderRouterProviderFunction;\n}\n\nexport function AppRouter(props: AppRouterProps) {\n const {\n waitForPublicData = false,\n waitForProtectedData = false,\n strictMode = true,\n children: renderRouterProvider\n } = props;\n const [state, dispatch] = useAppRouterReducer(waitForPublicData, waitForProtectedData);\n\n const logger = useLogger();\n\n useStrictRegistrationMode({\n isEnabled: strictMode\n });\n\n useEffect(() => {\n logger\n .withText(\"[squide] AppRouter state has been updated to:\")\n .withObject(state)\n .debug();\n }, [state, logger]);\n\n const routerProvider = useRenderRouterProvider(state, renderRouterProvider, strictMode);\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","strictMode","routes","canRenderRouter","AppRouter","props","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,EAAEC,UAAmB;IAC3H,MAAMC,SAASf,SAASA;IAExB,uEAAuE;IACvE,yEAAyE;IACzE,MAAMgB,kBAAkBR,mBAAmBI;IAE3C,OAAOV,OAAOA,CAAC;QACX,IAAIc,iBAAiB;YACjB,OAAOH,qBAAqB;gBACxB,yBAAW,IAACP,SAASA;oBAAC,YAAYQ;;gBAClC,kBAAkBC;gBAClB,qBAAqB,CAAC;YAC1B;QACJ;QAEA,OAAO;IACX,GAAG;QAACC;QAAiBD;QAAQF;QAAsBC;KAAW;AAClE;AASO,SAASG,UAAUC,KAAqB;IAC3C,MAAM,EACFC,oBAAoB,KAAK,EACzBC,uBAAuB,KAAK,EAC5BN,aAAa,IAAI,EACjB,UAAUD,oBAAoB,EACjC,GAAGK;IACJ,MAAM,CAACN,OAAOS,SAAS,GAAGhB,mBAAmBA,CAACc,mBAAmBC;IAEjE,MAAME,SAASvB,SAASA;IAExBQ,yBAAyBA,CAAC;QACtB,WAAWO;IACf;IAEAb,SAASA,CAAC;QACNqB,OACK,QAAQ,CAAC,iDACT,UAAU,CAACV,OACX,KAAK;IACd,GAAG;QAACA;QAAOU;KAAO;IAElB,MAAMC,iBAAiBZ,wBAAwBC,OAAOC,sBAAsBC;IAE5E,qBACI,IAACX,mCAAmC;QAAC,OAAOkB;kBACxC,kBAACjB,8BAA8B;YAAC,OAAOQ;sBAClCW;;;AAIjB"}
1
+ {"version":3,"file":"AppRouter.js","sources":["../src/AppRouter.tsx"],"sourcesContent":["import { useLogger, useRuntime } from \"@squide/core\";\nimport { useRoutes, type Route } from \"@squide/react-router\";\nimport { useEffect, useMemo, type ReactElement } from \"react\";\nimport { DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyResult, DOMRouterOpts } from \"react-router\";\nimport type { RouterProviderProps } from \"react-router/dom\";\nimport { AppRouterDispatcherContext, AppRouterStateContext } from \"./AppRouterContext.ts\";\nimport { useAppRouterReducer, type AppRouterState } from \"./AppRouterReducer.ts\";\nimport { FireflyRuntime } from \"./FireflyRuntime.tsx\";\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 routerProps: DOMRouterOpts;\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\n// This is a custom React Router data strategy (https://reactrouter.com/api/data-routers/createMemoryRouter#optsdatastrategy)\n// to delay the execution of React Router data browser loaders until MSW is ready.\n// The data strategy implemention is copied from React Router default data strategy: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L5710.\nexport function createWaitForMswDataStrategy(runtime: FireflyRuntime) {\n const strategy: (args: DataStrategyFunctionArgs<unknown>) => ReturnType<DataStrategyFunction<unknown>> = async args => {\n await new Promise(resolve => {\n if (runtime.mswState.isReady) {\n resolve(null);\n } else {\n const handler = () => {\n runtime.mswState.removeMswReadyListener(handler);\n resolve(null);\n };\n\n runtime.mswState.addMswReadyListener(handler);\n }\n });\n\n const matchesToLoad = args.matches.filter(m => m.shouldCallHandler);\n const keyedResults: Record<string, DataStrategyResult> = {};\n const results = await Promise.all(matchesToLoad.map(m => m.resolve()));\n\n results.forEach((result, i) => {\n keyedResults[matchesToLoad[i].route.id] = result;\n });\n\n return keyedResults;\n };\n\n return strategy;\n}\n\nfunction useRenderRouterProvider(state: AppRouterState, renderRouterProvider: RenderRouterProviderFunction, strictMode: boolean) {\n const runtime = useRuntime() as FireflyRuntime;\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 strictMode={strictMode} />,\n registeredRoutes: routes,\n routerProps: {\n dataStrategy: runtime.isMswEnabled ? createWaitForMswDataStrategy(runtime) : undefined\n },\n routerProviderProps: {}\n });\n }\n\n return null;\n }, [runtime, canRenderRouter, routes, renderRouterProvider, strictMode]);\n}\n\nexport interface AppRouterProps {\n waitForPublicData?: boolean;\n waitForProtectedData?: boolean;\n strictMode?: boolean;\n children: RenderRouterProviderFunction;\n}\n\nexport function AppRouter(props: AppRouterProps) {\n const {\n waitForPublicData = false,\n waitForProtectedData = false,\n strictMode = true,\n children: renderRouterProvider\n } = props;\n const [state, dispatch] = useAppRouterReducer(waitForPublicData, waitForProtectedData);\n\n const logger = useLogger();\n\n useStrictRegistrationMode({\n isEnabled: strictMode\n });\n\n useEffect(() => {\n logger\n .withText(\"[squide] AppRouter state has been updated to:\")\n .withObject(state)\n .debug();\n }, [state, logger]);\n\n const routerProvider = useRenderRouterProvider(state, renderRouterProvider, strictMode);\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","useRuntime","useRoutes","useEffect","useMemo","AppRouterDispatcherContext","AppRouterStateContext","useAppRouterReducer","RootRoute","useStrictRegistrationMode","useCanRenderRouter","areModulesRegistered","areModulesReadyValue","createWaitForMswDataStrategy","runtime","strategy","args","Promise","resolve","handler","matchesToLoad","m","keyedResults","results","result","i","useRenderRouterProvider","state","renderRouterProvider","strictMode","routes","canRenderRouter","undefined","AppRouter","props","waitForPublicData","waitForProtectedData","dispatch","logger","routerProvider"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqD;AACQ;AACC;AAG4B;AACT;AAErC;AAC+B;AAepE,SAASU,mBAAmB,EAAEC,oBAAoB,EAAE,iBAAiBC,oBAAoB,EAAkB;IAC9G,OACI,qIAAqI;IACrI,iCAAiC;IAChCD,wBAAwBC;AAEjC;AAEA,6HAA6H;AAC7H,kFAAkF;AAClF,0LAA0L;AACnL,SAASC,6BAA6BC,OAAuB;IAChE,MAAMC,WAAmG,OAAMC;QAC3G,MAAM,IAAIC,QAAQC,CAAAA;YACd,IAAIJ,QAAQ,QAAQ,CAAC,OAAO,EAAE;gBAC1BI,QAAQ;YACZ,OAAO;gBACH,MAAMC,UAAU;oBACZL,QAAQ,QAAQ,CAAC,sBAAsB,CAACK;oBACxCD,QAAQ;gBACZ;gBAEAJ,QAAQ,QAAQ,CAAC,mBAAmB,CAACK;YACzC;QACJ;QAEA,MAAMC,gBAAgBJ,KAAK,OAAO,CAAC,MAAM,CAACK,CAAAA,IAAKA,EAAE,iBAAiB;QAClE,MAAMC,eAAmD,CAAC;QAC1D,MAAMC,UAAU,MAAMN,QAAQ,GAAG,CAACG,cAAc,GAAG,CAACC,CAAAA,IAAKA,EAAE,OAAO;QAElEE,QAAQ,OAAO,CAAC,CAACC,QAAQC;YACrBH,YAAY,CAACF,aAAa,CAACK,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,GAAGD;QAC9C;QAEA,OAAOF;IACX;IAEA,OAAOP;AACX;AAEA,SAASW,wBAAwBC,KAAqB,EAAEC,oBAAkD,EAAEC,UAAmB;IAC3H,MAAMf,UAAUb,UAAUA;IAC1B,MAAM6B,SAAS5B,SAASA;IAExB,uEAAuE;IACvE,yEAAyE;IACzE,MAAM6B,kBAAkBrB,mBAAmBiB;IAE3C,OAAOvB,OAAOA,CAAC;QACX,IAAI2B,iBAAiB;YACjB,OAAOH,qBAAqB;gBACxB,yBAAW,IAACpB,SAASA;oBAAC,YAAYqB;;gBAClC,kBAAkBC;gBAClB,aAAa;oBACT,cAAchB,QAAQ,YAAY,GAAGD,6BAA6BC,WAAWkB;gBACjF;gBACA,qBAAqB,CAAC;YAC1B;QACJ;QAEA,OAAO;IACX,GAAG;QAAClB;QAASiB;QAAiBD;QAAQF;QAAsBC;KAAW;AAC3E;AASO,SAASI,UAAUC,KAAqB;IAC3C,MAAM,EACFC,oBAAoB,KAAK,EACzBC,uBAAuB,KAAK,EAC5BP,aAAa,IAAI,EACjB,UAAUD,oBAAoB,EACjC,GAAGM;IACJ,MAAM,CAACP,OAAOU,SAAS,GAAG9B,mBAAmBA,CAAC4B,mBAAmBC;IAEjE,MAAME,SAAStC,SAASA;IAExBS,yBAAyBA,CAAC;QACtB,WAAWoB;IACf;IAEA1B,SAASA,CAAC;QACNmC,OACK,QAAQ,CAAC,iDACT,UAAU,CAACX,OACX,KAAK;IACd,GAAG;QAACA;QAAOW;KAAO;IAElB,MAAMC,iBAAiBb,wBAAwBC,OAAOC,sBAAsBC;IAE5E,qBACI,IAACxB,mCAAmC;QAAC,OAAOgC;kBACxC,kBAAC/B,8BAA8B;YAAC,OAAOqB;sBAClCY;;;AAIjB"}
@@ -1 +1 @@
1
- export declare function useCanUpdateDeferredRegistrations(): boolean | 0 | undefined;
1
+ export declare function useCanUpdateDeferredRegistrations(): boolean;
@@ -5,10 +5,21 @@ import { useAppRouterState } from "./AppRouterContext.js";
5
5
  ;// CONCATENATED MODULE: ./src/useCanUpdateDeferredRegistrations.ts
6
6
 
7
7
  function useCanUpdateDeferredRegistrations() {
8
- const { areModulesReady, publicDataUpdatedAt, protectedDataUpdatedAt, featureFlagsUpdatedAt, deferredRegistrationsUpdatedAt } = useAppRouterState();
9
- return(// Do not trigger an update if the deferred registrations has not been registered yet (if there are deferred registrations, once they are
10
- // registered, the modules will be marked as ready).
11
- areModulesReady && deferredRegistrationsUpdatedAt && (publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt || protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt || featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt));
8
+ const { areModulesReady } = useAppRouterState();
9
+ return areModulesReady;
10
+ // return !!(
11
+ // // Do not trigger an update if the deferred registrations has not been registered yet (if there are deferred registrations, once they are
12
+ // // registered, the modules will be marked as ready).
13
+ // areModulesReady
14
+ // // Make sure the apps is actually having deferred registrations.
15
+ // // && deferredRegistrationsUpdatedAt
16
+ // // // If either the public data or the protected data has been updated, update the deferred registrations.
17
+ // // && (
18
+ // // (publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
19
+ // // (protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
20
+ // // (featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt)
21
+ // // )
22
+ // );
12
23
  }
13
24
 
14
25
  export { useCanUpdateDeferredRegistrations };
@@ -1 +1 @@
1
- {"version":3,"file":"useCanUpdateDeferredRegistrations.js","sources":["../src/useCanUpdateDeferredRegistrations.ts"],"sourcesContent":["import { useAppRouterState } from \"./AppRouterContext.ts\";\n\nexport function useCanUpdateDeferredRegistrations() {\n const {\n areModulesReady,\n publicDataUpdatedAt,\n protectedDataUpdatedAt,\n featureFlagsUpdatedAt,\n deferredRegistrationsUpdatedAt\n } = useAppRouterState();\n\n return (\n // Do not trigger an update if the deferred registrations has not been registered yet (if there are deferred registrations, once they are\n // registered, the modules will be marked as ready).\n areModulesReady\n // Make sure the apps is actually having deferred registrations.\n && deferredRegistrationsUpdatedAt\n // If either the public data or the protected data has been updated, update the deferred registrations.\n && (\n (publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt) ||\n (protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt) ||\n (featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt)\n )\n );\n}\n"],"names":["useAppRouterState","useCanUpdateDeferredRegistrations","areModulesReady","publicDataUpdatedAt","protectedDataUpdatedAt","featureFlagsUpdatedAt","deferredRegistrationsUpdatedAt"],"mappings":";;;;;AAA0D;AAEnD,SAASC;IACZ,MAAM,EACFC,eAAe,EACfC,mBAAmB,EACnBC,sBAAsB,EACtBC,qBAAqB,EACrBC,8BAA8B,EACjC,GAAGN,iBAAiBA;IAErB,OACI,yIAAyI;IACzI,oDAAoD;IACpDE,mBAEGI,kCAGC,CAACH,uBAAuBA,sBAAsBG,kCAC7CF,0BAA0BA,yBAAyBE,kCACnDD,yBAAyBA,wBAAwBC,8BAA8B;AAG5F"}
1
+ {"version":3,"file":"useCanUpdateDeferredRegistrations.js","sources":["../src/useCanUpdateDeferredRegistrations.ts"],"sourcesContent":["import { useAppRouterState } from \"./AppRouterContext.ts\";\n\nexport function useCanUpdateDeferredRegistrations() {\n const {\n areModulesReady\n // publicDataUpdatedAt,\n // protectedDataUpdatedAt,\n // featureFlagsUpdatedAt,\n // deferredRegistrationsUpdatedAt\n } = useAppRouterState();\n\n return areModulesReady;\n\n // return !!(\n // // Do not trigger an update if the deferred registrations has not been registered yet (if there are deferred registrations, once they are\n // // registered, the modules will be marked as ready).\n // areModulesReady\n // // Make sure the apps is actually having deferred registrations.\n // // && deferredRegistrationsUpdatedAt\n // // // If either the public data or the protected data has been updated, update the deferred registrations.\n // // && (\n // // (publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt) ||\n // // (protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt) ||\n // // (featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt)\n // // )\n // );\n}\n"],"names":["useAppRouterState","useCanUpdateDeferredRegistrations","areModulesReady"],"mappings":";;;;;AAA0D;AAEnD,SAASC;IACZ,MAAM,EACFC,eAAe,EAKlB,GAAGF,iBAAiBA;IAErB,OAAOE;AAEP,aAAa;AACb,gJAAgJ;AAChJ,2DAA2D;AAC3D,sBAAsB;AACtB,uEAAuE;AACvE,2CAA2C;AAC3C,iHAAiH;AACjH,cAAc;AACd,8FAA8F;AAC9F,oGAAoG;AACpG,+FAA+F;AAC/F,WAAW;AACX,KAAK;AACT"}
@@ -1,5 +1,5 @@
1
1
  import { useRuntime } from "@squide/core";
2
- import { useEffect } from "react";
2
+ import { useEffect, useRef } from "react";
3
3
  import { useCanRegisterDeferredRegistrations } from "./useCanRegisterDeferredRegistrations.js";
4
4
  import { useCanUpdateDeferredRegistrations } from "./useCanUpdateDeferredRegistrations.js";
5
5
  import { useRegisterDeferredRegistrations } from "./useRegisterDeferredRegistrations.js";
@@ -26,6 +26,7 @@ import { useUpdateDeferredRegistrations } from "./useUpdateDeferredRegistrations
26
26
 
27
27
  function useDeferredRegistrations(data, { onError } = {}) {
28
28
  const runtime = useRuntime();
29
+ // const isExecutedBecauseModulesAreNowReadyRef = useRef(true);
29
30
  const canRegisterDeferredRegistrations = useCanRegisterDeferredRegistrations();
30
31
  const canUpdateDeferredRegistrations = useCanUpdateDeferredRegistrations();
31
32
  const registerDeferredRegistrations = useRegisterDeferredRegistrations();
@@ -46,8 +47,18 @@ function useDeferredRegistrations(data, { onError } = {}) {
46
47
  data,
47
48
  onError
48
49
  ]);
50
+ const isInitialUpdateDeferredRegistrationsExecution = useRef(true);
49
51
  useEffect(()=>{
50
52
  if (canUpdateDeferredRegistrations) {
53
+ // HACK: Skipping the first execution successfully passing the gate because this is due to
54
+ // the modules being ready, and it's most certainly the same data that has been forwarded earlier to the deferred registration.
55
+ // Ideally, instead of this hacky ref, it would be a ref tracking the previous data object, and the deferred registration would
56
+ // only be updated if the current data object != than the previous data object. Sadly, it is not possible because
57
+ // of the feature flags.
58
+ if (isInitialUpdateDeferredRegistrationsExecution.current) {
59
+ isInitialUpdateDeferredRegistrationsExecution.current = false;
60
+ return;
61
+ }
51
62
  const update = async ()=>{
52
63
  const errors = await updateDeferredRegistrations(data);
53
64
  if (errors.length > 0 && onError) {
@@ -1 +1 @@
1
- {"version":3,"file":"useDeferredRegistrations.js","sources":["../src/useDeferredRegistrations.ts"],"sourcesContent":["import { useRuntime, type ModuleRegistrationError } from \"@squide/core\";\nimport { useEffect } from \"react\";\nimport { FireflyRuntime } from \"./FireflyRuntime.tsx\";\nimport { useCanRegisterDeferredRegistrations } from \"./useCanRegisterDeferredRegistrations.ts\";\nimport { useCanUpdateDeferredRegistrations } from \"./useCanUpdateDeferredRegistrations.ts\";\nimport { useRegisterDeferredRegistrations } from \"./useRegisterDeferredRegistrations.ts\";\nimport { useUpdateDeferredRegistrations } from \"./useUpdateDeferredRegistrations.ts\";\n\nexport type DeferredRegistrationsErrorCallback = (errors: ModuleRegistrationError[]) => void;\n\nexport interface UseDeferredRegistrationsOptions {\n onError?: DeferredRegistrationsErrorCallback;\n}\n\nexport function useDeferredRegistrations(data?: unknown, { onError }: UseDeferredRegistrationsOptions = {}) {\n const runtime = useRuntime() as FireflyRuntime;\n\n const canRegisterDeferredRegistrations = useCanRegisterDeferredRegistrations();\n const canUpdateDeferredRegistrations = useCanUpdateDeferredRegistrations();\n\n const registerDeferredRegistrations = useRegisterDeferredRegistrations();\n const updateDeferredRegistrations = useUpdateDeferredRegistrations();\n\n useEffect(() => {\n if (canRegisterDeferredRegistrations) {\n const register = async () => {\n const errors = await registerDeferredRegistrations(data);\n\n if (errors.length > 0 && onError) {\n onError(errors);\n }\n };\n\n register();\n }\n }, [canRegisterDeferredRegistrations, registerDeferredRegistrations, data, onError]);\n\n useEffect(() => {\n if (canUpdateDeferredRegistrations) {\n const update = async () => {\n const errors = await updateDeferredRegistrations(data);\n\n if (errors.length > 0 && onError) {\n onError(errors);\n }\n };\n\n update();\n }\n }, [\n canUpdateDeferredRegistrations,\n updateDeferredRegistrations,\n data,\n onError,\n // Trigger this closure when the feature flags changed. Using the timestamp because the\n // actual feature flags are not forwarded to the deferred registrations.\n runtime.appRouterStore.state.featureFlagsUpdatedAt\n ]);\n}\n"],"names":["useRuntime","useEffect","useCanRegisterDeferredRegistrations","useCanUpdateDeferredRegistrations","useRegisterDeferredRegistrations","useUpdateDeferredRegistrations","useDeferredRegistrations","data","onError","runtime","canRegisterDeferredRegistrations","canUpdateDeferredRegistrations","registerDeferredRegistrations","updateDeferredRegistrations","register","errors","update"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAwE;AACtC;AAE6D;AACJ;AACF;AACJ;AAQ9E,SAASM,yBAAyBC,IAAc,EAAE,EAAEC,OAAO,EAAmC,GAAG,CAAC,CAAC;IACtG,MAAMC,UAAUT,UAAUA;IAE1B,MAAMU,mCAAmCR,mCAAmCA;IAC5E,MAAMS,iCAAiCR,iCAAiCA;IAExE,MAAMS,gCAAgCR,gCAAgCA;IACtE,MAAMS,8BAA8BR,8BAA8BA;IAElEJ,SAASA,CAAC;QACN,IAAIS,kCAAkC;YAClC,MAAMI,WAAW;gBACb,MAAMC,SAAS,MAAMH,8BAA8BL;gBAEnD,IAAIQ,OAAO,MAAM,GAAG,KAAKP,SAAS;oBAC9BA,QAAQO;gBACZ;YACJ;YAEAD;QACJ;IACJ,GAAG;QAACJ;QAAkCE;QAA+BL;QAAMC;KAAQ;IAEnFP,SAASA,CAAC;QACN,IAAIU,gCAAgC;YAChC,MAAMK,SAAS;gBACX,MAAMD,SAAS,MAAMF,4BAA4BN;gBAEjD,IAAIQ,OAAO,MAAM,GAAG,KAAKP,SAAS;oBAC9BA,QAAQO;gBACZ;YACJ;YAEAC;QACJ;IACJ,GAAG;QACCL;QACAE;QACAN;QACAC;QACA,uFAAuF;QACvF,wEAAwE;QACxEC,QAAQ,cAAc,CAAC,KAAK,CAAC,qBAAqB;KACrD;AACL"}
1
+ {"version":3,"file":"useDeferredRegistrations.js","sources":["../src/useDeferredRegistrations.ts"],"sourcesContent":["import { useRuntime, type ModuleRegistrationError } from \"@squide/core\";\nimport { useEffect, useRef } from \"react\";\nimport { FireflyRuntime } from \"./FireflyRuntime.tsx\";\nimport { useCanRegisterDeferredRegistrations } from \"./useCanRegisterDeferredRegistrations.ts\";\nimport { useCanUpdateDeferredRegistrations } from \"./useCanUpdateDeferredRegistrations.ts\";\nimport { useRegisterDeferredRegistrations } from \"./useRegisterDeferredRegistrations.ts\";\nimport { useUpdateDeferredRegistrations } from \"./useUpdateDeferredRegistrations.ts\";\n\nexport type DeferredRegistrationsErrorCallback = (errors: ModuleRegistrationError[]) => void;\n\nexport interface UseDeferredRegistrationsOptions {\n onError?: DeferredRegistrationsErrorCallback;\n}\n\nexport function useDeferredRegistrations(data?: unknown, { onError }: UseDeferredRegistrationsOptions = {}) {\n const runtime = useRuntime() as FireflyRuntime;\n // const isExecutedBecauseModulesAreNowReadyRef = useRef(true);\n\n const canRegisterDeferredRegistrations = useCanRegisterDeferredRegistrations();\n const canUpdateDeferredRegistrations = useCanUpdateDeferredRegistrations();\n\n const registerDeferredRegistrations = useRegisterDeferredRegistrations();\n const updateDeferredRegistrations = useUpdateDeferredRegistrations();\n\n useEffect(() => {\n if (canRegisterDeferredRegistrations) {\n const register = async () => {\n const errors = await registerDeferredRegistrations(data);\n\n if (errors.length > 0 && onError) {\n onError(errors);\n }\n };\n\n register();\n }\n }, [canRegisterDeferredRegistrations, registerDeferredRegistrations, data, onError]);\n\n const isInitialUpdateDeferredRegistrationsExecution = useRef(true);\n\n useEffect(() => {\n if (canUpdateDeferredRegistrations) {\n // HACK: Skipping the first execution successfully passing the gate because this is due to\n // the modules being ready, and it's most certainly the same data that has been forwarded earlier to the deferred registration.\n // Ideally, instead of this hacky ref, it would be a ref tracking the previous data object, and the deferred registration would\n // only be updated if the current data object != than the previous data object. Sadly, it is not possible because\n // of the feature flags.\n if (isInitialUpdateDeferredRegistrationsExecution.current) {\n isInitialUpdateDeferredRegistrationsExecution.current = false;\n return;\n }\n\n const update = async () => {\n const errors = await updateDeferredRegistrations(data);\n\n if (errors.length > 0 && onError) {\n onError(errors);\n }\n };\n\n update();\n }\n }, [\n canUpdateDeferredRegistrations,\n updateDeferredRegistrations,\n data,\n onError,\n // Trigger this closure when the feature flags changed. Using the timestamp because the\n // actual feature flags are not forwarded to the deferred registrations.\n runtime.appRouterStore.state.featureFlagsUpdatedAt\n ]);\n}\n"],"names":["useRuntime","useEffect","useRef","useCanRegisterDeferredRegistrations","useCanUpdateDeferredRegistrations","useRegisterDeferredRegistrations","useUpdateDeferredRegistrations","useDeferredRegistrations","data","onError","runtime","canRegisterDeferredRegistrations","canUpdateDeferredRegistrations","registerDeferredRegistrations","updateDeferredRegistrations","register","errors","isInitialUpdateDeferredRegistrationsExecution","update"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAwE;AAC9B;AAEqD;AACJ;AACF;AACJ;AAQ9E,SAASO,yBAAyBC,IAAc,EAAE,EAAEC,OAAO,EAAmC,GAAG,CAAC,CAAC;IACtG,MAAMC,UAAUV,UAAUA;IAC1B,+DAA+D;IAE/D,MAAMW,mCAAmCR,mCAAmCA;IAC5E,MAAMS,iCAAiCR,iCAAiCA;IAExE,MAAMS,gCAAgCR,gCAAgCA;IACtE,MAAMS,8BAA8BR,8BAA8BA;IAElEL,SAASA,CAAC;QACN,IAAIU,kCAAkC;YAClC,MAAMI,WAAW;gBACb,MAAMC,SAAS,MAAMH,8BAA8BL;gBAEnD,IAAIQ,OAAO,MAAM,GAAG,KAAKP,SAAS;oBAC9BA,QAAQO;gBACZ;YACJ;YAEAD;QACJ;IACJ,GAAG;QAACJ;QAAkCE;QAA+BL;QAAMC;KAAQ;IAEnF,MAAMQ,gDAAgDf,MAAMA,CAAC;IAE7DD,SAASA,CAAC;QACN,IAAIW,gCAAgC;YAChC,0FAA0F;YAC1F,+HAA+H;YAC/H,+HAA+H;YAC/H,iHAAiH;YACjH,wBAAwB;YACxB,IAAIK,8CAA8C,OAAO,EAAE;gBACvDA,8CAA8C,OAAO,GAAG;gBACxD;YACJ;YAEA,MAAMC,SAAS;gBACX,MAAMF,SAAS,MAAMF,4BAA4BN;gBAEjD,IAAIQ,OAAO,MAAM,GAAG,KAAKP,SAAS;oBAC9BA,QAAQO;gBACZ;YACJ;YAEAE;QACJ;IACJ,GAAG;QACCN;QACAE;QACAN;QACAC;QACA,uFAAuF;QACvF,wEAAwE;QACxEC,QAAQ,cAAc,CAAC,KAAK,CAAC,qBAAqB;KACrD;AACL"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@squide/firefly",
3
3
  "author": "Workleap",
4
- "version": "16.1.12",
4
+ "version": "16.2.1",
5
5
  "description": "Squide bundle for the firefly technology stack.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -49,10 +49,10 @@
49
49
  "@workleap-telemetry/core": "^2.0.0",
50
50
  "@workleap/logging": "^1.3.6",
51
51
  "uuid": "^13.0.0",
52
- "@squide/core": "^6.1.14",
53
52
  "@squide/env-vars": "^1.4.19",
54
53
  "@squide/launch-darkly": "^1.0.10",
55
54
  "@squide/msw": "^4.0.17",
55
+ "@squide/core": "^6.1.14",
56
56
  "@squide/react-router": "^8.1.17"
57
57
  },
58
58
  "devDependencies": {
@@ -63,13 +63,13 @@
63
63
  "@types/react": "19.2.14",
64
64
  "@types/react-dom": "19.2.3",
65
65
  "@typescript-eslint/parser": "8.56.1",
66
- "@typescript/native-preview": "7.0.0-dev.20260224.1",
66
+ "@typescript/native-preview": "7.0.0-dev.20260303.1",
67
67
  "@vitejs/plugin-react": "5.1.4",
68
68
  "@workleap/eslint-configs": "1.1.13",
69
69
  "@workleap/rslib-configs": "1.1.7",
70
70
  "@workleap/typescript-configs": "3.0.7",
71
71
  "eslint": "9.39.2",
72
- "happy-dom": "20.7.0",
72
+ "happy-dom": "20.8.3",
73
73
  "typescript": "5.9.3",
74
74
  "typescript-eslint": "8.54.0",
75
75
  "vitest": "4.0.18"
package/src/AppRouter.tsx CHANGED
@@ -1,9 +1,11 @@
1
- import { useLogger } from "@squide/core";
1
+ import { useLogger, useRuntime } from "@squide/core";
2
2
  import { useRoutes, type Route } from "@squide/react-router";
3
3
  import { useEffect, useMemo, type ReactElement } from "react";
4
+ import { DataStrategyFunction, DataStrategyFunctionArgs, DataStrategyResult, DOMRouterOpts } from "react-router";
4
5
  import type { RouterProviderProps } from "react-router/dom";
5
6
  import { AppRouterDispatcherContext, AppRouterStateContext } from "./AppRouterContext.ts";
6
7
  import { useAppRouterReducer, type AppRouterState } from "./AppRouterReducer.ts";
8
+ import { FireflyRuntime } from "./FireflyRuntime.tsx";
7
9
  import { RootRoute } from "./RootRoute.tsx";
8
10
  import { useStrictRegistrationMode } from "./useStrictRegistrationMode.ts";
9
11
 
@@ -14,6 +16,7 @@ export interface AppRouterRenderFunctionArgs {
14
16
  export interface RenderRouterProviderFunctionArgs {
15
17
  rootRoute: ReactElement;
16
18
  registeredRoutes: Route[];
19
+ routerProps: DOMRouterOpts;
17
20
  routerProviderProps: Omit<RouterProviderProps, "router">;
18
21
  }
19
22
 
@@ -27,7 +30,40 @@ export function useCanRenderRouter({ areModulesRegistered, areModulesReady: areM
27
30
  );
28
31
  }
29
32
 
33
+ // This is a custom React Router data strategy (https://reactrouter.com/api/data-routers/createMemoryRouter#optsdatastrategy)
34
+ // to delay the execution of React Router data browser loaders until MSW is ready.
35
+ // The data strategy implemention is copied from React Router default data strategy: https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/router.ts#L5710.
36
+ export function createWaitForMswDataStrategy(runtime: FireflyRuntime) {
37
+ const strategy: (args: DataStrategyFunctionArgs<unknown>) => ReturnType<DataStrategyFunction<unknown>> = async args => {
38
+ await new Promise(resolve => {
39
+ if (runtime.mswState.isReady) {
40
+ resolve(null);
41
+ } else {
42
+ const handler = () => {
43
+ runtime.mswState.removeMswReadyListener(handler);
44
+ resolve(null);
45
+ };
46
+
47
+ runtime.mswState.addMswReadyListener(handler);
48
+ }
49
+ });
50
+
51
+ const matchesToLoad = args.matches.filter(m => m.shouldCallHandler);
52
+ const keyedResults: Record<string, DataStrategyResult> = {};
53
+ const results = await Promise.all(matchesToLoad.map(m => m.resolve()));
54
+
55
+ results.forEach((result, i) => {
56
+ keyedResults[matchesToLoad[i].route.id] = result;
57
+ });
58
+
59
+ return keyedResults;
60
+ };
61
+
62
+ return strategy;
63
+ }
64
+
30
65
  function useRenderRouterProvider(state: AppRouterState, renderRouterProvider: RenderRouterProviderFunction, strictMode: boolean) {
66
+ const runtime = useRuntime() as FireflyRuntime;
31
67
  const routes = useRoutes();
32
68
 
33
69
  // The value is computed outside of the router provider memo to prevent
@@ -39,12 +75,15 @@ function useRenderRouterProvider(state: AppRouterState, renderRouterProvider: Re
39
75
  return renderRouterProvider({
40
76
  rootRoute: <RootRoute strictMode={strictMode} />,
41
77
  registeredRoutes: routes,
78
+ routerProps: {
79
+ dataStrategy: runtime.isMswEnabled ? createWaitForMswDataStrategy(runtime) : undefined
80
+ },
42
81
  routerProviderProps: {}
43
82
  });
44
83
  }
45
84
 
46
85
  return null;
47
- }, [canRenderRouter, routes, renderRouterProvider, strictMode]);
86
+ }, [runtime, canRenderRouter, routes, renderRouterProvider, strictMode]);
48
87
  }
49
88
 
50
89
  export interface AppRouterProps {
@@ -2,24 +2,26 @@ import { useAppRouterState } from "./AppRouterContext.ts";
2
2
 
3
3
  export function useCanUpdateDeferredRegistrations() {
4
4
  const {
5
- areModulesReady,
6
- publicDataUpdatedAt,
7
- protectedDataUpdatedAt,
8
- featureFlagsUpdatedAt,
9
- deferredRegistrationsUpdatedAt
5
+ areModulesReady
6
+ // publicDataUpdatedAt,
7
+ // protectedDataUpdatedAt,
8
+ // featureFlagsUpdatedAt,
9
+ // deferredRegistrationsUpdatedAt
10
10
  } = useAppRouterState();
11
11
 
12
- return (
13
- // Do not trigger an update if the deferred registrations has not been registered yet (if there are deferred registrations, once they are
14
- // registered, the modules will be marked as ready).
15
- areModulesReady
16
- // Make sure the apps is actually having deferred registrations.
17
- && deferredRegistrationsUpdatedAt
18
- // If either the public data or the protected data has been updated, update the deferred registrations.
19
- && (
20
- (publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
21
- (protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
22
- (featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt)
23
- )
24
- );
12
+ return areModulesReady;
13
+
14
+ // return !!(
15
+ // // Do not trigger an update if the deferred registrations has not been registered yet (if there are deferred registrations, once they are
16
+ // // registered, the modules will be marked as ready).
17
+ // areModulesReady
18
+ // // Make sure the apps is actually having deferred registrations.
19
+ // // && deferredRegistrationsUpdatedAt
20
+ // // // If either the public data or the protected data has been updated, update the deferred registrations.
21
+ // // && (
22
+ // // (publicDataUpdatedAt && publicDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
23
+ // // (protectedDataUpdatedAt && protectedDataUpdatedAt > deferredRegistrationsUpdatedAt) ||
24
+ // // (featureFlagsUpdatedAt && featureFlagsUpdatedAt > deferredRegistrationsUpdatedAt)
25
+ // // )
26
+ // );
25
27
  }
@@ -1,5 +1,5 @@
1
1
  import { useRuntime, type ModuleRegistrationError } from "@squide/core";
2
- import { useEffect } from "react";
2
+ import { useEffect, useRef } from "react";
3
3
  import { FireflyRuntime } from "./FireflyRuntime.tsx";
4
4
  import { useCanRegisterDeferredRegistrations } from "./useCanRegisterDeferredRegistrations.ts";
5
5
  import { useCanUpdateDeferredRegistrations } from "./useCanUpdateDeferredRegistrations.ts";
@@ -14,6 +14,7 @@ export interface UseDeferredRegistrationsOptions {
14
14
 
15
15
  export function useDeferredRegistrations(data?: unknown, { onError }: UseDeferredRegistrationsOptions = {}) {
16
16
  const runtime = useRuntime() as FireflyRuntime;
17
+ // const isExecutedBecauseModulesAreNowReadyRef = useRef(true);
17
18
 
18
19
  const canRegisterDeferredRegistrations = useCanRegisterDeferredRegistrations();
19
20
  const canUpdateDeferredRegistrations = useCanUpdateDeferredRegistrations();
@@ -35,8 +36,20 @@ export function useDeferredRegistrations(data?: unknown, { onError }: UseDeferre
35
36
  }
36
37
  }, [canRegisterDeferredRegistrations, registerDeferredRegistrations, data, onError]);
37
38
 
39
+ const isInitialUpdateDeferredRegistrationsExecution = useRef(true);
40
+
38
41
  useEffect(() => {
39
42
  if (canUpdateDeferredRegistrations) {
43
+ // HACK: Skipping the first execution successfully passing the gate because this is due to
44
+ // the modules being ready, and it's most certainly the same data that has been forwarded earlier to the deferred registration.
45
+ // Ideally, instead of this hacky ref, it would be a ref tracking the previous data object, and the deferred registration would
46
+ // only be updated if the current data object != than the previous data object. Sadly, it is not possible because
47
+ // of the feature flags.
48
+ if (isInitialUpdateDeferredRegistrationsExecution.current) {
49
+ isInitialUpdateDeferredRegistrationsExecution.current = false;
50
+ return;
51
+ }
52
+
40
53
  const update = async () => {
41
54
  const errors = await updateDeferredRegistrations(data);
42
55