antaeus.keycloak.react 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -659,6 +659,71 @@ var SessionMonitor = ({
659
659
  ] });
660
660
  };
661
661
 
662
+ // src/utils/tokenBridge.ts
663
+ var TokenBridge = class {
664
+ constructor() {
665
+ this.currentToken = null;
666
+ this.listeners = /* @__PURE__ */ new Set();
667
+ }
668
+ /**
669
+ * Update the tracked token and notify subscribers when it changes.
670
+ */
671
+ setToken(token) {
672
+ if (this.currentToken === token) {
673
+ return;
674
+ }
675
+ this.currentToken = token;
676
+ for (const listener of this.listeners) {
677
+ try {
678
+ listener(token);
679
+ } catch (error) {
680
+ console.error("[TokenBridge] Listener threw error:", error);
681
+ }
682
+ }
683
+ }
684
+ /**
685
+ * Read the most recent token value.
686
+ */
687
+ getToken() {
688
+ return this.currentToken;
689
+ }
690
+ /**
691
+ * Convenience helper for async callers.
692
+ */
693
+ async getTokenAsync() {
694
+ return this.currentToken;
695
+ }
696
+ /**
697
+ * Subscribe to token changes. Returns an unsubscribe callback.
698
+ */
699
+ subscribe(listener) {
700
+ this.listeners.add(listener);
701
+ listener(this.currentToken);
702
+ return () => {
703
+ this.listeners.delete(listener);
704
+ };
705
+ }
706
+ };
707
+ var createTokenBridge = () => new TokenBridge();
708
+ var defaultTokenBridge = createTokenBridge();
709
+
710
+ // src/components/TokenBridge.tsx
711
+ var TokenBridgeSync = ({
712
+ bridge = defaultTokenBridge
713
+ }) => {
714
+ const auth = useAuth();
715
+ react.useEffect(() => {
716
+ const token = auth.user?.access_token ?? null;
717
+ bridge.setToken(token);
718
+ }, [auth.user, bridge]);
719
+ react.useEffect(() => {
720
+ if (!auth.isAuthenticated) {
721
+ bridge.setToken(null);
722
+ }
723
+ }, [auth.isAuthenticated, bridge]);
724
+ return null;
725
+ };
726
+
662
727
  // src/config/presets.ts
663
728
  var CONFIG_PRESETS = {
664
729
  /**
@@ -877,11 +942,97 @@ var StorageConfigProvider = ({ storageType, children }) => {
877
942
  return /* @__PURE__ */ jsxRuntime.jsx(StorageConfigContext.Provider, { value: { storageType, storage }, children });
878
943
  };
879
944
  var useStorageConfig = () => react.useContext(StorageConfigContext);
945
+ var defaultStatus = {
946
+ isEnabled: true,
947
+ isConfigured: true
948
+ };
949
+ var KeycloakStatusContext = react.createContext(defaultStatus);
950
+ var KeycloakStatusProvider = KeycloakStatusContext.Provider;
951
+ var useKeycloakStatus = () => react.useContext(KeycloakStatusContext);
952
+ var createDisabledEvents = () => {
953
+ const noop = () => void 0;
954
+ const noopSubscription = () => () => void 0;
955
+ const noopAsync = async () => void 0;
956
+ const events = {
957
+ addAccessTokenExpiring: noopSubscription,
958
+ removeAccessTokenExpiring: noop,
959
+ addAccessTokenExpired: noopSubscription,
960
+ removeAccessTokenExpired: noop,
961
+ addSilentRenewError: noopSubscription,
962
+ removeSilentRenewError: noop,
963
+ addUserLoaded: noopSubscription,
964
+ removeUserLoaded: noop,
965
+ addUserUnloaded: noopSubscription,
966
+ removeUserUnloaded: noop,
967
+ addUserSignedIn: noopSubscription,
968
+ removeUserSignedIn: noop,
969
+ addUserSignedOut: noopSubscription,
970
+ removeUserSignedOut: noop,
971
+ addUserSessionChanged: noopSubscription,
972
+ removeUserSessionChanged: noop,
973
+ load: noopAsync,
974
+ unload: noopAsync
975
+ };
976
+ return events;
977
+ };
978
+ var disabledEvents = createDisabledEvents();
979
+ var disabledSettings = {
980
+ authority: "",
981
+ client_id: "",
982
+ redirect_uri: "http://localhost/disabled",
983
+ response_type: "code",
984
+ scope: ""
985
+ };
986
+ var disabledError = () => new Error("Keycloak integration is disabled for this environment.");
987
+ var disabledAsync = async () => {
988
+ throw disabledError();
989
+ };
990
+ var disabledAuthContext = {
991
+ settings: disabledSettings,
992
+ events: disabledEvents,
993
+ clearStaleState: async () => void 0,
994
+ removeUser: async () => void 0,
995
+ signinPopup: (_args) => disabledAsync(),
996
+ signinSilent: async (_args) => null,
997
+ signinRedirect: (_args) => disabledAsync(),
998
+ signinResourceOwnerCredentials: (_args) => disabledAsync(),
999
+ signoutRedirect: async (_args) => void 0,
1000
+ signoutPopup: async (_args) => void 0,
1001
+ signoutSilent: async (_args) => void 0,
1002
+ querySessionStatus: async (_args) => null,
1003
+ revokeTokens: async (_types) => void 0,
1004
+ startSilentRenew: () => void 0,
1005
+ stopSilentRenew: () => void 0,
1006
+ user: null,
1007
+ isLoading: false,
1008
+ isAuthenticated: false,
1009
+ activeNavigator: void 0,
1010
+ error: void 0
1011
+ };
880
1012
  function isZeroConfig(props) {
881
1013
  return "authority" in props && "clientId" in props;
882
1014
  }
883
1015
  var KeycloakProvider = (props) => {
884
1016
  const { children, debug = false } = props;
1017
+ const status = react.useMemo(() => {
1018
+ const enabledFlag = props.enabled ?? true;
1019
+ const hasAuthority = isZeroConfig(props) ? Boolean(props.authority) : Boolean(props.config.authority);
1020
+ const hasClientId = isZeroConfig(props) ? Boolean(props.clientId) : Boolean(props.config.clientId);
1021
+ return {
1022
+ isEnabled: enabledFlag,
1023
+ isConfigured: hasAuthority && hasClientId,
1024
+ reason: !enabledFlag ? "disabled" : !hasAuthority || !hasClientId ? "missing-config" : void 0
1025
+ };
1026
+ }, [props]);
1027
+ const effectiveEnabled = status.isEnabled && status.isConfigured;
1028
+ react.useEffect(() => {
1029
+ if (!effectiveEnabled && props.tokenBridge) {
1030
+ props.tokenBridge.setToken(null);
1031
+ }
1032
+ }, [effectiveEnabled, props.tokenBridge]);
1033
+ if (!effectiveEnabled) {
1034
+ return /* @__PURE__ */ jsxRuntime.jsx(KeycloakStatusProvider, { value: status, children: /* @__PURE__ */ jsxRuntime.jsx(reactOidcContext.AuthContext.Provider, { value: disabledAuthContext, children: /* @__PURE__ */ jsxRuntime.jsx(StorageConfigProvider, { storageType: "session", children }) }) });
1035
+ }
885
1036
  const config = isZeroConfig(props) ? buildZeroConfig(props) : props.config;
886
1037
  const oidcConfig = KeycloakConfigBuilder.build(config);
887
1038
  const log = react.useCallback(
@@ -923,7 +1074,7 @@ var KeycloakProvider = (props) => {
923
1074
  }, [log]);
924
1075
  const showSessionMonitor = config.features?.sessionMonitor !== false;
925
1076
  const storageType = config.advanced?.storageType || "session";
926
- return /* @__PURE__ */ jsxRuntime.jsx(
1077
+ return /* @__PURE__ */ jsxRuntime.jsx(KeycloakStatusProvider, { value: status, children: /* @__PURE__ */ jsxRuntime.jsx(
927
1078
  reactOidcContext.AuthProvider,
928
1079
  {
929
1080
  ...oidcConfig,
@@ -931,11 +1082,12 @@ var KeycloakProvider = (props) => {
931
1082
  onSignoutCallback,
932
1083
  onRemoveUser,
933
1084
  children: /* @__PURE__ */ jsxRuntime.jsx(StorageConfigProvider, { storageType, children: /* @__PURE__ */ jsxRuntime.jsxs(TokenLifecycleManager, { config, debug, children: [
1085
+ props.tokenBridge && /* @__PURE__ */ jsxRuntime.jsx(TokenBridgeSync, { bridge: props.tokenBridge }),
934
1086
  showSessionMonitor && /* @__PURE__ */ jsxRuntime.jsx(SessionMonitor, {}),
935
1087
  children
936
1088
  ] }) })
937
1089
  }
938
- );
1090
+ ) });
939
1091
  };
940
1092
  function buildZeroConfig(props) {
941
1093
  const { authority, clientId, preset = "default", config: overrides = {} } = props;
@@ -1643,13 +1795,18 @@ exports.CONFIG_PRESETS = CONFIG_PRESETS;
1643
1795
  exports.DeviceLogin = DeviceLogin;
1644
1796
  exports.KeycloakConfigBuilder = KeycloakConfigBuilder;
1645
1797
  exports.KeycloakProvider = KeycloakProvider;
1798
+ exports.KeycloakStatusProvider = KeycloakStatusProvider;
1646
1799
  exports.LoginButton = LoginButton;
1647
1800
  exports.LogoutButton = LogoutButton;
1648
1801
  exports.ProtectedRoute = ProtectedRoute;
1649
1802
  exports.SessionMonitor = SessionMonitor;
1803
+ exports.TokenBridge = TokenBridge;
1804
+ exports.TokenBridgeSync = TokenBridgeSync;
1650
1805
  exports.TokenLifecycleManager = TokenLifecycleManager;
1651
1806
  exports.UserProfile = UserProfile;
1807
+ exports.createTokenBridge = createTokenBridge;
1652
1808
  exports.defaultConfig = defaultConfig;
1809
+ exports.defaultTokenBridge = defaultTokenBridge;
1653
1810
  exports.fetchUserInfo = fetchUserInfo;
1654
1811
  exports.getConfigFromEnv = getConfigFromEnv;
1655
1812
  exports.getConfigPreset = getConfigPreset;
@@ -1657,6 +1814,7 @@ exports.mergeWithPreset = mergeWithPreset;
1657
1814
  exports.pollForToken = pollForToken;
1658
1815
  exports.requestDeviceCode = requestDeviceCode;
1659
1816
  exports.useAuth = useAuth;
1817
+ exports.useKeycloakStatus = useKeycloakStatus;
1660
1818
  exports.useProtectedFetch = useProtectedFetch;
1661
1819
  exports.useRoles = useRoles;
1662
1820
  exports.useScopes = useScopes;