@squide/firefly 9.2.1 → 9.3.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/AppRouter.js +5 -3
  3. package/dist/AppRouterReducer.d.ts +14 -3
  4. package/dist/AppRouterReducer.js +4 -1
  5. package/dist/FireflyRuntime.js +5 -2
  6. package/dist/RootRoute.js +1 -1
  7. package/dist/boostrap.d.ts +20 -0
  8. package/dist/boostrap.js +1 -0
  9. package/dist/{chunk-PU7MASPN.js → chunk-4RUCDAUT.js} +2 -2
  10. package/dist/{chunk-2E76JVV7.js → chunk-BFHHJOJT.js} +1 -1
  11. package/dist/{chunk-FKQ7XQEU.js → chunk-CFNKNPS3.js} +1 -1
  12. package/dist/{chunk-VUMBZ5BP.js → chunk-CTLPFYLM.js} +32 -13
  13. package/dist/{chunk-I6L3AYOB.js → chunk-H2ILEMPE.js} +8 -4
  14. package/dist/chunk-IGJHKH2A.js +48 -0
  15. package/dist/chunk-JFMSLZ74.js +253 -0
  16. package/dist/{chunk-36U4TTNR.js → chunk-L44KFU57.js} +2 -2
  17. package/dist/{chunk-7R2Z7FXF.js → chunk-MKTGJHQR.js} +38 -22
  18. package/dist/{chunk-MZG2PJJG.js → chunk-PMVN3U47.js} +2 -0
  19. package/dist/chunk-TURKCH7J.js +20 -0
  20. package/dist/{chunk-L5BP3WP3.js → chunk-XDWYPVAJ.js} +2 -2
  21. package/dist/index.d.ts +5 -4
  22. package/dist/index.js +13 -11
  23. package/dist/useCanFetchProtectedData.js +1 -1
  24. package/dist/useCanRegisterDeferredRegistrations.js +1 -1
  25. package/dist/useDeferredRegistrations.js +2 -2
  26. package/dist/useExecuteOnce.d.ts +3 -0
  27. package/dist/useExecuteOnce.js +1 -0
  28. package/dist/useIsBootstrapping.d.ts +5 -1
  29. package/dist/useIsBootstrapping.js +1 -1
  30. package/dist/useProtectedDataQueries.d.ts +3 -1
  31. package/dist/useProtectedDataQueries.js +3 -2
  32. package/dist/usePublicDataQueries.d.ts +3 -1
  33. package/dist/usePublicDataQueries.js +2 -1
  34. package/dist/useRegisterDeferredRegistrations.d.ts +2 -1
  35. package/dist/useUpdateDeferredRegistrations.d.ts +2 -1
  36. package/package.json +6 -6
  37. package/dist/chunk-ENUCXEMN.js +0 -180
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @squide/firefly
2
2
 
3
+ ## 9.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#219](https://github.com/gsoft-inc/wl-squide/pull/219) [`25cb482`](https://github.com/gsoft-inc/wl-squide/commit/25cb482779ee280f3f7109de4607b92dcfeef7f3) Thanks [@patricklafrance](https://github.com/patricklafrance)! - Now dispatching events to enable instrumentation packages for observability platforms.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`25cb482`](https://github.com/gsoft-inc/wl-squide/commit/25cb482779ee280f3f7109de4607b92dcfeef7f3)]:
12
+ - @squide/module-federation@6.2.0
13
+ - @squide/react-router@6.4.0
14
+ - @squide/core@5.4.0
15
+ - @squide/msw@3.2.0
16
+
3
17
  ## 9.2.1
4
18
 
5
19
  ### Patch Changes
package/dist/AppRouter.js CHANGED
@@ -1,6 +1,8 @@
1
- export { AppRouter } from './chunk-36U4TTNR.js';
1
+ export { AppRouter } from './chunk-L44KFU57.js';
2
2
  import './chunk-WOPD33CM.js';
3
- import './chunk-ENUCXEMN.js';
4
- import './chunk-MZG2PJJG.js';
3
+ import './chunk-JFMSLZ74.js';
4
+ import './chunk-TURKCH7J.js';
5
+ import './chunk-H2ILEMPE.js';
6
+ import './chunk-PMVN3U47.js';
5
7
  import './chunk-PP3MRMJJ.js';
6
8
  import './chunk-G32YX2KR.js';
@@ -1,5 +1,6 @@
1
1
  import { Dispatch } from 'react';
2
2
 
3
+ type ActiveRouteVisiblity = "unknown" | "public" | "protected";
3
4
  interface AppRouterState {
4
5
  waitForMsw: boolean;
5
6
  waitForPublicData: boolean;
@@ -12,10 +13,19 @@ interface AppRouterState {
12
13
  publicDataUpdatedAt?: number;
13
14
  protectedDataUpdatedAt?: number;
14
15
  deferredRegistrationsUpdatedAt?: number;
15
- isActiveRouteProtected: boolean;
16
+ activeRouteVisibility: ActiveRouteVisiblity;
16
17
  isUnauthorized: boolean;
17
18
  }
18
- type AppRouterActionType = "modules-registered" | "modules-ready" | "msw-ready" | "public-data-ready" | "protected-data-ready" | "public-data-updated" | "protected-data-updated" | "deferred-registrations-updated" | "active-route-is-protected" | "is-unauthorized";
19
+ type AppRouterActionType = "modules-registered" | "modules-ready" | "msw-ready" | "public-data-ready" | "protected-data-ready" | "public-data-updated" | "protected-data-updated" | "deferred-registrations-updated" | "active-route-is-public" | "active-route-is-protected" | "is-unauthorized";
20
+ declare const ModulesRegisteredEvent = "squide-modules-registered";
21
+ declare const ModulesReadyEvent = "squide-modules-ready";
22
+ declare const MswReadyEvent = "squide-msw-ready";
23
+ declare const PublicDataReadyEvent = "squide-public-data-ready";
24
+ declare const ProtectedDataReadyEvent = "squide-protected-data-ready";
25
+ declare const PublicDataUpdatedEvent = "squide-public-data-updated";
26
+ declare const ProtectedDataUpdatedEvent = "squide-protected-data-updated";
27
+ declare const DeferredRegistrationsUpdatedEvent = "squide-deferred-registrations-updated";
28
+ declare const ApplicationBoostrappedEvent = "squide-app-boostrapped";
19
29
  interface AppRouterAction {
20
30
  type: AppRouterActionType;
21
31
  }
@@ -24,8 +34,9 @@ declare function getAreModulesRegistered(): boolean;
24
34
  declare function getAreModulesReady(): boolean;
25
35
  declare function useModuleRegistrationStatusDispatcher(areModulesRegisteredValue: boolean, areModulesReadyValue: boolean, dispatch: AppRouterDispatch): void;
26
36
  declare function useMswStatusDispatcher(isMswReadyValue: boolean, dispatch: AppRouterDispatch): void;
37
+ declare function useBootstrappingCompletedDispatcher(state: AppRouterState): void;
27
38
  declare function __setAppReducerDispatchProxyFactory(factory: (reactDispatch: AppRouterDispatch) => AppRouterDispatch): void;
28
39
  declare function __clearAppReducerDispatchProxy(): void;
29
40
  declare function useAppRouterReducer(waitForMsw: boolean, waitForPublicData: boolean, waitForProtectedData: boolean): [AppRouterState, AppRouterDispatch];
30
41
 
31
- export { type AppRouterAction, type AppRouterActionType, type AppRouterDispatch, type AppRouterState, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher };
42
+ export { type ActiveRouteVisiblity, type AppRouterAction, type AppRouterActionType, type AppRouterDispatch, type AppRouterState, ApplicationBoostrappedEvent, DeferredRegistrationsUpdatedEvent, ModulesReadyEvent, ModulesRegisteredEvent, MswReadyEvent, ProtectedDataReadyEvent, ProtectedDataUpdatedEvent, PublicDataReadyEvent, PublicDataUpdatedEvent, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useBootstrappingCompletedDispatcher, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher };
@@ -1 +1,4 @@
1
- export { __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher } from './chunk-ENUCXEMN.js';
1
+ export { ApplicationBoostrappedEvent, DeferredRegistrationsUpdatedEvent, ModulesReadyEvent, ModulesRegisteredEvent, MswReadyEvent, ProtectedDataReadyEvent, ProtectedDataUpdatedEvent, PublicDataReadyEvent, PublicDataUpdatedEvent, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useBootstrappingCompletedDispatcher, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher } from './chunk-JFMSLZ74.js';
2
+ import './chunk-TURKCH7J.js';
3
+ import './chunk-H2ILEMPE.js';
4
+ import './chunk-G32YX2KR.js';
@@ -1,2 +1,5 @@
1
- export { FireflyRuntime } from './chunk-FKQ7XQEU.js';
2
- import './chunk-ENUCXEMN.js';
1
+ export { FireflyRuntime } from './chunk-CFNKNPS3.js';
2
+ import './chunk-JFMSLZ74.js';
3
+ import './chunk-TURKCH7J.js';
4
+ import './chunk-H2ILEMPE.js';
5
+ import './chunk-G32YX2KR.js';
package/dist/RootRoute.js CHANGED
@@ -1,3 +1,3 @@
1
- export { RootRoute } from './chunk-MZG2PJJG.js';
1
+ export { RootRoute } from './chunk-PMVN3U47.js';
2
2
  import './chunk-PP3MRMJJ.js';
3
3
  import './chunk-G32YX2KR.js';
@@ -0,0 +1,20 @@
1
+ import { RegisterModulesOptions, ModuleRegisterFunction, ModuleRegistrationError } from '@squide/core';
2
+ import { RemoteDefinition, RemoteModuleRegistrationError } from '@squide/module-federation';
3
+ import { FireflyRuntime } from './FireflyRuntime.js';
4
+ import '@squide/react-router';
5
+ import 'msw';
6
+
7
+ declare const ApplicationBootstrappingStartedEvent = "squide-app-bootstrapping-started";
8
+ type StartMswFunction<TRuntime = FireflyRuntime> = (runtime: TRuntime) => Promise<void>;
9
+ interface BootstrapAppOptions<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown> extends RegisterModulesOptions<TContext> {
10
+ localModules?: ModuleRegisterFunction<TRuntime, TContext, TData>[];
11
+ remotes?: RemoteDefinition[];
12
+ startMsw?: StartMswFunction<TRuntime>;
13
+ }
14
+ declare function bootstrap<TRuntime extends FireflyRuntime = FireflyRuntime, TContext = unknown, TData = unknown>(runtime: TRuntime, options?: BootstrapAppOptions<TRuntime, TContext, TData>): Promise<{
15
+ localModuleErrors: ModuleRegistrationError[];
16
+ remoteModuleErrors: RemoteModuleRegistrationError[];
17
+ }>;
18
+ declare function __resetBootstrapGuard(): void;
19
+
20
+ export { ApplicationBootstrappingStartedEvent, type BootstrapAppOptions, type StartMswFunction, __resetBootstrapGuard, bootstrap };
@@ -0,0 +1 @@
1
+ export { ApplicationBootstrappingStartedEvent, __resetBootstrapGuard, bootstrap } from './chunk-IGJHKH2A.js';
@@ -9,10 +9,10 @@ function useCanRegisterDeferredRegistrations() {
9
9
  areModulesRegistered,
10
10
  isPublicDataReady,
11
11
  isProtectedDataReady,
12
- isActiveRouteProtected,
12
+ activeRouteVisibility,
13
13
  isUnauthorized
14
14
  } = useAppRouterState();
15
- return !isUnauthorized && areModulesRegistered && !areModulesReady && (!waitForPublicData || isPublicDataReady) && (!waitForProtectedData || !isActiveRouteProtected || isProtectedDataReady);
15
+ return !isUnauthorized && areModulesRegistered && !areModulesReady && (!waitForPublicData || isPublicDataReady) && (!waitForProtectedData || activeRouteVisibility === "public" || isProtectedDataReady);
16
16
  }
17
17
 
18
18
  export { useCanRegisterDeferredRegistrations };
@@ -1,6 +1,6 @@
1
1
  import { useRegisterDeferredRegistrations } from './chunk-YRWFYWK4.js';
2
2
  import { useUpdateDeferredRegistrations } from './chunk-N2GOIQ5E.js';
3
- import { useCanRegisterDeferredRegistrations } from './chunk-PU7MASPN.js';
3
+ import { useCanRegisterDeferredRegistrations } from './chunk-4RUCDAUT.js';
4
4
  import { useCanUpdateDeferredRegistrations } from './chunk-WVRMJZV6.js';
5
5
  import { useRuntime } from '@squide/core';
6
6
  import { useEffect } from 'react';
@@ -1,4 +1,4 @@
1
- import { getAreModulesRegistered } from './chunk-ENUCXEMN.js';
1
+ import { getAreModulesRegistered } from './chunk-JFMSLZ74.js';
2
2
  import { MswPlugin } from '@squide/msw';
3
3
  import { ReactRouterRuntime } from '@squide/react-router';
4
4
 
@@ -1,21 +1,27 @@
1
1
  import { useCanFetchPublicData } from './chunk-IOMSOUAL.js';
2
+ import { useExecuteOnce } from './chunk-TURKCH7J.js';
2
3
  import { GlobalDataQueriesError } from './chunk-HE5HKFL3.js';
3
4
  import { useAppRouterDispatcher } from './chunk-G32YX2KR.js';
5
+ import { useEventBus } from '@squide/core';
4
6
  import { useQueries } from '@tanstack/react-query';
5
- import { useCallback, useEffect, useRef } from 'react';
7
+ import { useCallback, useRef, useEffect } from 'react';
6
8
 
9
+ var PublicDataFetchStartedEvent = "squide-public-data-fetch-started";
10
+ var PublicDataFetchFailedEvent = "squide-public-data-fetch-failed";
7
11
  function usePublicDataQueries(queries) {
8
12
  const canFetchPublicData = useCanFetchPublicData();
13
+ const eventBus = useEventBus();
9
14
  const dispatch = useAppRouterDispatcher();
10
15
  const combineResults = useCallback((results) => {
11
16
  const errors = results.filter((x) => x.error).map((x) => x.error);
17
+ const hasErrors2 = errors.length > 0;
12
18
  return {
13
19
  data: results.map((x) => x.data),
14
20
  errors,
15
- hasErrors: errors.length > 0,
16
- isReady: results.length === queries.length && results.every((x) => x.data)
21
+ hasErrors: hasErrors2,
22
+ isReady: !hasErrors2 && !results.some((x) => x.isPending)
17
23
  };
18
- }, [queries.length]);
24
+ }, []);
19
25
  const { data, errors: queriesErrors, hasErrors, isReady } = useQueries({
20
26
  queries: queries.map((x) => ({
21
27
  enabled: canFetchPublicData,
@@ -23,24 +29,37 @@ function usePublicDataQueries(queries) {
23
29
  })),
24
30
  combine: combineResults
25
31
  });
26
- useEffect(() => {
27
- if (hasErrors) {
28
- throw new GlobalDataQueriesError("[squide] Global public data queries failed.", queriesErrors);
32
+ useExecuteOnce(useCallback(() => {
33
+ if (canFetchPublicData) {
34
+ eventBus.dispatch(PublicDataFetchStartedEvent);
35
+ return true;
29
36
  }
30
- }, [hasErrors, queriesErrors]);
37
+ return false;
38
+ }, [canFetchPublicData, eventBus]), true);
31
39
  const isReadyRef = useRef(false);
40
+ const dispatchReady = useExecuteOnce(useCallback(() => {
41
+ if (isReady) {
42
+ isReadyRef.current = true;
43
+ dispatch({ type: "public-data-ready" });
44
+ return true;
45
+ }
46
+ return false;
47
+ }, [isReady, dispatch]));
48
+ useEffect(() => {
49
+ dispatchReady();
50
+ }, [dispatchReady]);
32
51
  useEffect(() => {
33
52
  if (isReadyRef.current && data) {
34
53
  dispatch({ type: "public-data-updated" });
35
54
  }
36
55
  }, [data, dispatch]);
37
56
  useEffect(() => {
38
- if (isReady) {
39
- isReadyRef.current = true;
40
- dispatch({ type: "public-data-ready" });
57
+ if (hasErrors) {
58
+ eventBus.dispatch(PublicDataFetchFailedEvent, queriesErrors);
59
+ throw new GlobalDataQueriesError("[squide] Global public data queries failed.", queriesErrors);
41
60
  }
42
- }, [isReady, dispatch]);
61
+ }, [hasErrors, queriesErrors, eventBus]);
43
62
  return data;
44
63
  }
45
64
 
46
- export { usePublicDataQueries };
65
+ export { PublicDataFetchFailedEvent, PublicDataFetchStartedEvent, usePublicDataQueries };
@@ -2,6 +2,10 @@ import { useAppRouterState } from './chunk-G32YX2KR.js';
2
2
 
3
3
  // src/useIsBootstrapping.ts
4
4
  function useIsBootstrapping() {
5
+ const state = useAppRouterState();
6
+ return isApplicationBootstrapping(state);
7
+ }
8
+ function isApplicationBootstrapping(state) {
5
9
  const {
6
10
  waitForMsw,
7
11
  waitForPublicData,
@@ -10,10 +14,10 @@ function useIsBootstrapping() {
10
14
  isMswReady,
11
15
  isPublicDataReady,
12
16
  isProtectedDataReady,
13
- isActiveRouteProtected,
17
+ activeRouteVisibility,
14
18
  isUnauthorized
15
- } = useAppRouterState();
16
- const isAppReady = !isUnauthorized && areModulesReady && (!waitForMsw || isMswReady) && (!waitForPublicData || isPublicDataReady) && (!waitForProtectedData || !isActiveRouteProtected || isProtectedDataReady);
19
+ } = state;
20
+ const isAppReady = !isUnauthorized && areModulesReady && (!waitForMsw || isMswReady) && (!waitForPublicData || isPublicDataReady) && (!waitForProtectedData || activeRouteVisibility === "public" || isProtectedDataReady);
17
21
  const flush = (
18
22
  // Only applicable when there's a unauthorized request while fetching the initial data.
19
23
  isUnauthorized && (!waitForMsw || isMswReady) && (!waitForPublicData || isPublicDataReady)
@@ -21,4 +25,4 @@ function useIsBootstrapping() {
21
25
  return !isAppReady && !flush;
22
26
  }
23
27
 
24
- export { useIsBootstrapping };
28
+ export { isApplicationBootstrapping, useIsBootstrapping };
@@ -0,0 +1,48 @@
1
+ import { registerLocalModules, isFunction } from '@squide/core';
2
+ import { registerRemoteModules } from '@squide/module-federation';
3
+ import { setMswAsReady } from '@squide/msw';
4
+
5
+ // src/boostrap.ts
6
+ var ApplicationBootstrappingStartedEvent = "squide-app-bootstrapping-started";
7
+ var isBootstrapped = false;
8
+ async function bootstrap(runtime, options = {}) {
9
+ const {
10
+ localModules,
11
+ remotes,
12
+ context,
13
+ startMsw
14
+ } = options;
15
+ if (isBootstrapped) {
16
+ throw new Error('[squide] A squide application can only be bootstrapped once. Did you call the "bootstrap" function twice?');
17
+ }
18
+ runtime.eventBus.dispatch(ApplicationBootstrappingStartedEvent);
19
+ let localModuleErrors = [];
20
+ let remoteModuleErrors = [];
21
+ if (localModules) {
22
+ localModuleErrors = await registerLocalModules(localModules, runtime, { context });
23
+ }
24
+ if (remotes) {
25
+ remoteModuleErrors = await registerRemoteModules(remotes, runtime, { context });
26
+ }
27
+ if (runtime.isMswEnabled) {
28
+ if (!isFunction(startMsw)) {
29
+ throw new Error('[squide] When MSW is enabled, the "startMsw" function must be provided.');
30
+ }
31
+ try {
32
+ await startMsw(runtime);
33
+ setMswAsReady();
34
+ } catch (error) {
35
+ runtime.logger.debug("[squide] An error occured while starting MSW.", error);
36
+ }
37
+ }
38
+ isBootstrapped = true;
39
+ return {
40
+ localModuleErrors,
41
+ remoteModuleErrors
42
+ };
43
+ }
44
+ function __resetBootstrapGuard() {
45
+ isBootstrapped = false;
46
+ }
47
+
48
+ export { ApplicationBootstrappingStartedEvent, __resetBootstrapGuard, bootstrap };
@@ -0,0 +1,253 @@
1
+ import { useExecuteOnce } from './chunk-TURKCH7J.js';
2
+ import { isApplicationBootstrapping } from './chunk-H2ILEMPE.js';
3
+ import { getLocalModuleRegistrationStatus, useLogger, addLocalModuleRegistrationStatusChangedListener, removeLocalModuleRegistrationStatusChangedListener, useEventBus } from '@squide/core';
4
+ import { getRemoteModuleRegistrationStatus, areModulesRegistered, areModulesReady, addRemoteModuleRegistrationStatusChangedListener, removeRemoteModuleRegistrationStatusChangedListener } from '@squide/module-federation';
5
+ import { isMswReady, addMswStateChangedListener, removeMswStateChangedListener } from '@squide/msw';
6
+ import { useCallback, useEffect, useReducer, useMemo } from 'react';
7
+
8
+ var ModulesRegisteredEvent = "squide-modules-registered";
9
+ var ModulesReadyEvent = "squide-modules-ready";
10
+ var MswReadyEvent = "squide-msw-ready";
11
+ var PublicDataReadyEvent = "squide-public-data-ready";
12
+ var ProtectedDataReadyEvent = "squide-protected-data-ready";
13
+ var PublicDataUpdatedEvent = "squide-public-data-updated";
14
+ var ProtectedDataUpdatedEvent = "squide-protected-data-updated";
15
+ var DeferredRegistrationsUpdatedEvent = "squide-deferred-registrations-updated";
16
+ var ApplicationBoostrappedEvent = "squide-app-boostrapped";
17
+ function reducer(state, action) {
18
+ let newState = state;
19
+ switch (action.type) {
20
+ case "modules-registered": {
21
+ newState = {
22
+ ...newState,
23
+ areModulesRegistered: true
24
+ };
25
+ break;
26
+ }
27
+ case "modules-ready": {
28
+ newState = {
29
+ ...newState,
30
+ areModulesReady: true,
31
+ // Will be set even if the app is not using deferred registrations.
32
+ deferredRegistrationsUpdatedAt: Date.now()
33
+ };
34
+ break;
35
+ }
36
+ case "msw-ready": {
37
+ newState = {
38
+ ...newState,
39
+ isMswReady: true
40
+ };
41
+ break;
42
+ }
43
+ case "public-data-ready": {
44
+ newState = {
45
+ ...newState,
46
+ isPublicDataReady: true,
47
+ publicDataUpdatedAt: Date.now()
48
+ };
49
+ break;
50
+ }
51
+ case "protected-data-ready": {
52
+ newState = {
53
+ ...newState,
54
+ isProtectedDataReady: true,
55
+ protectedDataUpdatedAt: Date.now()
56
+ };
57
+ break;
58
+ }
59
+ case "public-data-updated": {
60
+ newState = {
61
+ ...newState,
62
+ publicDataUpdatedAt: Date.now()
63
+ };
64
+ break;
65
+ }
66
+ case "protected-data-updated": {
67
+ newState = {
68
+ ...newState,
69
+ protectedDataUpdatedAt: Date.now()
70
+ };
71
+ break;
72
+ }
73
+ case "deferred-registrations-updated": {
74
+ newState = {
75
+ ...newState,
76
+ deferredRegistrationsUpdatedAt: Date.now()
77
+ };
78
+ break;
79
+ }
80
+ case "active-route-is-public": {
81
+ newState = {
82
+ ...newState,
83
+ activeRouteVisibility: "public"
84
+ };
85
+ break;
86
+ }
87
+ case "active-route-is-protected": {
88
+ newState = {
89
+ ...newState,
90
+ activeRouteVisibility: "protected"
91
+ };
92
+ break;
93
+ }
94
+ case "is-unauthorized": {
95
+ newState = {
96
+ ...newState,
97
+ isUnauthorized: true
98
+ };
99
+ break;
100
+ }
101
+ default: {
102
+ throw new Error(`[squide] The AppRouter component state reducer doesn't support action type "${action.type}".`);
103
+ }
104
+ }
105
+ return newState;
106
+ }
107
+ function getAreModulesRegistered() {
108
+ const localModuleStatus = getLocalModuleRegistrationStatus();
109
+ const remoteModuleStatus = getRemoteModuleRegistrationStatus();
110
+ return areModulesRegistered(localModuleStatus, remoteModuleStatus);
111
+ }
112
+ function getAreModulesReady() {
113
+ const localModuleStatus = getLocalModuleRegistrationStatus();
114
+ const remoteModuleStatus = getRemoteModuleRegistrationStatus();
115
+ return areModulesReady(localModuleStatus, remoteModuleStatus);
116
+ }
117
+ function useModuleRegistrationStatusDispatcher(areModulesRegisteredValue, areModulesReadyValue, dispatch) {
118
+ const logger = useLogger();
119
+ const dispatchModulesRegistered = useExecuteOnce(useCallback(() => {
120
+ if (getAreModulesRegistered()) {
121
+ dispatch({ type: "modules-registered" });
122
+ logger.debug("[squide] %cModules are registered%c.", "color: white; background-color: green;", "");
123
+ return true;
124
+ }
125
+ return false;
126
+ }, [dispatch, logger]));
127
+ const dispatchModulesReady = useExecuteOnce(useCallback(() => {
128
+ if (getAreModulesReady()) {
129
+ dispatch({ type: "modules-ready" });
130
+ logger.debug("[squide] %cModules are ready%c.", "color: white; background-color: green;", "");
131
+ return true;
132
+ }
133
+ return false;
134
+ }, [dispatch, logger]));
135
+ return useEffect(() => {
136
+ if (!areModulesRegisteredValue) {
137
+ addLocalModuleRegistrationStatusChangedListener(dispatchModulesRegistered);
138
+ addRemoteModuleRegistrationStatusChangedListener(dispatchModulesRegistered);
139
+ }
140
+ if (!areModulesReadyValue) {
141
+ addLocalModuleRegistrationStatusChangedListener(dispatchModulesReady);
142
+ addRemoteModuleRegistrationStatusChangedListener(dispatchModulesReady);
143
+ }
144
+ return () => {
145
+ removeLocalModuleRegistrationStatusChangedListener(dispatchModulesRegistered);
146
+ removeRemoteModuleRegistrationStatusChangedListener(dispatchModulesRegistered);
147
+ removeLocalModuleRegistrationStatusChangedListener(dispatchModulesReady);
148
+ removeRemoteModuleRegistrationStatusChangedListener(dispatchModulesReady);
149
+ };
150
+ }, [areModulesRegisteredValue, areModulesReadyValue, dispatchModulesRegistered, dispatchModulesReady]);
151
+ }
152
+ function useMswStatusDispatcher(isMswReadyValue, dispatch) {
153
+ const logger = useLogger();
154
+ const dispatchMswReady = useExecuteOnce(useCallback(() => {
155
+ if (isMswReady()) {
156
+ dispatch({ type: "msw-ready" });
157
+ logger.debug("[squide] %cMSW is ready%c.", "color: white; background-color: green;", "");
158
+ return true;
159
+ }
160
+ return false;
161
+ }, [dispatch, logger]));
162
+ useEffect(() => {
163
+ if (!isMswReadyValue) {
164
+ addMswStateChangedListener(dispatchMswReady);
165
+ }
166
+ return () => {
167
+ removeMswStateChangedListener(dispatchMswReady);
168
+ };
169
+ }, [isMswReadyValue, dispatchMswReady]);
170
+ }
171
+ function useBootstrappingCompletedDispatcher(state) {
172
+ const eventBus = useEventBus();
173
+ const areModulesRegisteredValue = state.areModulesRegistered;
174
+ const isBoostrapping = isApplicationBootstrapping(state);
175
+ useExecuteOnce(useCallback(() => {
176
+ if (areModulesRegisteredValue && !isBoostrapping) {
177
+ eventBus.dispatch(ApplicationBoostrappedEvent);
178
+ return true;
179
+ }
180
+ return false;
181
+ }, [areModulesRegisteredValue, isBoostrapping, eventBus]), true);
182
+ }
183
+ var dispatchProxyFactory;
184
+ function __setAppReducerDispatchProxyFactory(factory) {
185
+ dispatchProxyFactory = factory;
186
+ }
187
+ function __clearAppReducerDispatchProxy() {
188
+ dispatchProxyFactory = void 0;
189
+ }
190
+ function useReducerDispatchProxy(reactDispatch) {
191
+ return useMemo(() => {
192
+ return dispatchProxyFactory ? dispatchProxyFactory(reactDispatch) : reactDispatch;
193
+ }, [reactDispatch]);
194
+ }
195
+ function useEnhancedReducerDispatch(reducerDispatch) {
196
+ const logger = useLogger();
197
+ const eventBus = useEventBus();
198
+ return useCallback((action) => {
199
+ logger.debug("[squide] The following action has been dispatched to the AppRouter reducer:", action);
200
+ eventBus.dispatch(`squide-${action.type}`);
201
+ reducerDispatch(action);
202
+ }, [reducerDispatch, logger, eventBus]);
203
+ }
204
+ function useAppRouterReducer(waitForMsw, waitForPublicData, waitForProtectedData) {
205
+ const areModulesInitiallyRegistered = getAreModulesRegistered();
206
+ const areModulesInitiallyReady = getAreModulesReady();
207
+ const isMswInitiallyReady = isMswReady();
208
+ const eventBus = useEventBus();
209
+ useExecuteOnce(useCallback(() => {
210
+ if (areModulesInitiallyRegistered) {
211
+ eventBus.dispatch(ModulesRegisteredEvent);
212
+ }
213
+ return true;
214
+ }, [areModulesInitiallyRegistered, eventBus]), true);
215
+ useExecuteOnce(useCallback(() => {
216
+ if (areModulesInitiallyReady) {
217
+ eventBus.dispatch(ModulesReadyEvent);
218
+ }
219
+ return true;
220
+ }, [areModulesInitiallyReady, eventBus]), true);
221
+ useExecuteOnce(useCallback(() => {
222
+ if (isMswInitiallyReady) {
223
+ eventBus.dispatch(MswReadyEvent);
224
+ }
225
+ return true;
226
+ }, [isMswInitiallyReady, eventBus]), true);
227
+ const [state, reactDispatch] = useReducer(reducer, {
228
+ waitForMsw,
229
+ waitForPublicData,
230
+ waitForProtectedData,
231
+ // When the modules registration functions are awaited, the event listeners are registered after the modules are registered.
232
+ areModulesRegistered: areModulesInitiallyRegistered,
233
+ areModulesReady: areModulesInitiallyReady,
234
+ isMswReady: isMswInitiallyReady,
235
+ isPublicDataReady: false,
236
+ isProtectedDataReady: false,
237
+ activeRouteVisibility: "unknown",
238
+ isUnauthorized: false
239
+ });
240
+ const {
241
+ areModulesRegistered: areModulesRegisteredValue,
242
+ areModulesReady: areModulesReadyValue,
243
+ isMswReady: isMswReadyValue
244
+ } = state;
245
+ const dispatchProxy = useReducerDispatchProxy(reactDispatch);
246
+ const dispatch = useEnhancedReducerDispatch(dispatchProxy);
247
+ useModuleRegistrationStatusDispatcher(areModulesRegisteredValue, areModulesReadyValue, dispatch);
248
+ useMswStatusDispatcher(isMswReadyValue, dispatch);
249
+ useBootstrappingCompletedDispatcher(state);
250
+ return [state, dispatch];
251
+ }
252
+
253
+ export { ApplicationBoostrappedEvent, DeferredRegistrationsUpdatedEvent, ModulesReadyEvent, ModulesRegisteredEvent, MswReadyEvent, ProtectedDataReadyEvent, ProtectedDataUpdatedEvent, PublicDataReadyEvent, PublicDataUpdatedEvent, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useBootstrappingCompletedDispatcher, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher };
@@ -1,6 +1,6 @@
1
1
  import { useStrictRegistrationMode } from './chunk-WOPD33CM.js';
2
- import { useAppRouterReducer } from './chunk-ENUCXEMN.js';
3
- import { RootRoute } from './chunk-MZG2PJJG.js';
2
+ import { useAppRouterReducer } from './chunk-JFMSLZ74.js';
3
+ import { RootRoute } from './chunk-PMVN3U47.js';
4
4
  import { AppRouterDispatcherContext, AppRouterStateContext } from './chunk-G32YX2KR.js';
5
5
  import { useLogger } from '@squide/core';
6
6
  import { useRoutes } from '@squide/react-router';
@@ -1,19 +1,25 @@
1
+ import { useCanFetchProtectedData } from './chunk-XDWYPVAJ.js';
2
+ import { useExecuteOnce } from './chunk-TURKCH7J.js';
1
3
  import { GlobalDataQueriesError } from './chunk-HE5HKFL3.js';
2
- import { useCanFetchProtectedData } from './chunk-L5BP3WP3.js';
3
4
  import { useAppRouterDispatcher, useAppRouterState } from './chunk-G32YX2KR.js';
5
+ import { useEventBus } from '@squide/core';
4
6
  import { useQueries } from '@tanstack/react-query';
5
- import { useCallback, useEffect, useRef } from 'react';
7
+ import { useCallback, useRef, useEffect } from 'react';
6
8
 
9
+ var ProtectedDataFetchStartedEvent = "squide-protected-data-fetch-started";
10
+ var ProtectedDataFetchFailedEvent = "squide-protected-data-fetch-failed";
7
11
  function useProtectedDataQueries(queries, isUnauthorizedError) {
8
12
  const canFetchProtectedData = useCanFetchProtectedData();
13
+ const eventBus = useEventBus();
9
14
  const dispatch = useAppRouterDispatcher();
10
15
  const combineResults = useCallback((results) => {
11
16
  const errors = results.filter((x) => x.error).map((x) => x.error);
17
+ const hasErrors2 = errors.length > 0;
12
18
  return {
13
19
  data: results.map((x) => x.data),
14
20
  errors,
15
- hasErrors: errors.length > 0,
16
- isReady: !results.some((x) => x.isPending)
21
+ hasErrors: hasErrors2,
22
+ isReady: !hasErrors2 && !results.some((x) => x.isPending)
17
23
  };
18
24
  }, []);
19
25
  const { data, errors: queriesErrors, hasErrors, isReady } = useQueries({
@@ -23,33 +29,43 @@ function useProtectedDataQueries(queries, isUnauthorizedError) {
23
29
  })),
24
30
  combine: combineResults
25
31
  });
26
- const {
27
- isProtectedDataReady,
28
- isUnauthorized
29
- } = useAppRouterState();
30
- useEffect(() => {
31
- if (hasErrors) {
32
- if (!isProtectedDataReady && !isUnauthorized && queriesErrors.some((x) => isUnauthorizedError(x))) {
33
- dispatch({ type: "is-unauthorized" });
34
- }
35
- if (!queriesErrors.every((x) => isUnauthorizedError(x))) {
36
- throw new GlobalDataQueriesError("[squide] Global protected data queries failed.", queriesErrors);
37
- }
32
+ const { isProtectedDataReady, isUnauthorized } = useAppRouterState();
33
+ useExecuteOnce(useCallback(() => {
34
+ if (canFetchProtectedData) {
35
+ eventBus.dispatch(ProtectedDataFetchStartedEvent);
36
+ return true;
38
37
  }
39
- }, [hasErrors, queriesErrors, isProtectedDataReady, isUnauthorized, isUnauthorizedError, dispatch]);
38
+ return false;
39
+ }, [canFetchProtectedData, eventBus]), true);
40
40
  const isReadyRef = useRef(false);
41
+ const dispatchReady = useExecuteOnce(useCallback(() => {
42
+ if (isReady) {
43
+ isReadyRef.current = true;
44
+ dispatch({ type: "protected-data-ready" });
45
+ return true;
46
+ }
47
+ return false;
48
+ }, [isReady, dispatch]));
49
+ useEffect(() => {
50
+ dispatchReady();
51
+ }, [dispatchReady]);
41
52
  useEffect(() => {
42
53
  if (isReadyRef.current && data) {
43
54
  dispatch({ type: "protected-data-updated" });
44
55
  }
45
56
  }, [data, dispatch]);
46
57
  useEffect(() => {
47
- if (isReady) {
48
- isReadyRef.current = true;
49
- dispatch({ type: "protected-data-ready" });
58
+ if (hasErrors) {
59
+ if (!isProtectedDataReady && !isUnauthorized && queriesErrors.some((x) => isUnauthorizedError(x))) {
60
+ dispatch({ type: "is-unauthorized" });
61
+ }
62
+ if (!queriesErrors.every((x) => isUnauthorizedError(x))) {
63
+ eventBus.dispatch(ProtectedDataFetchFailedEvent, queriesErrors);
64
+ throw new GlobalDataQueriesError("[squide] Global protected data queries failed.", queriesErrors);
65
+ }
50
66
  }
51
- }, [isReady, dispatch]);
67
+ }, [hasErrors, queriesErrors, isProtectedDataReady, isUnauthorized, isUnauthorizedError, dispatch, eventBus]);
52
68
  return data;
53
69
  }
54
70
 
55
- export { useProtectedDataQueries };
71
+ export { ProtectedDataFetchFailedEvent, ProtectedDataFetchStartedEvent, useProtectedDataQueries };
@@ -11,6 +11,8 @@ function RootRoute() {
11
11
  useEffect(() => {
12
12
  if (isActiveRouteProtected) {
13
13
  dispatch({ type: "active-route-is-protected" });
14
+ } else {
15
+ dispatch({ type: "active-route-is-public" });
14
16
  }
15
17
  }, [isActiveRouteProtected, dispatch]);
16
18
  return /* @__PURE__ */ jsx(Outlet, {});
@@ -0,0 +1,20 @@
1
+ import { useRef, useCallback } from 'react';
2
+
3
+ // src/useExecuteOnce.ts
4
+ function useExecuteOnce(fct, inline = false) {
5
+ const triggered = useRef(false);
6
+ const onceFct = useCallback(() => {
7
+ if (!triggered.current) {
8
+ const result = fct();
9
+ if (result) {
10
+ triggered.current = true;
11
+ }
12
+ }
13
+ }, [fct]);
14
+ if (inline) {
15
+ onceFct();
16
+ }
17
+ return onceFct;
18
+ }
19
+
20
+ export { useExecuteOnce };
@@ -8,13 +8,13 @@ function useCanFetchProtectedData() {
8
8
  areModulesReady,
9
9
  isMswReady,
10
10
  isProtectedDataReady,
11
- isActiveRouteProtected
11
+ activeRouteVisibility
12
12
  } = useAppRouterState();
13
13
  return (
14
14
  // Always return true when the protected data has already been fetched sucessfully so TanStack Query can update the data in the background.
15
15
  isProtectedDataReady || // Wait until the modules has been registered, but do not wait for the deferred registrations to be registered as they will probably
16
16
  // depends on the protected data.
17
- (areModulesRegistered || areModulesReady) && isActiveRouteProtected && (!waitForMsw || isMswReady)
17
+ (areModulesRegistered || areModulesReady) && activeRouteVisibility === "protected" && (!waitForMsw || isMswReady)
18
18
  );
19
19
  }
20
20
 
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export * from '@squide/react-router';
5
5
  export { FireflyRuntime, FireflyRuntimeOptions } from './FireflyRuntime.js';
6
6
  export { AppRouter, AppRouterProps, AppRouterRenderFunctionArgs, RenderRouterProviderFunction, RenderRouterProviderFunctionArgs } from './AppRouter.js';
7
7
  export { AppRouterDispatcherContext, AppRouterStateContext, useAppRouterDispatcher, useAppRouterState } from './AppRouterContext.js';
8
- export { AppRouterAction, AppRouterActionType, AppRouterDispatch, AppRouterState, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher } from './AppRouterReducer.js';
8
+ export { ActiveRouteVisiblity, AppRouterAction, AppRouterActionType, AppRouterDispatch, AppRouterState, ApplicationBoostrappedEvent, DeferredRegistrationsUpdatedEvent, ModulesReadyEvent, ModulesRegisteredEvent, MswReadyEvent, ProtectedDataReadyEvent, ProtectedDataUpdatedEvent, PublicDataReadyEvent, PublicDataUpdatedEvent, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useBootstrappingCompletedDispatcher, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher } from './AppRouterReducer.js';
9
9
  export { GlobalDataQueriesError, isGlobalDataQueriesError } from './GlobalDataQueriesError.js';
10
10
  export { useCanFetchProtectedData } from './useCanFetchProtectedData.js';
11
11
  export { useCanFetchPublicData } from './useCanFetchPublicData.js';
@@ -13,13 +13,14 @@ export { useCanRegisterDeferredRegistrations } from './useCanRegisterDeferredReg
13
13
  export { useCanUpdateDeferredRegistrations } from './useCanUpdateDeferredRegistrations.js';
14
14
  export { DeferredRegistrationsErrorCallback, DeferredRegistrationsErrorsObject, UseDeferredRegistrationsOptions, useDeferredRegistrations } from './useDeferredRegistrations.js';
15
15
  export { useIsActiveRouteProtected } from './useIsActiveRouteProtected.js';
16
- export { useIsBootstrapping } from './useIsBootstrapping.js';
16
+ export { isApplicationBootstrapping, useIsBootstrapping } from './useIsBootstrapping.js';
17
17
  export { UseNavigationItemsOptions, useNavigationItems } from './useNavigationItems.js';
18
- export { IsUnauthorizedErrorCallback, useProtectedDataQueries } from './useProtectedDataQueries.js';
19
- export { usePublicDataQueries } from './usePublicDataQueries.js';
18
+ export { IsUnauthorizedErrorCallback, ProtectedDataFetchFailedEvent, ProtectedDataFetchStartedEvent, useProtectedDataQueries } from './useProtectedDataQueries.js';
19
+ export { PublicDataFetchFailedEvent, PublicDataFetchStartedEvent, usePublicDataQueries } from './usePublicDataQueries.js';
20
20
  export { useRegisterDeferredRegistrations } from './useRegisterDeferredRegistrations.js';
21
21
  export { useStrictRegistrationMode } from './useStrictRegistrationMode.js';
22
22
  export { useUpdateDeferredRegistrations } from './useUpdateDeferredRegistrations.js';
23
+ export { ApplicationBootstrappingStartedEvent, BootstrapAppOptions, StartMswFunction, __resetBootstrapGuard, bootstrap } from './boostrap.js';
23
24
  import 'msw';
24
25
  import 'react/jsx-runtime';
25
26
  import 'react';
package/dist/index.js CHANGED
@@ -1,22 +1,24 @@
1
- export { usePublicDataQueries } from './chunk-VUMBZ5BP.js';
1
+ export { useNavigationItems } from './chunk-GXSW4CZS.js';
2
+ export { ProtectedDataFetchFailedEvent, ProtectedDataFetchStartedEvent, useProtectedDataQueries } from './chunk-MKTGJHQR.js';
3
+ export { PublicDataFetchFailedEvent, PublicDataFetchStartedEvent, usePublicDataQueries } from './chunk-CTLPFYLM.js';
4
+ export { useCanFetchProtectedData } from './chunk-XDWYPVAJ.js';
2
5
  export { useCanFetchPublicData } from './chunk-IOMSOUAL.js';
3
- export { useDeferredRegistrations } from './chunk-2E76JVV7.js';
6
+ export { useDeferredRegistrations } from './chunk-BFHHJOJT.js';
4
7
  export { useRegisterDeferredRegistrations } from './chunk-YRWFYWK4.js';
5
8
  export { useUpdateDeferredRegistrations } from './chunk-N2GOIQ5E.js';
6
- export { useCanRegisterDeferredRegistrations } from './chunk-PU7MASPN.js';
9
+ export { useCanRegisterDeferredRegistrations } from './chunk-4RUCDAUT.js';
7
10
  export { useCanUpdateDeferredRegistrations } from './chunk-WVRMJZV6.js';
8
- export { useIsBootstrapping } from './chunk-I6L3AYOB.js';
9
- export { useNavigationItems } from './chunk-GXSW4CZS.js';
10
- export { useProtectedDataQueries } from './chunk-7R2Z7FXF.js';
11
- export { AppRouter } from './chunk-36U4TTNR.js';
11
+ export { AppRouter } from './chunk-L44KFU57.js';
12
12
  export { useStrictRegistrationMode } from './chunk-WOPD33CM.js';
13
- export { FireflyRuntime } from './chunk-FKQ7XQEU.js';
14
- export { __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher } from './chunk-ENUCXEMN.js';
13
+ export { FireflyRuntime } from './chunk-CFNKNPS3.js';
14
+ export { ApplicationBoostrappedEvent, DeferredRegistrationsUpdatedEvent, ModulesReadyEvent, ModulesRegisteredEvent, MswReadyEvent, ProtectedDataReadyEvent, ProtectedDataUpdatedEvent, PublicDataReadyEvent, PublicDataUpdatedEvent, __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useBootstrappingCompletedDispatcher, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher } from './chunk-JFMSLZ74.js';
15
+ import './chunk-TURKCH7J.js';
16
+ export { isApplicationBootstrapping, useIsBootstrapping } from './chunk-H2ILEMPE.js';
15
17
  export { GlobalDataQueriesError, isGlobalDataQueriesError } from './chunk-HE5HKFL3.js';
16
- import './chunk-MZG2PJJG.js';
18
+ import './chunk-PMVN3U47.js';
17
19
  export { useIsActiveRouteProtected } from './chunk-PP3MRMJJ.js';
18
- export { useCanFetchProtectedData } from './chunk-L5BP3WP3.js';
19
20
  export { AppRouterDispatcherContext, AppRouterStateContext, useAppRouterDispatcher, useAppRouterState } from './chunk-G32YX2KR.js';
21
+ export { ApplicationBootstrappingStartedEvent, __resetBootstrapGuard, bootstrap } from './chunk-IGJHKH2A.js';
20
22
  export * from '@squide/core';
21
23
  export * from '@squide/module-federation';
22
24
  export * from '@squide/msw';
@@ -1,2 +1,2 @@
1
- export { useCanFetchProtectedData } from './chunk-L5BP3WP3.js';
1
+ export { useCanFetchProtectedData } from './chunk-XDWYPVAJ.js';
2
2
  import './chunk-G32YX2KR.js';
@@ -1,2 +1,2 @@
1
- export { useCanRegisterDeferredRegistrations } from './chunk-PU7MASPN.js';
1
+ export { useCanRegisterDeferredRegistrations } from './chunk-4RUCDAUT.js';
2
2
  import './chunk-G32YX2KR.js';
@@ -1,6 +1,6 @@
1
- export { useDeferredRegistrations } from './chunk-2E76JVV7.js';
1
+ export { useDeferredRegistrations } from './chunk-BFHHJOJT.js';
2
2
  import './chunk-YRWFYWK4.js';
3
3
  import './chunk-N2GOIQ5E.js';
4
- import './chunk-PU7MASPN.js';
4
+ import './chunk-4RUCDAUT.js';
5
5
  import './chunk-WVRMJZV6.js';
6
6
  import './chunk-G32YX2KR.js';
@@ -0,0 +1,3 @@
1
+ declare function useExecuteOnce(fct: () => boolean, inline?: boolean): () => void;
2
+
3
+ export { useExecuteOnce };
@@ -0,0 +1 @@
1
+ export { useExecuteOnce } from './chunk-TURKCH7J.js';
@@ -1,3 +1,7 @@
1
+ import { AppRouterState } from './AppRouterReducer.js';
2
+ import 'react';
3
+
1
4
  declare function useIsBootstrapping(): boolean;
5
+ declare function isApplicationBootstrapping(state: AppRouterState): boolean;
2
6
 
3
- export { useIsBootstrapping };
7
+ export { isApplicationBootstrapping, useIsBootstrapping };
@@ -1,2 +1,2 @@
1
- export { useIsBootstrapping } from './chunk-I6L3AYOB.js';
1
+ export { isApplicationBootstrapping, useIsBootstrapping } from './chunk-H2ILEMPE.js';
2
2
  import './chunk-G32YX2KR.js';
@@ -1,9 +1,11 @@
1
1
  import { QueriesOptions, QueriesResults, UseQueryResult } from '@tanstack/react-query';
2
2
 
3
+ declare const ProtectedDataFetchStartedEvent = "squide-protected-data-fetch-started";
4
+ declare const ProtectedDataFetchFailedEvent = "squide-protected-data-fetch-failed";
3
5
  type IsUnauthorizedErrorCallback = (error: unknown) => boolean;
4
6
  type MapUseQueryResultToData<T> = {
5
7
  [K in keyof T]: T[K] extends UseQueryResult<infer U> ? U : never;
6
8
  };
7
9
  declare function useProtectedDataQueries<T extends Array<any>>(queries: QueriesOptions<T>, isUnauthorizedError: IsUnauthorizedErrorCallback): MapUseQueryResultToData<QueriesResults<T>>;
8
10
 
9
- export { type IsUnauthorizedErrorCallback, useProtectedDataQueries };
11
+ export { type IsUnauthorizedErrorCallback, ProtectedDataFetchFailedEvent, ProtectedDataFetchStartedEvent, useProtectedDataQueries };
@@ -1,4 +1,5 @@
1
- export { useProtectedDataQueries } from './chunk-7R2Z7FXF.js';
1
+ export { ProtectedDataFetchFailedEvent, ProtectedDataFetchStartedEvent, useProtectedDataQueries } from './chunk-MKTGJHQR.js';
2
+ import './chunk-XDWYPVAJ.js';
3
+ import './chunk-TURKCH7J.js';
2
4
  import './chunk-HE5HKFL3.js';
3
- import './chunk-L5BP3WP3.js';
4
5
  import './chunk-G32YX2KR.js';
@@ -1,8 +1,10 @@
1
1
  import { QueriesOptions, QueriesResults, UseQueryResult } from '@tanstack/react-query';
2
2
 
3
+ declare const PublicDataFetchStartedEvent = "squide-public-data-fetch-started";
4
+ declare const PublicDataFetchFailedEvent = "squide-public-data-fetch-failed";
3
5
  type MapUseQueryResultToData<T> = {
4
6
  [K in keyof T]: T[K] extends UseQueryResult<infer U> ? U : never;
5
7
  };
6
8
  declare function usePublicDataQueries<T extends Array<any>>(queries: QueriesOptions<T>): MapUseQueryResultToData<QueriesResults<T>>;
7
9
 
8
- export { usePublicDataQueries };
10
+ export { PublicDataFetchFailedEvent, PublicDataFetchStartedEvent, usePublicDataQueries };
@@ -1,4 +1,5 @@
1
- export { usePublicDataQueries } from './chunk-VUMBZ5BP.js';
1
+ export { PublicDataFetchFailedEvent, PublicDataFetchStartedEvent, usePublicDataQueries } from './chunk-CTLPFYLM.js';
2
2
  import './chunk-IOMSOUAL.js';
3
+ import './chunk-TURKCH7J.js';
3
4
  import './chunk-HE5HKFL3.js';
4
5
  import './chunk-G32YX2KR.js';
@@ -1,9 +1,10 @@
1
+ import * as _squide_module_federation from '@squide/module-federation';
1
2
  import * as _squide_core from '@squide/core';
2
3
  import { Runtime } from '@squide/core';
3
4
 
4
5
  declare function useRegisterDeferredRegistrations(): <TData = unknown, TRuntime extends Runtime = Runtime<unknown, unknown>>(data: TData, runtime: TRuntime) => Promise<{
5
6
  localModuleErrors: _squide_core.ModuleRegistrationError[];
6
- remoteModuleErrors: _squide_core.ModuleRegistrationError[];
7
+ remoteModuleErrors: _squide_module_federation.RemoteModuleRegistrationError[];
7
8
  }>;
8
9
 
9
10
  export { useRegisterDeferredRegistrations };
@@ -1,9 +1,10 @@
1
+ import * as _squide_module_federation from '@squide/module-federation';
1
2
  import * as _squide_core from '@squide/core';
2
3
  import { Runtime } from '@squide/core';
3
4
 
4
5
  declare function useUpdateDeferredRegistrations(): <TData = unknown, TRuntime extends Runtime = Runtime<unknown, unknown>>(data: TData, runtime: TRuntime) => Promise<{
5
6
  localModuleErrors: _squide_core.ModuleRegistrationError[];
6
- remoteModuleErrors: _squide_core.ModuleRegistrationError[];
7
+ remoteModuleErrors: _squide_module_federation.RemoteModuleRegistrationError[];
7
8
  }>;
8
9
 
9
10
  export { useUpdateDeferredRegistrations };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@squide/firefly",
3
3
  "author": "Workleap",
4
- "version": "9.2.1",
4
+ "version": "9.3.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": {
@@ -39,7 +39,7 @@
39
39
  "@testing-library/jest-dom": "6.5.0",
40
40
  "@testing-library/react": "16.0.1",
41
41
  "@types/jest": "29.5.13",
42
- "@types/react": "18.3.8",
42
+ "@types/react": "18.3.11",
43
43
  "@types/react-dom": "18.3.0",
44
44
  "@workleap/eslint-plugin": "3.2.2",
45
45
  "@workleap/swc-configs": "2.2.3",
@@ -57,10 +57,10 @@
57
57
  "typescript": "5.5.4"
58
58
  },
59
59
  "dependencies": {
60
- "@squide/core": "5.3.0",
61
- "@squide/module-federation": "6.1.1",
62
- "@squide/msw": "3.1.1",
63
- "@squide/react-router": "6.3.0"
60
+ "@squide/core": "5.4.0",
61
+ "@squide/module-federation": "6.2.0",
62
+ "@squide/msw": "3.2.0",
63
+ "@squide/react-router": "6.4.0"
64
64
  },
65
65
  "sideEffects": false,
66
66
  "engines": {
@@ -1,180 +0,0 @@
1
- import { getLocalModuleRegistrationStatus, useLogger, addLocalModuleRegistrationStatusChangedListener, removeLocalModuleRegistrationStatusChangedListener } from '@squide/core';
2
- import { getRemoteModuleRegistrationStatus, areModulesRegistered, areModulesReady, addRemoteModuleRegistrationStatusChangedListener, removeRemoteModuleRegistrationStatusChangedListener } from '@squide/module-federation';
3
- import { addMswStateChangedListener, removeMswStateChangedListener, isMswReady } from '@squide/msw';
4
- import { useEffect, useReducer, useCallback, useMemo } from 'react';
5
-
6
- // src/AppRouterReducer.ts
7
- function useVerboseDispatch(dispatch) {
8
- const logger = useLogger();
9
- return useCallback((action) => {
10
- logger.debug("[squide] The following action has been dispatched to the AppRouter reducer:", action);
11
- dispatch(action);
12
- }, [dispatch, logger]);
13
- }
14
- function reducer(state, action) {
15
- let newState = state;
16
- switch (action.type) {
17
- case "modules-registered": {
18
- newState = {
19
- ...newState,
20
- areModulesRegistered: true
21
- };
22
- break;
23
- }
24
- case "modules-ready": {
25
- newState = {
26
- ...newState,
27
- areModulesReady: true,
28
- // Will be set even if the app is not using deferred registrations.
29
- deferredRegistrationsUpdatedAt: Date.now()
30
- };
31
- break;
32
- }
33
- case "msw-ready": {
34
- newState = {
35
- ...newState,
36
- isMswReady: true
37
- };
38
- break;
39
- }
40
- case "public-data-ready": {
41
- newState = {
42
- ...newState,
43
- isPublicDataReady: true,
44
- publicDataUpdatedAt: Date.now()
45
- };
46
- break;
47
- }
48
- case "protected-data-ready": {
49
- newState = {
50
- ...newState,
51
- isProtectedDataReady: true,
52
- protectedDataUpdatedAt: Date.now()
53
- };
54
- break;
55
- }
56
- case "public-data-updated": {
57
- newState = {
58
- ...newState,
59
- publicDataUpdatedAt: Date.now()
60
- };
61
- break;
62
- }
63
- case "protected-data-updated": {
64
- newState = {
65
- ...newState,
66
- protectedDataUpdatedAt: Date.now()
67
- };
68
- break;
69
- }
70
- case "deferred-registrations-updated": {
71
- newState = {
72
- ...newState,
73
- deferredRegistrationsUpdatedAt: Date.now()
74
- };
75
- break;
76
- }
77
- case "active-route-is-protected": {
78
- newState = {
79
- ...newState,
80
- isActiveRouteProtected: true
81
- };
82
- break;
83
- }
84
- case "is-unauthorized": {
85
- newState = {
86
- ...newState,
87
- isUnauthorized: true
88
- };
89
- break;
90
- }
91
- default: {
92
- throw new Error(`[squide] The AppRouter component state reducer doesn't support action type "${action.type}".`);
93
- }
94
- }
95
- return newState;
96
- }
97
- function getAreModulesRegistered() {
98
- const localModuleStatus = getLocalModuleRegistrationStatus();
99
- const remoteModuleStatus = getRemoteModuleRegistrationStatus();
100
- return areModulesRegistered(localModuleStatus, remoteModuleStatus);
101
- }
102
- function getAreModulesReady() {
103
- const localModuleStatus = getLocalModuleRegistrationStatus();
104
- const remoteModuleStatus = getRemoteModuleRegistrationStatus();
105
- return areModulesReady(localModuleStatus, remoteModuleStatus);
106
- }
107
- function useModuleRegistrationStatusDispatcher(areModulesRegisteredValue, areModulesReadyValue, dispatch) {
108
- const logger = useLogger();
109
- return useEffect(() => {
110
- const handleModulesRegistrationStatusChange = () => {
111
- if (!areModulesRegisteredValue && getAreModulesRegistered()) {
112
- dispatch({ type: "modules-registered" });
113
- }
114
- if (!areModulesReadyValue && getAreModulesReady()) {
115
- dispatch({ type: "modules-ready" });
116
- logger.debug("[squide] %cModules are ready%c.", "color: white; background-color: green;", "");
117
- }
118
- };
119
- addLocalModuleRegistrationStatusChangedListener(handleModulesRegistrationStatusChange);
120
- addRemoteModuleRegistrationStatusChangedListener(handleModulesRegistrationStatusChange);
121
- return () => {
122
- removeLocalModuleRegistrationStatusChangedListener(handleModulesRegistrationStatusChange);
123
- removeRemoteModuleRegistrationStatusChangedListener(handleModulesRegistrationStatusChange);
124
- };
125
- }, [areModulesRegisteredValue, areModulesReadyValue, dispatch, logger]);
126
- }
127
- function useMswStatusDispatcher(isMswReadyValue, dispatch) {
128
- const logger = useLogger();
129
- useEffect(() => {
130
- const handleMswStateChange = () => {
131
- if (!isMswReadyValue && isMswReady()) {
132
- dispatch({ type: "msw-ready" });
133
- logger.debug("[squide] %cMSW is ready%c.", "color: white; background-color: green;", "");
134
- }
135
- };
136
- addMswStateChangedListener(handleMswStateChange);
137
- return () => {
138
- removeMswStateChangedListener(handleMswStateChange);
139
- };
140
- }, [isMswReadyValue, dispatch, logger]);
141
- }
142
- var dispatchProxyFactory;
143
- function __setAppReducerDispatchProxyFactory(factory) {
144
- dispatchProxyFactory = factory;
145
- }
146
- function __clearAppReducerDispatchProxy() {
147
- dispatchProxyFactory = void 0;
148
- }
149
- function useDispatchProxy(reactDispatch) {
150
- return useMemo(() => {
151
- return dispatchProxyFactory ? dispatchProxyFactory(reactDispatch) : reactDispatch;
152
- }, [reactDispatch]);
153
- }
154
- function useAppRouterReducer(waitForMsw, waitForPublicData, waitForProtectedData) {
155
- const [state, reactDispatch] = useReducer(reducer, {
156
- waitForMsw,
157
- waitForPublicData,
158
- waitForProtectedData,
159
- // When the modules registration functions are awaited, the event listeners are registered after the modules are registered.
160
- areModulesRegistered: getAreModulesRegistered(),
161
- areModulesReady: getAreModulesReady(),
162
- isMswReady: isMswReady(),
163
- isPublicDataReady: false,
164
- isProtectedDataReady: false,
165
- isActiveRouteProtected: false,
166
- isUnauthorized: false
167
- });
168
- const {
169
- areModulesRegistered: areModulesRegisteredValue,
170
- areModulesReady: areModulesReadyValue,
171
- isMswReady: isMswReadyValue
172
- } = state;
173
- const dispatchProxy = useDispatchProxy(reactDispatch);
174
- const dispatch = useVerboseDispatch(dispatchProxy);
175
- useModuleRegistrationStatusDispatcher(areModulesRegisteredValue, areModulesReadyValue, dispatch);
176
- useMswStatusDispatcher(isMswReadyValue, dispatch);
177
- return [state, dispatch];
178
- }
179
-
180
- export { __clearAppReducerDispatchProxy, __setAppReducerDispatchProxyFactory, getAreModulesReady, getAreModulesRegistered, useAppRouterReducer, useModuleRegistrationStatusDispatcher, useMswStatusDispatcher };