@multiplatform.one/keycloak 7.34.4 → 7.36.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 (40) hide show
  1. package/dist/cjs/index.cjs +120 -70
  2. package/dist/cjs/index.native.cjs +283 -148
  3. package/dist/esm/index.js +78 -28
  4. package/dist/esm/index.native.js +270 -135
  5. package/package.json +9 -9
  6. package/src/betterAuth/expoAuthFlow.deadline.spec.ts +230 -0
  7. package/src/betterAuth/expoAuthFlow.native.ts +67 -27
  8. package/src/keycloak/base.ts +3 -2
  9. package/src/keycloak/context.ts +2 -2
  10. package/src/keycloak/index.ts +26 -13
  11. package/src/keycloak/login.error.spec.tsx +85 -0
  12. package/src/provider/KeycloakProvider.loading.spec.tsx +37 -0
  13. package/src/provider/KeycloakProvider.tsx +16 -9
  14. package/src/provider/authProvider/index.native.tsx +170 -108
  15. package/src/provider/authProvider/nonblocking.native.spec.tsx +303 -0
  16. package/src/session/authError.ts +30 -0
  17. package/src/session/index.native.ts +6 -1
  18. package/src/session/index.ts +11 -4
  19. package/types/betterAuth/expoAuthFlow.native.d.ts +3 -1
  20. package/types/betterAuth/expoAuthFlow.native.d.ts.map +1 -1
  21. package/types/keycloak/base.d.ts +1 -1
  22. package/types/keycloak/base.d.ts.map +1 -1
  23. package/types/keycloak/context.d.ts +2 -2
  24. package/types/keycloak/context.d.ts.map +1 -1
  25. package/types/keycloak/index.d.ts +1 -1
  26. package/types/keycloak/index.d.ts.map +1 -1
  27. package/types/keycloak/index.native.d.ts +1 -1
  28. package/types/keycloak/index.native.d.ts.map +1 -1
  29. package/types/keycloak/index.webext.d.ts +1 -1
  30. package/types/keycloak/index.webext.d.ts.map +1 -1
  31. package/types/provider/KeycloakProvider.d.ts +3 -2
  32. package/types/provider/KeycloakProvider.d.ts.map +1 -1
  33. package/types/provider/authProvider/index.native.d.ts +1 -1
  34. package/types/provider/authProvider/index.native.d.ts.map +1 -1
  35. package/types/session/authError.d.ts +7 -0
  36. package/types/session/authError.d.ts.map +1 -0
  37. package/types/session/index.d.ts +2 -0
  38. package/types/session/index.d.ts.map +1 -1
  39. package/types/session/index.native.d.ts +1 -0
  40. package/types/session/index.native.d.ts.map +1 -1
@@ -33,6 +33,7 @@ __export(index_exports, {
33
33
  AfterAuth: () => AfterAuth,
34
34
  AuthConfigContext: () => AuthConfigContext,
35
35
  AuthProvider: () => AuthProvider,
36
+ AuthTimeoutError: () => AuthTimeoutError,
36
37
  Authenticated: () => Authenticated,
37
38
  BaseKeycloak: () => BaseKeycloak,
38
39
  Keycloak: () => Keycloak,
@@ -40,14 +41,17 @@ __export(index_exports, {
40
41
  KeycloakProvider: () => KeycloakProvider,
41
42
  defaultAuthConfig: () => defaultAuthConfig,
42
43
  getAllWalletAddresses: () => getAllWalletAddresses,
44
+ getAuthError: () => getAuthError,
43
45
  getKeycloakBearerToken: () => getKeycloakBearerToken,
44
46
  getSession: () => getSession,
45
47
  getWalletAddresses: () => getWalletAddresses,
46
48
  getWalletsFromToken: () => getWalletsFromToken,
47
49
  hasWallets: () => hasWallets,
48
50
  isTokenExpired: () => isTokenExpired,
51
+ setAuthError: () => setAuthError,
49
52
  setNativeSession: () => setNativeSession,
50
53
  useAuthConfig: () => useAuthConfig,
54
+ useAuthError: () => useAuthError,
51
55
  useKeycloak: () => useKeycloak,
52
56
  useSession: () => useSession,
53
57
  useTokensFromQuery: () => useTokensFromQuery,
@@ -527,8 +531,9 @@ var BaseKeycloak = class {
527
531
  this._clear();
528
532
  if (this._keycloakClient) {
529
533
  await this._keycloakClient.login(options);
530
- } else {
531
- await this._login?.(options);
534
+ } else if (this._login) {
535
+ await this._login(options);
536
+ return;
532
537
  }
533
538
  this._sync();
534
539
  }
@@ -680,7 +685,7 @@ var Logger = class extends BaseLogger {
680
685
  var logger = new Logger();
681
686
 
682
687
  // src/provider/AfterAuth.tsx
683
- var import_react8 = require("react");
688
+ var import_react9 = require("react");
684
689
 
685
690
  // src/frappeToken.native.ts
686
691
  var import_react_native3 = require("react-native");
@@ -718,6 +723,32 @@ async function requestAccessToken(providerId, send, userId) {
718
723
  return second;
719
724
  }
720
725
 
726
+ // src/session/authError.ts
727
+ var import_react8 = require("react");
728
+ var error;
729
+ var listeners = /* @__PURE__ */ new Set();
730
+ var AuthTimeoutError = class extends Error {
731
+ constructor(timeoutMs = 1e4) {
732
+ super(`Authentication request timed out after ${timeoutMs}ms`);
733
+ this.name = "AuthTimeoutError";
734
+ }
735
+ };
736
+ function setAuthError(next) {
737
+ if (error === next) return;
738
+ error = next;
739
+ for (const listener of listeners) listener();
740
+ }
741
+ function getAuthError() {
742
+ return error;
743
+ }
744
+ function subscribe(listener) {
745
+ listeners.add(listener);
746
+ return () => listeners.delete(listener);
747
+ }
748
+ function useAuthError() {
749
+ return (0, import_react8.useSyncExternalStore)(subscribe, getAuthError, getAuthError);
750
+ }
751
+
721
752
  // src/betterAuth/expoAuthFlow.native.ts
722
753
  try {
723
754
  WebBrowser.maybeCompleteAuthSession?.();
@@ -858,24 +889,50 @@ var activeFlow = null;
858
889
  function getActiveExpoAuthFlow() {
859
890
  return activeFlow;
860
891
  }
861
- function createExpoAuthFlow(baseURL, scheme) {
892
+ function createExpoAuthFlow(baseURL, scheme, options) {
862
893
  const base = baseURL.replace(/\/$/, "");
863
894
  const origin = () => Linking.createURL("/", scheme ? { scheme } : void 0);
864
895
  async function authFetch(path, init) {
865
- const cookie = cookieHeader();
866
- const res = await fetch(`${base}/api/auth${path}`, {
867
- ...init,
868
- credentials: "omit",
869
- headers: {
870
- "Content-Type": "application/json",
871
- ...cookie ? { cookie } : {},
872
- "expo-origin": origin(),
873
- "x-skip-oauth-proxy": "true",
874
- ...init?.headers
875
- }
896
+ const controller = new AbortController();
897
+ const timeoutMs = options?.timeoutMs ?? 1e4;
898
+ let timer;
899
+ const deadline = new Promise((_resolve, reject) => {
900
+ timer = setTimeout(() => {
901
+ reject(new AuthTimeoutError(timeoutMs));
902
+ controller.abort();
903
+ }, timeoutMs);
876
904
  });
877
- absorbSetCookie(res.headers.get("set-cookie"));
878
- return res;
905
+ try {
906
+ const buffered = await Promise.race([
907
+ (async () => {
908
+ const cookie = cookieHeader();
909
+ const response = await fetch(`${base}/api/auth${path}`, {
910
+ ...init,
911
+ signal: controller.signal,
912
+ credentials: "omit",
913
+ headers: {
914
+ "Content-Type": "application/json",
915
+ ...cookie ? { cookie } : {},
916
+ "expo-origin": origin(),
917
+ "x-skip-oauth-proxy": "true",
918
+ ...init?.headers
919
+ }
920
+ });
921
+ const text = await response.text();
922
+ return { response, text };
923
+ })(),
924
+ deadline
925
+ ]);
926
+ absorbSetCookie(buffered.response.headers.get("set-cookie"));
927
+ return {
928
+ status: buffered.response.status,
929
+ ok: buffered.response.ok,
930
+ text: buffered.text,
931
+ json: () => buffered.text.trim() ? JSON.parse(buffered.text) : null
932
+ };
933
+ } finally {
934
+ clearTimeout(timer);
935
+ }
879
936
  }
880
937
  const flow = {
881
938
  async signIn(provider, callbackURL) {
@@ -885,10 +942,10 @@ function createExpoAuthFlow(baseURL, scheme) {
885
942
  body: JSON.stringify({ provider, callbackURL: to })
886
943
  });
887
944
  if (!res.ok) {
888
- const body = await res.text().catch(() => "");
945
+ const body = res.text;
889
946
  throw new Error(`sign-in failed (${res.status}): ${body.slice(0, 200)}`);
890
947
  }
891
- const data = await res.json();
948
+ const data = res.json();
892
949
  if (!data?.url) throw new Error("sign-in response had no authorization url");
893
950
  const params = new URLSearchParams({ authorizationURL: data.url });
894
951
  const oauthState = getOAuthState();
@@ -907,28 +964,31 @@ function createExpoAuthFlow(baseURL, scheme) {
907
964
  postLogoutRedirectUri || Linking.createURL("/"),
908
965
  "signed-out"
909
966
  );
967
+ let missingSso = false;
910
968
  try {
911
969
  const res = await authFetch(
912
970
  `/sign-out/sso?mode=json&callbackURL=${encodeURIComponent(to)}`,
913
971
  { method: "GET" }
914
972
  );
973
+ missingSso = res.status === 404 || res.status === 405;
915
974
  if (!res.ok) throw new Error(`sign-out/sso failed (${res.status})`);
916
- const data = await res.json().catch(() => null);
975
+ const data = res.json();
917
976
  if (data?.redirect && data.url) {
918
- await openAuthBrowser(data.url, to.split("?")[0], { timeoutMs: 12e4 }).catch(
919
- () => void 0
920
- );
977
+ await openAuthBrowser(data.url, to.split("?")[0], { timeoutMs: 12e4 });
921
978
  }
922
- } catch {
923
- await authFetch("/sign-out", { method: "POST", body: "{}" }).catch(() => void 0);
979
+ } catch (error2) {
980
+ const fallback = await authFetch("/sign-out", { method: "POST", body: "{}" });
981
+ if (!fallback.ok) throw new Error(`sign-out failed (${fallback.status})`);
982
+ if (!missingSso) throw error2;
924
983
  } finally {
925
984
  writeJar({});
926
985
  }
927
986
  },
928
987
  async getSession() {
929
988
  const res = await authFetch("/get-session");
930
- if (!res.ok) return null;
931
- const data = await res.json().catch(() => null);
989
+ if (res.status === 401) return null;
990
+ if (!res.ok) throw new Error(`get-session failed (${res.status})`);
991
+ const data = res.json();
932
992
  return data && Object.keys(data).length ? data : null;
933
993
  },
934
994
  async getAccessToken(providerId) {
@@ -938,7 +998,15 @@ function createExpoAuthFlow(baseURL, scheme) {
938
998
  method: "POST",
939
999
  body: JSON.stringify(body)
940
1000
  });
941
- payload = await response.json().catch(() => null);
1001
+ if (response.status >= 500) {
1002
+ throw new Error(`get-access-token failed (${response.status})`);
1003
+ }
1004
+ try {
1005
+ payload = response.json();
1006
+ } catch (error2) {
1007
+ if (response.ok) throw error2;
1008
+ payload = null;
1009
+ }
942
1010
  return { status: response.status, body: payload };
943
1011
  });
944
1012
  if (res.status < 200 || res.status >= 300) return null;
@@ -1006,7 +1074,7 @@ function AfterAuth({ children, loadingComponent: _loadingComponent }) {
1006
1074
  const authConfig = useAuthConfig();
1007
1075
  const authStore2 = useAuthStore();
1008
1076
  const keycloak = useKeycloak();
1009
- (0, import_react8.useEffect)(() => {
1077
+ (0, import_react9.useEffect)(() => {
1010
1078
  if (!persist || !keycloak?.authenticated) return;
1011
1079
  if (keycloak.token) {
1012
1080
  authStore2.setTokens({
@@ -1025,173 +1093,234 @@ function AfterAuth({ children, loadingComponent: _loadingComponent }) {
1025
1093
  keycloak?.idToken,
1026
1094
  keycloak?.refreshToken
1027
1095
  ]);
1028
- (0, import_react8.useEffect)(() => {
1096
+ (0, import_react9.useEffect)(() => {
1029
1097
  if (authConfig.debug && keycloak?.token) {
1030
1098
  logger.debug("token", keycloak.token);
1031
1099
  }
1032
1100
  }, [authConfig.debug, keycloak?.token]);
1033
- (0, import_react8.useEffect)(() => {
1101
+ (0, import_react9.useEffect)(() => {
1034
1102
  if (authConfig.debug && keycloak?.idToken) {
1035
1103
  logger.debug("idToken", keycloak.idToken);
1036
1104
  }
1037
1105
  }, [authConfig.debug, keycloak?.idToken]);
1038
- (0, import_react8.useEffect)(() => {
1106
+ (0, import_react9.useEffect)(() => {
1039
1107
  if (authConfig.debug && keycloak?.refreshToken) {
1040
1108
  logger.debug("refreshToken", keycloak.refreshToken);
1041
1109
  }
1042
1110
  }, [authConfig.debug, keycloak?.refreshToken]);
1043
- (0, import_react8.useEffect)(() => {
1111
+ (0, import_react9.useEffect)(() => {
1044
1112
  if (authConfig.debug && keycloak?.authenticated) {
1045
1113
  logger.debug("authenticated", keycloak.authenticated);
1046
1114
  }
1047
1115
  }, [authConfig.debug, keycloak?.authenticated]);
1048
- (0, import_react8.useEffect)(() => {
1116
+ (0, import_react9.useEffect)(() => {
1049
1117
  if (authConfig.debug && keycloak === null) {
1050
1118
  logger.debug("keycloak disabled");
1051
1119
  }
1052
1120
  }, [authConfig.debug, keycloak]);
1053
- (0, import_react8.useEffect)(() => watchKeycloakBearerTokenRevalidate(), []);
1121
+ (0, import_react9.useEffect)(() => watchKeycloakBearerTokenRevalidate(), []);
1054
1122
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
1055
1123
  }
1056
1124
 
1057
1125
  // src/provider/authProvider/index.native.tsx
1058
- var import_react10 = require("react");
1059
- var import_react_native5 = require("react-native");
1060
- var Linking2 = __toESM(require("expo-linking"));
1061
-
1062
- // src/Loading.tsx
1126
+ var import_react11 = require("react");
1063
1127
  var import_react_native4 = require("react-native");
1064
- var import_jsx_runtime3 = require("react/jsx-runtime");
1065
- function Loading({ loadingComponent }) {
1066
- const { debug } = useAuthConfig();
1067
- const LoadingComponent = loadingComponent;
1068
- if (typeof LoadingComponent === "undefined") {
1069
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: [
1070
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.ActivityIndicator, {}),
1071
- debug ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.Text, { children: "loading" }) : null
1072
- ] });
1073
- }
1074
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoadingComponent, {});
1075
- }
1128
+ var Linking2 = __toESM(require("expo-linking"));
1076
1129
 
1077
1130
  // src/session/index.native.ts
1078
- var import_react9 = require("react");
1131
+ var import_react10 = require("react");
1079
1132
  var state = { session: null, status: "loading" };
1080
- var listeners = /* @__PURE__ */ new Set();
1133
+ var listeners2 = /* @__PURE__ */ new Set();
1081
1134
  function setNativeSession(session, status) {
1082
1135
  state = {
1083
1136
  session,
1084
1137
  status: status ?? (session?.user ? "authenticated" : "unauthenticated")
1085
1138
  };
1086
- for (const l of listeners) l();
1139
+ for (const l of listeners2) l();
1087
1140
  }
1088
- function subscribe(listener) {
1089
- listeners.add(listener);
1090
- return () => listeners.delete(listener);
1141
+ function subscribe2(listener) {
1142
+ listeners2.add(listener);
1143
+ return () => listeners2.delete(listener);
1091
1144
  }
1092
1145
  async function getSession() {
1093
1146
  return state.session;
1094
1147
  }
1095
1148
  function useSession(_options) {
1096
- return (0, import_react9.useSyncExternalStore)(
1097
- subscribe,
1149
+ const session = (0, import_react10.useSyncExternalStore)(
1150
+ subscribe2,
1098
1151
  () => state,
1099
1152
  () => state
1100
1153
  );
1154
+ const error2 = useAuthError();
1155
+ return { ...session, error: error2 };
1101
1156
  }
1102
1157
 
1103
1158
  // src/provider/authProvider/index.native.tsx
1104
- var import_jsx_runtime4 = require("react/jsx-runtime");
1159
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1160
+ function createController(config, disabled, notify) {
1161
+ const flow = disabled ? null : createExpoAuthFlow(
1162
+ rewriteLoopbackHostForNative(config.betterAuthBaseUrl || "http://localhost:8000"),
1163
+ config.expoScheme
1164
+ );
1165
+ let active = true;
1166
+ let sequence = 0;
1167
+ let interactive = false;
1168
+ let session = null;
1169
+ const current = (request) => active && request === sequence;
1170
+ const controller = {
1171
+ keycloak: makeKeycloak(null),
1172
+ loading: !disabled,
1173
+ start() {
1174
+ active = true;
1175
+ if (!flow) {
1176
+ publish(null);
1177
+ } else if (!interactive) {
1178
+ void refresh().catch(() => void 0);
1179
+ }
1180
+ },
1181
+ stop() {
1182
+ active = false;
1183
+ sequence++;
1184
+ interactive = false;
1185
+ },
1186
+ refresh
1187
+ };
1188
+ function makeKeycloak(next) {
1189
+ const keycloak = new Keycloak(config, void 0, void 0, void 0, login, logout);
1190
+ if (next?.user) {
1191
+ keycloak.authenticated = true;
1192
+ keycloak.subject = next.user.id;
1193
+ keycloak.email = next.user.email ?? void 0;
1194
+ keycloak.username = next.user.name ?? void 0;
1195
+ }
1196
+ return keycloak;
1197
+ }
1198
+ function publish(next, error2) {
1199
+ session = next;
1200
+ controller.keycloak = makeKeycloak(next);
1201
+ controller.loading = false;
1202
+ setAuthError(error2);
1203
+ setNativeSession(next);
1204
+ notify();
1205
+ }
1206
+ function begin() {
1207
+ const request = ++sequence;
1208
+ controller.loading = true;
1209
+ setAuthError();
1210
+ setNativeSession(session, "loading");
1211
+ notify();
1212
+ return request;
1213
+ }
1214
+ async function probe(request) {
1215
+ const next = await flow.getSession();
1216
+ if (!current(request)) return;
1217
+ publish(
1218
+ next?.user ? {
1219
+ user: {
1220
+ id: next.user.id,
1221
+ name: next.user.name ?? null,
1222
+ email: next.user.email ?? null
1223
+ }
1224
+ } : null
1225
+ );
1226
+ }
1227
+ function fail(request, cause) {
1228
+ const error2 = cause instanceof Error ? cause : new Error(String(cause));
1229
+ if (current(request)) publish(null, error2);
1230
+ throw error2;
1231
+ }
1232
+ async function refresh() {
1233
+ if (!active || !flow || interactive) return;
1234
+ const request = begin();
1235
+ try {
1236
+ await probe(request);
1237
+ } catch (error2) {
1238
+ fail(request, error2);
1239
+ }
1240
+ }
1241
+ async function login(options) {
1242
+ if (!active || !flow) return void 0;
1243
+ interactive = true;
1244
+ const request = begin();
1245
+ try {
1246
+ await flow.signIn("keycloak", options.redirectUri || Linking2.createURL("/"));
1247
+ if (!current(request)) return void 0;
1248
+ clearKeycloakBearerToken();
1249
+ await probe(request);
1250
+ } catch (error2) {
1251
+ fail(request, error2);
1252
+ } finally {
1253
+ if (current(request)) interactive = false;
1254
+ }
1255
+ return void 0;
1256
+ }
1257
+ async function logout(options) {
1258
+ if (!active || !flow) return void 0;
1259
+ interactive = true;
1260
+ const request = ++sequence;
1261
+ clearKeycloakBearerToken();
1262
+ publish(null);
1263
+ try {
1264
+ const redirectUri = options.redirectUri?.includes("://") ? options.redirectUri : Linking2.createURL("/");
1265
+ await flow.signOut(redirectUri);
1266
+ } catch (error2) {
1267
+ fail(request, error2);
1268
+ } finally {
1269
+ if (current(request)) {
1270
+ clearKeycloakBearerToken();
1271
+ interactive = false;
1272
+ }
1273
+ }
1274
+ return void 0;
1275
+ }
1276
+ return controller;
1277
+ }
1105
1278
  function AuthProvider({
1106
1279
  children,
1107
1280
  disabled,
1108
1281
  keycloakConfig,
1109
- loadingComponent
1282
+ loadingComponent: LoadingComponent
1110
1283
  }) {
1111
- const [keycloak, setKeycloak] = (0, import_react10.useState)();
1112
- const [isLoading, setIsLoading] = (0, import_react10.useState)(true);
1113
- const serverBaseUrl = (0, import_react10.useMemo)(() => {
1114
- return rewriteLoopbackHostForNative(
1115
- keycloakConfig.betterAuthBaseUrl || "http://localhost:8000"
1116
- );
1117
- }, [keycloakConfig]);
1118
- const scheme = (0, import_react10.useMemo)(() => keycloakConfig.expoScheme, [keycloakConfig]);
1119
- const flow = (0, import_react10.useMemo)(
1120
- () => disabled ? null : createExpoAuthFlow(serverBaseUrl, scheme),
1121
- [disabled, serverBaseUrl, scheme]
1284
+ const [, setRevision] = (0, import_react11.useState)(0);
1285
+ const { url, realm, clientId, publicClientId, betterAuthBaseUrl, expoScheme } = keycloakConfig;
1286
+ const scopes = JSON.stringify(keycloakConfig.scopes);
1287
+ const controller = (0, import_react11.useMemo)(
1288
+ () => createController(
1289
+ {
1290
+ url,
1291
+ realm,
1292
+ clientId,
1293
+ publicClientId,
1294
+ betterAuthBaseUrl,
1295
+ expoScheme,
1296
+ scopes: scopes ? JSON.parse(scopes) : void 0
1297
+ },
1298
+ disabled,
1299
+ () => setRevision((revision) => revision + 1)
1300
+ ),
1301
+ [url, realm, clientId, publicClientId, betterAuthBaseUrl, expoScheme, scopes, disabled]
1122
1302
  );
1123
- (0, import_react10.useEffect)(() => {
1124
- if (disabled || !flow) {
1125
- setIsLoading(false);
1126
- return;
1127
- }
1128
- let alive = true;
1129
- const refresh = async () => {
1130
- let session = null;
1131
- try {
1132
- session = await flow.getSession();
1133
- } catch (err) {
1134
- console.error("[keycloak] native session check failed:", err);
1135
- }
1136
- const _keycloak = new Keycloak(
1137
- keycloakConfig,
1138
- void 0,
1139
- void 0,
1140
- void 0,
1141
- async (options) => {
1142
- await flow.signIn("keycloak", options.redirectUri || Linking2.createURL("/"));
1143
- clearKeycloakBearerToken();
1144
- await refresh();
1145
- return void 0;
1146
- },
1147
- async (options) => {
1148
- const redirectUri = options.redirectUri && options.redirectUri.includes("://") ? options.redirectUri : Linking2.createURL("/");
1149
- await flow.signOut(redirectUri);
1150
- clearKeycloakBearerToken();
1151
- await refresh();
1152
- return void 0;
1153
- }
1154
- );
1155
- if (session?.user) {
1156
- _keycloak.authenticated = true;
1157
- _keycloak.email = session.user.email || void 0;
1158
- _keycloak.username = session.user.name || void 0;
1159
- _keycloak.subject = session.user.id;
1160
- }
1161
- if (!alive) return;
1162
- setNativeSession(
1163
- session?.user ? {
1164
- user: {
1165
- id: session.user.id,
1166
- name: session.user.name ?? null,
1167
- email: session.user.email ?? null
1168
- }
1169
- } : null
1170
- );
1171
- setKeycloak(_keycloak);
1172
- };
1173
- refresh().finally(() => {
1174
- if (alive) setIsLoading(false);
1303
+ (0, import_react11.useEffect)(() => {
1304
+ if (disabled) return;
1305
+ controller.start();
1306
+ const appSub = import_react_native4.AppState.addEventListener("change", (next) => {
1307
+ if (next === "active") void controller.refresh().catch(() => void 0);
1175
1308
  });
1176
- const onAppState = (next) => {
1177
- if (next === "active") refresh().catch(() => void 0);
1178
- };
1179
- const appSub = import_react_native5.AppState.addEventListener("change", onAppState);
1180
1309
  return () => {
1181
- alive = false;
1310
+ controller.stop();
1182
1311
  appSub.remove();
1183
1312
  };
1184
- }, [disabled, flow, keycloakConfig]);
1185
- if (disabled) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
1186
- if (isLoading || !keycloak) {
1187
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Loading, { loadingComponent });
1188
- }
1189
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeycloakConfigContext.Provider, { value: keycloakConfig, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeycloakContext.Provider, { value: keycloak, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AfterAuth, { children }) }) });
1313
+ }, [controller, disabled]);
1314
+ if (disabled) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_jsx_runtime3.Fragment, { children });
1315
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(KeycloakConfigContext.Provider, { value: controller.keycloak.config, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(KeycloakContext.Provider, { value: controller.keycloak, children: [
1316
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AfterAuth, { children }),
1317
+ controller.loading && LoadingComponent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoadingComponent, {}) : null
1318
+ ] }) });
1190
1319
  }
1191
1320
 
1192
1321
  // src/provider/KeycloakProvider.tsx
1193
- var import_react11 = require("react");
1194
- var import_jsx_runtime5 = require("react/jsx-runtime");
1322
+ var import_react12 = require("react");
1323
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1195
1324
  function KeycloakProvider({
1196
1325
  baseUrl,
1197
1326
  betterAuthBaseUrl,
@@ -1199,28 +1328,34 @@ function KeycloakProvider({
1199
1328
  clientId,
1200
1329
  expoScheme,
1201
1330
  loginRedirectUri,
1331
+ loadingComponent,
1202
1332
  debug,
1203
1333
  disabled,
1204
1334
  iframeSso,
1205
1335
  publicClientId,
1206
1336
  realm
1207
1337
  }) {
1208
- const authConfig = (0, import_react11.useMemo)(
1338
+ const authConfig = (0, import_react12.useMemo)(
1209
1339
  () => ({ debug, disabled, iframeSso, loginRedirectUri }),
1210
1340
  [debug, disabled, iframeSso, loginRedirectUri]
1211
1341
  );
1212
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AuthConfigContext.Provider, { value: authConfig, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1342
+ const keycloakConfig = (0, import_react12.useMemo)(
1343
+ () => ({
1344
+ clientId: clientId || "app",
1345
+ publicClientId,
1346
+ realm: realm || "main",
1347
+ url: baseUrl ?? "",
1348
+ betterAuthBaseUrl,
1349
+ expoScheme
1350
+ }),
1351
+ [clientId, publicClientId, realm, baseUrl, betterAuthBaseUrl, expoScheme]
1352
+ );
1353
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AuthConfigContext.Provider, { value: authConfig, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1213
1354
  AuthProvider,
1214
1355
  {
1215
1356
  disabled,
1216
- keycloakConfig: {
1217
- clientId: clientId || "app",
1218
- publicClientId,
1219
- realm: realm || "main",
1220
- url: baseUrl ?? "",
1221
- betterAuthBaseUrl,
1222
- expoScheme
1223
- },
1357
+ keycloakConfig,
1358
+ loadingComponent,
1224
1359
  children
1225
1360
  }
1226
1361
  ) });