oidc-spa 8.1.4 → 8.1.5

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 (39) hide show
  1. package/README.md +5 -7
  2. package/core/createOidc.js +85 -35
  3. package/core/createOidc.js.map +1 -1
  4. package/core/diagnostic.d.ts +1 -0
  5. package/core/diagnostic.js +5 -4
  6. package/core/diagnostic.js.map +1 -1
  7. package/core/isNewBrowserSession.d.ts +1 -1
  8. package/core/isNewBrowserSession.js +2 -2
  9. package/core/isNewBrowserSession.js.map +1 -1
  10. package/core/loginOrGoToAuthServer.d.ts +3 -2
  11. package/core/loginOrGoToAuthServer.js +45 -29
  12. package/core/loginOrGoToAuthServer.js.map +1 -1
  13. package/core/loginSilent.d.ts +1 -0
  14. package/core/loginSilent.js +10 -1
  15. package/core/loginSilent.js.map +1 -1
  16. package/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
  17. package/esm/core/createOidc.js +86 -36
  18. package/esm/core/createOidc.js.map +1 -1
  19. package/esm/core/diagnostic.d.ts +1 -0
  20. package/esm/core/diagnostic.js +1 -1
  21. package/esm/core/diagnostic.js.map +1 -1
  22. package/esm/core/isNewBrowserSession.d.ts +1 -1
  23. package/esm/core/isNewBrowserSession.js +2 -2
  24. package/esm/core/isNewBrowserSession.js.map +1 -1
  25. package/esm/core/loginOrGoToAuthServer.d.ts +3 -2
  26. package/esm/core/loginOrGoToAuthServer.js +44 -28
  27. package/esm/core/loginOrGoToAuthServer.js.map +1 -1
  28. package/esm/core/loginSilent.d.ts +1 -0
  29. package/esm/core/loginSilent.js +10 -1
  30. package/esm/core/loginSilent.js.map +1 -1
  31. package/esm/core/ongoingLoginOrRefreshProcesses.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/core/createOidc.ts +110 -38
  34. package/src/core/diagnostic.ts +2 -2
  35. package/src/core/isNewBrowserSession.ts +3 -3
  36. package/src/core/loginOrGoToAuthServer.ts +59 -31
  37. package/src/core/loginSilent.ts +13 -1
  38. package/src/core/ongoingLoginOrRefreshProcesses.ts +8 -0
  39. package/vendor/backend/tsafe.js +1 -1
@@ -38,7 +38,7 @@ import { createEvt } from "../tools/Evt";
38
38
  import { getHaveSharedParentDomain } from "../tools/haveSharedParentDomain";
39
39
  import {
40
40
  createLoginOrGoToAuthServer,
41
- getPrSafelyRestoredFromBfCacheAfterLoginBackNavigation
41
+ getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError
42
42
  } from "./loginOrGoToAuthServer";
43
43
  import { createEphemeralSessionStorage } from "../tools/EphemeralSessionStorage";
44
44
  import {
@@ -49,6 +49,8 @@ import { createGetIsNewBrowserSession } from "./isNewBrowserSession";
49
49
  import { getIsOnline } from "../tools/getIsOnline";
50
50
  import { isKeycloak } from "../keycloak/isKeycloak";
51
51
  import { INFINITY_TIME } from "../tools/INFINITY_TIME";
52
+ import type { WELL_KNOWN_PATH } from "./diagnostic";
53
+ import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
52
54
 
53
55
  // NOTE: Replaced at build time
54
56
  const VERSION = "{{OIDC_SPA_VERSION}}";
@@ -454,7 +456,7 @@ export async function createOidc_nonMemoized<
454
456
  metadata: __metadata
455
457
  });
456
458
 
457
- const evtIsUserLoggedIn = createEvt<boolean>();
459
+ const evtInitializationOutcomeUserNotLoggedIn = createEvt<void>();
458
460
 
459
461
  const { loginOrGoToAuthServer } = createLoginOrGoToAuthServer({
460
462
  configId,
@@ -463,23 +465,13 @@ export async function createOidc_nonMemoized<
463
465
  getExtraQueryParams,
464
466
  getExtraTokenParams,
465
467
  homeUrl: homeUrlAndRedirectUri,
466
- evtIsUserLoggedIn,
468
+ evtInitializationOutcomeUserNotLoggedIn,
467
469
  log
468
470
  });
469
471
 
470
472
  const { getIsNewBrowserSession } = createGetIsNewBrowserSession({
471
473
  configId,
472
- evtUserNotLoggedIn: (() => {
473
- const evt = createEvt<void>();
474
-
475
- evtIsUserLoggedIn.subscribe(isUserLoggedIn => {
476
- if (!isUserLoggedIn) {
477
- evt.post();
478
- }
479
- });
480
-
481
- return evt;
482
- })()
474
+ evtInitializationOutcomeUserNotLoggedIn
483
475
  });
484
476
 
485
477
  const { completeLoginOrRefreshProcess } = await startLoginOrRefreshProcess();
@@ -673,6 +665,8 @@ export async function createOidc_nonMemoized<
673
665
  }
674
666
  }
675
667
 
668
+ // NOTE: We almost never persist tokens, we have to only to support edge case
669
+ // of multiple oidc instance in a single App with no iframe support.
676
670
  restore_from_session_storage: {
677
671
  if (isUserStoreInMemoryOnly) {
678
672
  break restore_from_session_storage;
@@ -744,6 +738,20 @@ export async function createOidc_nonMemoized<
744
738
  }
745
739
 
746
740
  if (!canUseIframe) {
741
+ if (
742
+ !(await getIsValidRemoteJson(
743
+ `${issuerUri}${id<typeof WELL_KNOWN_PATH>(
744
+ "/.well-known/openid-configuration"
745
+ )}`
746
+ ))
747
+ ) {
748
+ return (
749
+ await import("./diagnostic")
750
+ ).createWellKnownOidcConfigurationEndpointUnreachableInitializationError({
751
+ issuerUri
752
+ });
753
+ }
754
+
747
755
  break actual_silent_signin;
748
756
  }
749
757
 
@@ -758,7 +766,8 @@ export async function createOidc_nonMemoized<
758
766
  transformUrlBeforeRedirect,
759
767
  getExtraQueryParams,
760
768
  getExtraTokenParams,
761
- autoLogin
769
+ autoLogin,
770
+ log
762
771
  });
763
772
 
764
773
  assert(result_loginSilent.outcome !== "token refreshed using refresh token", "876995");
@@ -832,11 +841,12 @@ export async function createOidc_nonMemoized<
832
841
  completeLoginOrRefreshProcess();
833
842
 
834
843
  if (autoLogin && persistedAuthState !== "logged in") {
835
- evtIsUserLoggedIn.post(false);
844
+ evtInitializationOutcomeUserNotLoggedIn.post();
836
845
  }
837
846
 
838
847
  await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
839
- prUnlock: new Promise<never>(() => {})
848
+ prUnlock:
849
+ getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError()
840
850
  });
841
851
 
842
852
  if (persistedAuthState === "logged in") {
@@ -845,7 +855,9 @@ export async function createOidc_nonMemoized<
845
855
  });
846
856
  }
847
857
 
848
- await loginOrGoToAuthServer({
858
+ const dCantFetchWellKnownEndpointOrNever = new Deferred<void | never>();
859
+
860
+ loginOrGoToAuthServer({
849
861
  action: "login",
850
862
  doForceReloadOnBfCache: true,
851
863
  redirectUrl: getRootRelativeOriginalLocationHref(),
@@ -864,9 +876,20 @@ export async function createOidc_nonMemoized<
864
876
  }
865
877
 
866
878
  return "ensure no interaction";
867
- })()
879
+ })(),
880
+ onCantFetchWellKnownEndpointError: () => {
881
+ dCantFetchWellKnownEndpointOrNever.resolve();
882
+ }
883
+ });
884
+
885
+ await dCantFetchWellKnownEndpointOrNever.pr;
886
+
887
+ return (
888
+ await import("./diagnostic")
889
+ ).createFailedToFetchTokenEndpointInitializationError({
890
+ clientId,
891
+ issuerUri
868
892
  });
869
- assert(false, "321389");
870
893
  }
871
894
 
872
895
  if (authResponse_error !== undefined) {
@@ -913,7 +936,7 @@ export async function createOidc_nonMemoized<
913
936
  break not_loggedIn_case;
914
937
  }
915
938
 
916
- evtIsUserLoggedIn.post(false);
939
+ evtInitializationOutcomeUserNotLoggedIn.post();
917
940
 
918
941
  if (getPersistedAuthState({ configId }) !== "explicitly logged out") {
919
942
  persistAuthState({ configId, state: undefined });
@@ -970,7 +993,8 @@ export async function createOidc_nonMemoized<
970
993
  transformUrlBeforeRedirect
971
994
  }) => {
972
995
  await waitForAllOtherOngoingLoginOrRefreshProcessesToComplete({
973
- prUnlock: getPrSafelyRestoredFromBfCacheAfterLoginBackNavigation()
996
+ prUnlock:
997
+ getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError()
974
998
  });
975
999
 
976
1000
  return loginOrGoToAuthServer({
@@ -985,7 +1009,11 @@ export async function createOidc_nonMemoized<
985
1009
  interaction:
986
1010
  getPersistedAuthState({ configId }) === "explicitly logged out"
987
1011
  ? "ensure interaction"
988
- : "directly redirect if active session show login otherwise"
1012
+ : "directly redirect if active session show login otherwise",
1013
+ onCantFetchWellKnownEndpointError: () => {
1014
+ log?.("Login called but the auth server seems to be down..");
1015
+ alert("Authentication unavailable please try again later.");
1016
+ }
989
1017
  });
990
1018
  },
991
1019
  initializationError: undefined
@@ -1017,8 +1045,6 @@ export async function createOidc_nonMemoized<
1017
1045
 
1018
1046
  log?.("User is logged in");
1019
1047
 
1020
- evtIsUserLoggedIn.post(true);
1021
-
1022
1048
  let currentTokens = oidcClientTsUserToTokens({
1023
1049
  oidcClientTsUser: resultOfLoginProcess.oidcClientTsUser,
1024
1050
  decodedIdTokenSchema,
@@ -1198,7 +1224,16 @@ export async function createOidc_nonMemoized<
1198
1224
  extraQueryParams_local: undefined,
1199
1225
  transformUrlBeforeRedirect_local: undefined,
1200
1226
  doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
1201
- interaction: "directly redirect if active session show login otherwise"
1227
+ interaction: "directly redirect if active session show login otherwise",
1228
+ onCantFetchWellKnownEndpointError: () => {
1229
+ log?.(
1230
+ [
1231
+ "The auth server seems to be down while we needed to refresh the token",
1232
+ "with a full page redirect. Reloading the page"
1233
+ ].join(" ")
1234
+ );
1235
+ window.location.reload();
1236
+ }
1202
1237
  });
1203
1238
  assert(false, "136134");
1204
1239
  };
@@ -1229,14 +1264,20 @@ export async function createOidc_nonMemoized<
1229
1264
  transformUrlBeforeRedirect,
1230
1265
  getExtraQueryParams,
1231
1266
  getExtraTokenParams: () => extraTokenParams,
1232
- autoLogin
1267
+ autoLogin,
1268
+ log
1233
1269
  });
1234
1270
 
1235
1271
  if (result_loginSilent.outcome === "failure") {
1236
- completeLoginOrRefreshProcess();
1237
- // NOTE: This is a configuration or network error, okay to throw,
1238
- // this exception doesn't have to be handle if it fails it fails.
1239
- throw new Error(result_loginSilent.cause);
1272
+ log?.(
1273
+ [
1274
+ `Silent refresh of the token failed with ${result_loginSilent.cause}.`,
1275
+ `This isn't recoverable, reloading the page.`
1276
+ ].join(" ")
1277
+ );
1278
+ window.location.reload();
1279
+ await new Promise<never>(() => {});
1280
+ assert(false);
1240
1281
  }
1241
1282
 
1242
1283
  let oidcClientTsUser: OidcClientTsUser;
@@ -1420,7 +1461,11 @@ export async function createOidc_nonMemoized<
1420
1461
  action: "go to auth server",
1421
1462
  redirectUrl: redirectUrl ?? window.location.href,
1422
1463
  extraQueryParams_local: extraQueryParams,
1423
- transformUrlBeforeRedirect_local: transformUrlBeforeRedirect
1464
+ transformUrlBeforeRedirect_local: transformUrlBeforeRedirect,
1465
+ onCantFetchWellKnownEndpointError: () => {
1466
+ log?.("goToAuthServer called but the auth server seems to be down..");
1467
+ alert("Authentication unavailable please try again later.");
1468
+ }
1424
1469
  }),
1425
1470
  backFromAuthServer: resultOfLoginProcess.backFromAuthServer,
1426
1471
  isNewBrowserSession: (() => {
@@ -1493,12 +1538,12 @@ export async function createOidc_nonMemoized<
1493
1538
  });
1494
1539
  })();
1495
1540
 
1496
- (function scheduleRenew() {
1541
+ (function scheduleTokenRefreshToKeepSessionAlive() {
1497
1542
  if (!currentTokens.hasRefreshToken && !canUseIframe) {
1498
1543
  log?.(
1499
1544
  [
1500
- "Disabling token auto refresh mechanism because we",
1501
- "have no way to renew the tokens without a full page reload"
1545
+ "Session keep-alive disabled: no refresh token and no iframe support. ",
1546
+ "Result: once tokens expire, continuing requires full reload."
1502
1547
  ].join(" ")
1503
1548
  );
1504
1549
  return;
@@ -1508,7 +1553,34 @@ export async function createOidc_nonMemoized<
1508
1553
  currentTokens.refreshTokenExpirationTime !== undefined &&
1509
1554
  currentTokens.refreshTokenExpirationTime >= INFINITY_TIME
1510
1555
  ) {
1511
- log?.("The refresh_token never expires, disabling auto-renewal mechanism");
1556
+ const warningLines: string[] = [];
1557
+
1558
+ if (scopes.includes("offline_access")) {
1559
+ warningLines.push("offline_access scope was explicitly requested.");
1560
+ } else if (isKeycloak({ issuerUri })) {
1561
+ warningLines.push("Keycloak likely enabled offline_access by default.");
1562
+ }
1563
+
1564
+ if (warningLines.length > 0) {
1565
+ warningLines.push(
1566
+ ...[
1567
+ "Misconfiguration: offline_access is for native apps, not SPAs. ",
1568
+ "You lose SSO and users must log in after every reload."
1569
+ ]
1570
+ );
1571
+ }
1572
+
1573
+ const logMessage = [
1574
+ "Refresh token never expires → no need to ping server.",
1575
+ "The backend session will not expire.",
1576
+ ...warningLines
1577
+ ].join(" ");
1578
+
1579
+ if (warningLines.length > 0) {
1580
+ console.warn(`oidc-spa: ${logMessage}`);
1581
+ } else {
1582
+ log?.(logMessage);
1583
+ }
1512
1584
  return;
1513
1585
  }
1514
1586
 
@@ -1524,7 +1596,7 @@ export async function createOidc_nonMemoized<
1524
1596
  if (msBeforeExpiration <= RENEW_MS_BEFORE_EXPIRES) {
1525
1597
  log?.(
1526
1598
  [
1527
- "Disabling auto renew mechanism. We just got fresh tokens",
1599
+ "Session keep-alive disabled. We just got fresh tokens",
1528
1600
  (() => {
1529
1601
  switch (typeOfTheTokenWeGotTheTtlFrom) {
1530
1602
  case "refresh":
@@ -1608,7 +1680,7 @@ export async function createOidc_nonMemoized<
1608
1680
  const { unsubscribe: tokenChangeUnsubscribe } = oidc_loggedIn.subscribeToTokensChange(() => {
1609
1681
  clearTimeout(timer);
1610
1682
  tokenChangeUnsubscribe();
1611
- scheduleRenew();
1683
+ scheduleTokenRefreshToKeepSessionAlive();
1612
1684
  });
1613
1685
  })();
1614
1686
 
@@ -2,13 +2,13 @@ import { OidcInitializationError } from "./OidcInitializationError";
2
2
  import { isKeycloak, createKeycloakUtils } from "../keycloak";
3
3
  import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
4
4
 
5
+ export const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
6
+
5
7
  export async function createWellKnownOidcConfigurationEndpointUnreachableInitializationError(params: {
6
8
  issuerUri: string;
7
9
  }): Promise<OidcInitializationError> {
8
10
  const { issuerUri } = params;
9
11
 
10
- const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
11
-
12
12
  const commonFallbackMessagePart = [
13
13
  `The OIDC server is either down or the issuerUri you provided is incorrect.`,
14
14
  `You provided the issuerUri: ${issuerUri}`,
@@ -2,14 +2,14 @@ import type { NonPostableEvt } from "../tools/Evt";
2
2
 
3
3
  export function createGetIsNewBrowserSession(params: {
4
4
  configId: string;
5
- evtUserNotLoggedIn: NonPostableEvt<void>;
5
+ evtInitializationOutcomeUserNotLoggedIn: NonPostableEvt<void>;
6
6
  }) {
7
- const { configId, evtUserNotLoggedIn } = params;
7
+ const { configId, evtInitializationOutcomeUserNotLoggedIn } = params;
8
8
 
9
9
  const SESSION_STORAGE_KEY = `oidc-spa.subject-id:${configId}`;
10
10
 
11
11
  {
12
- const { unsubscribe } = evtUserNotLoggedIn.subscribe(() => {
12
+ const { unsubscribe } = evtInitializationOutcomeUserNotLoggedIn.subscribe(() => {
13
13
  unsubscribe();
14
14
  sessionStorage.removeItem(SESSION_STORAGE_KEY);
15
15
  });
@@ -7,6 +7,7 @@ import type { NonPostableEvt } from "../tools/Evt";
7
7
  import { createStatefulEvt } from "../tools/StatefulEvt";
8
8
  import { Deferred } from "../tools/Deferred";
9
9
  import { addOrUpdateSearchParam, getAllSearchParams } from "../tools/urlSearchParams";
10
+ import { getIsOnline } from "../tools/getIsOnline";
10
11
 
11
12
  const globalContext = {
12
13
  evtHasLoginBeenCalled: createStatefulEvt(() => false)
@@ -19,6 +20,7 @@ namespace Params {
19
20
  redirectUrl: string;
20
21
  extraQueryParams_local: Record<string, string | undefined> | undefined;
21
22
  transformUrlBeforeRedirect_local: ((url: string) => string) | undefined;
23
+ onCantFetchWellKnownEndpointError: () => void;
22
24
  };
23
25
 
24
26
  export type Login = Common & {
@@ -36,7 +38,7 @@ namespace Params {
36
38
  };
37
39
  }
38
40
 
39
- export function getPrSafelyRestoredFromBfCacheAfterLoginBackNavigation() {
41
+ export function getPrSafelyRestoredFromBfCacheAfterLoginBackNavigationOrInitializationError() {
40
42
  const dOut = new Deferred<void>();
41
43
 
42
44
  const { unsubscribe } = globalContext.evtHasLoginBeenCalled.subscribe(hasLoginBeenCalled => {
@@ -63,7 +65,7 @@ export function createLoginOrGoToAuthServer(params: {
63
65
  getExtraTokenParams: (() => Record<string, string | undefined>) | undefined;
64
66
 
65
67
  homeUrl: string;
66
- evtIsUserLoggedIn: NonPostableEvt<boolean>;
68
+ evtInitializationOutcomeUserNotLoggedIn: NonPostableEvt<void>;
67
69
  log: typeof console.log | undefined;
68
70
  }) {
69
71
  const {
@@ -76,12 +78,11 @@ export function createLoginOrGoToAuthServer(params: {
76
78
  getExtraTokenParams,
77
79
 
78
80
  homeUrl,
79
- evtIsUserLoggedIn,
81
+ evtInitializationOutcomeUserNotLoggedIn,
82
+
80
83
  log
81
84
  } = params;
82
85
 
83
- const LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN = `oidc-spa.login-redirect-initiated:${configId}`;
84
-
85
86
  let lastPublicUrl: string | undefined = undefined;
86
87
 
87
88
  async function loginOrGoToAuthServer(params: Params): Promise<never> {
@@ -89,11 +90,24 @@ export function createLoginOrGoToAuthServer(params: {
89
90
  redirectUrl: redirectUrl_params,
90
91
  extraQueryParams_local,
91
92
  transformUrlBeforeRedirect_local,
93
+ onCantFetchWellKnownEndpointError: onCantFetchWellKnownEndpointError_params,
92
94
  ...rest
93
95
  } = params;
96
+ let onCantFetchWellKnownEndpointError = onCantFetchWellKnownEndpointError_params;
94
97
 
95
98
  log?.(`Calling loginOrGoToAuthServer ${JSON.stringify(params, null, 2)}`);
96
99
 
100
+ delay_until_online: {
101
+ const { isOnline, prOnline } = getIsOnline();
102
+ if (isOnline) {
103
+ break delay_until_online;
104
+ }
105
+ log?.(
106
+ "The browser seem offline, waiting to get back a connection before proceeding to login"
107
+ );
108
+ await prOnline;
109
+ }
110
+
97
111
  login_specific_handling: {
98
112
  if (rest.action !== "login") {
99
113
  break login_specific_handling;
@@ -125,17 +139,23 @@ export function createLoginOrGoToAuthServer(params: {
125
139
 
126
140
  bf_cache_handling: {
127
141
  if (rest.doForceReloadOnBfCache) {
128
- window.removeEventListener("pageshow", event => {
142
+ const callback = (event: { persisted: boolean }) => {
129
143
  if (!event.persisted) {
130
144
  return;
131
145
  }
132
146
  location.reload();
133
- });
147
+ };
148
+
149
+ window.addEventListener("pageshow", callback);
150
+
151
+ onCantFetchWellKnownEndpointError = () => {
152
+ window.removeEventListener("pageshow", callback);
153
+ onCantFetchWellKnownEndpointError_params();
154
+ };
155
+
134
156
  break bf_cache_handling;
135
157
  }
136
158
 
137
- localStorage.setItem(LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN, "true");
138
-
139
159
  const callback = (event: { persisted: boolean }) => {
140
160
  if (!event.persisted) {
141
161
  return;
@@ -156,21 +176,19 @@ export function createLoginOrGoToAuthServer(params: {
156
176
  window.history.back();
157
177
  }
158
178
  } else {
159
- log?.("The current page doesn't require auth...");
160
-
161
- if (
162
- localStorage.getItem(LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN) === null
163
- ) {
164
- log?.("but the user is now authenticated, reloading the page");
165
- location.reload();
166
- } else {
167
- log?.("and the user doesn't seem to be authenticated, avoiding a reload");
168
- globalContext.evtHasLoginBeenCalled.current = false;
169
- }
179
+ // NOTE: We know the user is not logged in because login can only be called when not logged in.
180
+ log?.("The current page doesn't require auth, avoiding reloading the page");
181
+ globalContext.evtHasLoginBeenCalled.current = false;
170
182
  }
171
183
  };
172
184
 
173
185
  window.addEventListener("pageshow", callback);
186
+
187
+ onCantFetchWellKnownEndpointError = () => {
188
+ window.removeEventListener("pageshow", callback);
189
+ globalContext.evtHasLoginBeenCalled.current = false;
190
+ onCantFetchWellKnownEndpointError_params();
191
+ };
174
192
  }
175
193
  }
176
194
 
@@ -327,21 +345,31 @@ export function createLoginOrGoToAuthServer(params: {
327
345
  extraTokenParams:
328
346
  getExtraTokenParams === undefined ? undefined : noUndefined(getExtraTokenParams())
329
347
  })
330
- .then(() => new Promise<never>(() => {}));
348
+ .then(
349
+ () => new Promise<never>(() => {}),
350
+ (error: Error) => {
351
+ if (error.message === "Failed to fetch") {
352
+ // NOTE: See ./loginSilent for explanation.
353
+ onCantFetchWellKnownEndpointError();
354
+
355
+ return new Promise<never>(() => {});
356
+ }
357
+
358
+ // NOTE: Here, except error on our understanding there can't be any other
359
+ // error.
360
+ assert(false, "30442320");
361
+ }
362
+ );
331
363
  }
332
364
 
333
- const { unsubscribe } = evtIsUserLoggedIn.subscribe(isLoggedIn => {
365
+ const { unsubscribe } = evtInitializationOutcomeUserNotLoggedIn.subscribe(() => {
334
366
  unsubscribe();
335
367
 
336
- if (isLoggedIn) {
337
- localStorage.removeItem(LOCAL_STORAGE_KEY_TO_CLEAR_WHEN_USER_LOGGED_IN);
338
- } else {
339
- const realPushState = history.pushState.bind(history);
340
- history.pushState = function pushState(...args) {
341
- lastPublicUrl = window.location.href;
342
- return realPushState(...args);
343
- };
344
- }
368
+ const realPushState = history.pushState.bind(history);
369
+ history.pushState = function pushState(...args) {
370
+ lastPublicUrl = window.location.href;
371
+ return realPushState(...args);
372
+ };
345
373
  });
346
374
 
347
375
  return {
@@ -12,6 +12,7 @@ import { getIsDev } from "../tools/isDev";
12
12
  import { type AuthResponse } from "./AuthResponse";
13
13
  import { addOrUpdateSearchParam } from "../tools/urlSearchParams";
14
14
  import { initIframeMessageProtection } from "./iframeMessageProtection";
15
+ import { getIsOnline } from "../tools/getIsOnline";
15
16
 
16
17
  type ResultOfLoginSilent =
17
18
  | {
@@ -42,6 +43,7 @@ export async function loginSilent(params: {
42
43
 
43
44
  getExtraTokenParams: (() => Record<string, string | undefined>) | undefined;
44
45
  autoLogin: boolean;
46
+ log: typeof console.log | undefined;
45
47
  }): Promise<ResultOfLoginSilent> {
46
48
  const {
47
49
  oidcClientTsUserManager,
@@ -50,9 +52,19 @@ export async function loginSilent(params: {
50
52
  transformUrlBeforeRedirect,
51
53
  getExtraQueryParams,
52
54
  getExtraTokenParams,
53
- autoLogin
55
+ autoLogin,
56
+ log
54
57
  } = params;
55
58
 
59
+ delay_until_online: {
60
+ const { isOnline, prOnline } = getIsOnline();
61
+ if (isOnline) {
62
+ break delay_until_online;
63
+ }
64
+ log?.("The browser seems offline, waiting to get back a connection before proceeding to login");
65
+ await prOnline;
66
+ }
67
+
56
68
  const dResult = new Deferred<ResultOfLoginSilent>();
57
69
 
58
70
  const timeoutDelayMs: number = (() => {
@@ -32,6 +32,14 @@ export async function startLoginOrRefreshProcess(): Promise<{
32
32
  }
33
33
 
34
34
  export async function waitForAllOtherOngoingLoginOrRefreshProcessesToComplete(params: {
35
+ // NOTE: when providing
36
+ // - prUnlock: new Promise<never>(()=>{}); All the subsequent startLoginOrRefreshProcess()
37
+ // will never resolve: No lock can be acquired anymore in this app instance.
38
+ // - prUnlock: Promise.resolve(); The subsequent startLoginOrRefreshProcess() will resolve
39
+ // normally: The lock can be acquired again
40
+ // - prUnlock: prMightOrMightNotResolve. The lock will be acquirable again assuming the pr ever resolves.
41
+ //
42
+ // In any case it does not affect the call that are already running.
35
43
  prUnlock: Promise<void>;
36
44
  }): Promise<void> {
37
45
  const { prUnlock } = params;
@@ -1,2 +1,2 @@
1
- (()=>{"use strict";var e={720:function(e,r){var t,n=this&&this.__extends||(t=function(e,r){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,r){e.__proto__=r}||function(e,r){for(var t in r)Object.prototype.hasOwnProperty.call(r,t)&&(e[t]=r[t])},t(e,r)},function(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Class extends value "+String(r)+" is not a constructor or null");function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)});Object.defineProperty(r,"__esModule",{value:!0}),r.AssertionError=void 0,r.assert=function e(r,t){if(0===arguments.length&&(r=!0),void 0===i){if(!r){var n=new o("function"==typeof t?t():t);throw Error.captureStackTrace&&Error.captureStackTrace(n,e),n}}else i=void 0},r.is=function(e){var r={};if(void 0!==i)throw i=void 0,new Error(u);return i=r,Promise.resolve().then((function(){if(i===r)throw new Error(u)})),null};var o=function(e){function r(r){var t=this.constructor,n=e.call(this,"Wrong assertion encountered"+(r?': "'.concat(r,'"'):""))||this;return n.originalMessage=r,Object.setPrototypeOf(n,t.prototype),n.stack,n}return n(r,e),r}(Error);r.AssertionError=o;var i=void 0,u="Wrong usage of the `is` function refer to https://docs.tsafe.dev/is"},202:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.exclude=function(e){var r=e instanceof Object?function(r){return e.indexOf(r)<0}:function(r){return r!==e};return function(e){return r(e)}}},135:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.id=void 0,r.id=function(e){return e}},952:function(e,r){var t=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,t=r&&e[r],n=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(r,"__esModule",{value:!0}),r.isAmong=function(e,r){var n,o;try{for(var i=t(e),u=i.next();!u.done;u=i.next())if(u.value===r)return!0}catch(e){n={error:e}}finally{try{u&&!u.done&&(o=i.return)&&o.call(i)}finally{if(n)throw n.error}}return!1}}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}var n={};(()=>{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.exclude=e.isAmong=e.id=e.is=e.assert=void 0;var r=t(720);Object.defineProperty(e,"assert",{enumerable:!0,get:function(){return r.assert}}),Object.defineProperty(e,"is",{enumerable:!0,get:function(){return r.is}});var o=t(135);Object.defineProperty(e,"id",{enumerable:!0,get:function(){return o.id}});var i=t(952);Object.defineProperty(e,"isAmong",{enumerable:!0,get:function(){return i.isAmong}});var u=t(202);Object.defineProperty(e,"exclude",{enumerable:!0,get:function(){return u.exclude}})})(),module.exports=n})();
1
+ (()=>{"use strict";var e={720:function(e,r){var t,n=this&&this.__extends||(t=function(e,r){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,r){e.__proto__=r}||function(e,r){for(var t in r)Object.prototype.hasOwnProperty.call(r,t)&&(e[t]=r[t])},t(e,r)},function(e,r){if("function"!=typeof r&&null!==r)throw new TypeError("Class extends value "+String(r)+" is not a constructor or null");function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)});Object.defineProperty(r,"__esModule",{value:!0}),r.AssertionError=void 0,r.assert=function e(r,t){if(0===arguments.length&&(r=!0),void 0===i){if(!r){var n=new o("function"==typeof t?t():t);throw Error.captureStackTrace&&Error.captureStackTrace(n,e),n}}else i=void 0},r.is=function(e){var r={};if(void 0!==i)throw i=void 0,new Error(u);return i=r,Promise.resolve().then((function(){if(i===r)throw new Error(u)})),null};var o=function(e){function r(r){var t=this.constructor,n=e.call(this,"Wrong assertion encountered"+(r?': "'.concat(r,'"'):""))||this;return n.originalMessage=r,Object.setPrototypeOf(n,t.prototype),n}return n(r,e),r}(Error);r.AssertionError=o;var i=void 0,u="Wrong usage of the `is` function refer to https://docs.tsafe.dev/is"},202:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.exclude=function(e){var r=e instanceof Object?function(r){return e.indexOf(r)<0}:function(r){return r!==e};return function(e){return r(e)}}},135:(e,r)=>{Object.defineProperty(r,"__esModule",{value:!0}),r.id=void 0,r.id=function(e){return e}},952:function(e,r){var t=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,t=r&&e[r],n=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return e&&n>=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")};Object.defineProperty(r,"__esModule",{value:!0}),r.isAmong=function(e,r){var n,o;try{for(var i=t(e),u=i.next();!u.done;u=i.next())if(u.value===r)return!0}catch(e){n={error:e}}finally{try{u&&!u.done&&(o=i.return)&&o.call(i)}finally{if(n)throw n.error}}return!1}}},r={};function t(n){var o=r[n];if(void 0!==o)return o.exports;var i=r[n]={exports:{}};return e[n].call(i.exports,i,i.exports,t),i.exports}var n={};(()=>{var e=n;Object.defineProperty(e,"__esModule",{value:!0}),e.exclude=e.isAmong=e.id=e.is=e.assert=void 0;var r=t(720);Object.defineProperty(e,"assert",{enumerable:!0,get:function(){return r.assert}}),Object.defineProperty(e,"is",{enumerable:!0,get:function(){return r.is}});var o=t(135);Object.defineProperty(e,"id",{enumerable:!0,get:function(){return o.id}});var i=t(952);Object.defineProperty(e,"isAmong",{enumerable:!0,get:function(){return i.isAmong}});var u=t(202);Object.defineProperty(e,"exclude",{enumerable:!0,get:function(){return u.exclude}})})(),module.exports=n})();
2
2
  exports.__oidcSpaBundle = true;