oidc-spa 8.1.14 → 8.2.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 (111) hide show
  1. package/core/BASE_URL.d.ts +4 -0
  2. package/core/BASE_URL.js +12 -0
  3. package/core/BASE_URL.js.map +1 -0
  4. package/core/createOidc.d.ts +14 -7
  5. package/core/createOidc.js +38 -3
  6. package/core/createOidc.js.map +1 -1
  7. package/core/earlyInit.d.ts +1 -0
  8. package/core/earlyInit.js +8 -8
  9. package/core/earlyInit.js.map +1 -1
  10. package/core/prShouldLoadApp.d.ts +4 -0
  11. package/core/prShouldLoadApp.js +13 -0
  12. package/core/prShouldLoadApp.js.map +1 -0
  13. package/esm/core/BASE_URL.d.ts +4 -0
  14. package/esm/core/BASE_URL.js +8 -0
  15. package/esm/core/BASE_URL.js.map +1 -0
  16. package/esm/core/createOidc.d.ts +14 -7
  17. package/esm/core/createOidc.js +38 -3
  18. package/esm/core/createOidc.js.map +1 -1
  19. package/esm/core/earlyInit.d.ts +1 -0
  20. package/esm/core/earlyInit.js +8 -8
  21. package/esm/core/earlyInit.js.map +1 -1
  22. package/esm/core/prShouldLoadApp.d.ts +4 -0
  23. package/esm/core/prShouldLoadApp.js +9 -0
  24. package/esm/core/prShouldLoadApp.js.map +1 -0
  25. package/esm/keycloak/keycloak-js/Keycloak.d.ts +1 -1
  26. package/esm/keycloak/keycloak-js/Keycloak.js +1 -1
  27. package/esm/keycloak/keycloak-js/Keycloak.js.map +1 -1
  28. package/esm/mock/oidc.d.ts +3 -1
  29. package/esm/mock/oidc.js +4 -2
  30. package/esm/mock/oidc.js.map +1 -1
  31. package/esm/react-spa/apiBuilder.d.ts +12 -0
  32. package/esm/react-spa/apiBuilder.js +26 -0
  33. package/esm/react-spa/apiBuilder.js.map +1 -0
  34. package/esm/react-spa/createOidcSpaApi.d.ts +8 -0
  35. package/esm/react-spa/createOidcSpaApi.js +387 -0
  36. package/esm/react-spa/createOidcSpaApi.js.map +1 -0
  37. package/esm/react-spa/index.d.ts +2 -0
  38. package/esm/react-spa/index.js +3 -0
  39. package/esm/react-spa/index.js.map +1 -0
  40. package/esm/react-spa/types.d.ts +279 -0
  41. package/esm/react-spa/types.js +2 -0
  42. package/esm/react-spa/types.js.map +1 -0
  43. package/esm/tanstack-start/react/apiBuilder.js.map +1 -1
  44. package/esm/tanstack-start/react/createOidcSpaApi.js +13 -9
  45. package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -1
  46. package/esm/tanstack-start/react/types.d.ts +5 -4
  47. package/keycloak/keycloak-js/Keycloak.d.ts +1 -1
  48. package/keycloak/keycloak-js/Keycloak.js +1 -1
  49. package/keycloak/keycloak-js/Keycloak.js.map +1 -1
  50. package/mock/oidc.d.ts +3 -1
  51. package/mock/oidc.js +4 -2
  52. package/mock/oidc.js.map +1 -1
  53. package/package.json +5 -1
  54. package/react-spa/apiBuilder.d.ts +12 -0
  55. package/react-spa/apiBuilder.js +29 -0
  56. package/react-spa/apiBuilder.js.map +1 -0
  57. package/react-spa/createOidcSpaApi.d.ts +8 -0
  58. package/react-spa/createOidcSpaApi.js +423 -0
  59. package/react-spa/createOidcSpaApi.js.map +1 -0
  60. package/react-spa/index.d.ts +2 -0
  61. package/react-spa/index.js +6 -0
  62. package/react-spa/index.js.map +1 -0
  63. package/react-spa/types.d.ts +279 -0
  64. package/react-spa/types.js +3 -0
  65. package/react-spa/types.js.map +1 -0
  66. package/src/angular.ts +1 -1
  67. package/src/core/BASE_URL.ts +9 -0
  68. package/src/core/createOidc.ts +64 -10
  69. package/src/core/earlyInit.ts +14 -11
  70. package/src/core/prShouldLoadApp.ts +11 -0
  71. package/src/keycloak/keycloak-js/Keycloak.ts +2 -2
  72. package/src/mock/oidc.ts +9 -3
  73. package/src/react-spa/apiBuilder.ts +70 -0
  74. package/src/react-spa/createOidcSpaApi.tsx +527 -0
  75. package/src/react-spa/index.ts +4 -0
  76. package/src/react-spa/types.tsx +308 -0
  77. package/src/tanstack-start/react/apiBuilder.ts +0 -1
  78. package/src/tanstack-start/react/createOidcSpaApi.tsx +24 -20
  79. package/src/tanstack-start/react/types.tsx +3 -4
  80. package/src/vite-plugin/handleClientEntrypoint.ts +5 -5
  81. package/src/vite-plugin/manageOptimizedDeps.ts +64 -0
  82. package/src/vite-plugin/projectType.ts +18 -0
  83. package/src/vite-plugin/vite-plugin.ts +47 -11
  84. package/vite-plugin/handleClientEntrypoint.d.ts +2 -0
  85. package/vite-plugin/handleClientEntrypoint.js +3 -4
  86. package/vite-plugin/handleClientEntrypoint.js.map +1 -1
  87. package/vite-plugin/manageOptimizedDeps.d.ts +6 -0
  88. package/vite-plugin/{excludeModuleExportFromOptimizedDeps.js → manageOptimizedDeps.js} +42 -7
  89. package/vite-plugin/manageOptimizedDeps.js.map +1 -0
  90. package/vite-plugin/projectType.d.ts +4 -0
  91. package/vite-plugin/projectType.js +15 -0
  92. package/vite-plugin/projectType.js.map +1 -0
  93. package/vite-plugin/{transformCreateFileRoute.js → transformTanstackRouterCreateFileRoute.js} +1 -1
  94. package/vite-plugin/transformTanstackRouterCreateFileRoute.js.map +1 -0
  95. package/vite-plugin/vite-plugin.d.ts +2 -2
  96. package/vite-plugin/vite-plugin.js +33 -9
  97. package/vite-plugin/vite-plugin.js.map +1 -1
  98. package/esm/tools/infer_import_meta_env_BASE_URL.d.ts +0 -1
  99. package/esm/tools/infer_import_meta_env_BASE_URL.js +0 -15
  100. package/esm/tools/infer_import_meta_env_BASE_URL.js.map +0 -1
  101. package/src/tools/infer_import_meta_env_BASE_URL.ts +0 -19
  102. package/src/vite-plugin/detectProjectType.ts +0 -20
  103. package/src/vite-plugin/excludeModuleExportFromOptimizedDeps.ts +0 -20
  104. package/vite-plugin/detectProjectType.d.ts +0 -10
  105. package/vite-plugin/detectProjectType.js +0 -15
  106. package/vite-plugin/detectProjectType.js.map +0 -1
  107. package/vite-plugin/excludeModuleExportFromOptimizedDeps.d.ts +0 -4
  108. package/vite-plugin/excludeModuleExportFromOptimizedDeps.js.map +0 -1
  109. package/vite-plugin/transformCreateFileRoute.js.map +0 -1
  110. /package/src/vite-plugin/{transformCreateFileRoute.ts → transformTanstackRouterCreateFileRoute.ts} +0 -0
  111. /package/vite-plugin/{transformCreateFileRoute.d.ts → transformTanstackRouterCreateFileRoute.d.ts} +0 -0
@@ -0,0 +1,279 @@
1
+ import type { ReactNode, ComponentType } from "react";
2
+ import type { Oidc as Oidc_core, OidcInitializationError } from "../core";
3
+ import type { OidcMetadata } from "../core/OidcMetadata";
4
+ export type UseOidc<DecodedIdToken> = {
5
+ (params?: {
6
+ assert?: undefined;
7
+ }): UseOidc.Oidc<DecodedIdToken>;
8
+ (params: {
9
+ assert: "user logged in";
10
+ }): UseOidc.Oidc.LoggedIn<DecodedIdToken>;
11
+ (params: {
12
+ assert: "user not logged in";
13
+ }): UseOidc.Oidc.NotLoggedIn;
14
+ };
15
+ export declare namespace UseOidc {
16
+ type WithAutoLogin<DecodedIdToken> = (params?: {
17
+ assert: "user logged in";
18
+ }) => Oidc.LoggedIn<DecodedIdToken>;
19
+ type Oidc<DecodedIdToken> = (Oidc.NotLoggedIn & {
20
+ decodedIdToken?: never;
21
+ logout?: never;
22
+ renewTokens?: never;
23
+ goToAuthServer?: never;
24
+ backFromAuthServer?: never;
25
+ isNewBrowserSession?: never;
26
+ }) | (Oidc.LoggedIn<DecodedIdToken> & {
27
+ login?: never;
28
+ initializationError?: never;
29
+ });
30
+ namespace Oidc {
31
+ type Common = {
32
+ issuerUri: string;
33
+ clientId: string;
34
+ };
35
+ export type NotLoggedIn = Common & {
36
+ login: (params?: {
37
+ extraQueryParams?: Record<string, string | undefined>;
38
+ redirectUrl?: string;
39
+ transformUrlBeforeRedirect?: (url: string) => string;
40
+ }) => Promise<never>;
41
+ autoLogoutState: {
42
+ shouldDisplayWarning: false;
43
+ };
44
+ isUserLoggedIn: false;
45
+ initializationError: OidcInitializationError | undefined;
46
+ };
47
+ export type LoggedIn<DecodedIdToken> = Common & {
48
+ isUserLoggedIn: true;
49
+ decodedIdToken: DecodedIdToken;
50
+ logout: Oidc_core.LoggedIn["logout"];
51
+ renewTokens: Oidc_core.LoggedIn["renewTokens"];
52
+ goToAuthServer: Oidc_core.LoggedIn["goToAuthServer"];
53
+ backFromAuthServer: Oidc_core.LoggedIn["backFromAuthServer"];
54
+ isNewBrowserSession: boolean;
55
+ autoLogoutState: {
56
+ shouldDisplayWarning: true;
57
+ secondsLeftBeforeAutoLogout: number;
58
+ } | {
59
+ shouldDisplayWarning: false;
60
+ };
61
+ };
62
+ export {};
63
+ }
64
+ }
65
+ export type GetOidc<DecodedIdToken> = {
66
+ (params?: {
67
+ assert?: undefined;
68
+ }): Promise<GetOidc.Oidc<DecodedIdToken>>;
69
+ (params: {
70
+ assert: "user logged in";
71
+ }): Promise<GetOidc.Oidc.LoggedIn<DecodedIdToken>>;
72
+ (params: {
73
+ assert: "user not logged in";
74
+ }): Promise<GetOidc.Oidc.NotLoggedIn>;
75
+ };
76
+ export declare namespace GetOidc {
77
+ type WithAutoLogin<DecodedIdToken> = (params?: {
78
+ assert: "user logged in";
79
+ }) => Promise<Oidc.LoggedIn<DecodedIdToken>>;
80
+ type Oidc<DecodedIdToken> = (Oidc.NotLoggedIn & {
81
+ getAccessToken?: never;
82
+ getDecodedIdToken?: never;
83
+ logout?: never;
84
+ renewTokens?: never;
85
+ goToAuthServer?: never;
86
+ backFromAuthServer?: never;
87
+ isNewBrowserSession?: never;
88
+ subscribeToAutoLogoutState?: never;
89
+ }) | (Oidc.LoggedIn<DecodedIdToken> & {
90
+ initializationError?: never;
91
+ login?: never;
92
+ });
93
+ namespace Oidc {
94
+ type Common = {
95
+ issuerUri: string;
96
+ clientId: string;
97
+ };
98
+ export type NotLoggedIn = Common & {
99
+ isUserLoggedIn: false;
100
+ initializationError: OidcInitializationError | undefined;
101
+ login: Oidc_core.NotLoggedIn["login"];
102
+ };
103
+ export type LoggedIn<DecodedIdToken> = Common & {
104
+ isUserLoggedIn: true;
105
+ getAccessToken: () => Promise<string>;
106
+ getDecodedIdToken: () => DecodedIdToken;
107
+ logout: Oidc_core.LoggedIn["logout"];
108
+ renewTokens: Oidc_core.LoggedIn["renewTokens"];
109
+ goToAuthServer: Oidc_core.LoggedIn["goToAuthServer"];
110
+ backFromAuthServer: Oidc_core.LoggedIn["backFromAuthServer"];
111
+ isNewBrowserSession: boolean;
112
+ subscribeToAutoLogoutState: (next: (autoLogoutState: {
113
+ shouldDisplayWarning: true;
114
+ secondsLeftBeforeAutoLogout: number;
115
+ } | {
116
+ shouldDisplayWarning: false;
117
+ }) => void) => {
118
+ unsubscribeFromAutoLogoutState: () => void;
119
+ };
120
+ };
121
+ export {};
122
+ }
123
+ }
124
+ export type ParamsOfBootstrap<AutoLogin, DecodedIdToken> = ParamsOfBootstrap.Real<AutoLogin> | ParamsOfBootstrap.Mock<AutoLogin, DecodedIdToken>;
125
+ export declare namespace ParamsOfBootstrap {
126
+ type Real<AutoLogin> = {
127
+ implementation: "real";
128
+ /**
129
+ * See: https://docs.oidc-spa.dev/v/v8/providers-configuration/provider-configuration
130
+ */
131
+ issuerUri: string;
132
+ /**
133
+ * See: https://docs.oidc-spa.dev/v/v8/providers-configuration/provider-configuration
134
+ */
135
+ clientId: string;
136
+ /**
137
+ * Default: 45 second.
138
+ * It defines how long before the auto logout we should start
139
+ * displaying an overlay message to the user alerting them
140
+ * like: "Are you still there? You'll be disconnected in 45...44..."
141
+ * NOTE: This parameter is only UI related! It does not defines
142
+ * after how much time of inactivity the user should be auto logged out.
143
+ * This is a server policy (that can be overwrote by idleSessionLifetimeInSeconds)
144
+ * See: https://docs.oidc-spa.dev/v/v8/auto-logout
145
+ */
146
+ startCountdownSecondsBeforeAutoLogout?: number;
147
+ /**
148
+ * This parameter defines after how many seconds of inactivity the user should be
149
+ * logged out automatically.
150
+ *
151
+ * WARNING: It should be configured on the identity server side
152
+ * as it's the authoritative source for security policies and not the client.
153
+ * If you don't provide this parameter it will be inferred from the refresh token expiration time.
154
+ * Some provider however don't issue a refresh token or do not correctly set the
155
+ * expiration time. This parameter enable you to hard code the value to compensate
156
+ * the shortcoming of your auth server.
157
+ * */
158
+ idleSessionLifetimeInSeconds?: number;
159
+ /**
160
+ * The scopes being requested from the OIDC/OAuth2 provider (default: `["profile"]`
161
+ * (the scope "openid" is added automatically as it's mandatory)
162
+ **/
163
+ scopes?: string[];
164
+ /**
165
+ * Transform the url (authorization endpoint) before redirecting to the login pages.
166
+ *
167
+ * The isSilent parameter is true when the redirect is initiated in the background iframe for silent signin.
168
+ * This can be used to omit ui related query parameters (like `ui_locales`).
169
+ */
170
+ transformUrlBeforeRedirect?: (params: {
171
+ authorizationUrl: string;
172
+ isSilent: boolean;
173
+ }) => string;
174
+ /**
175
+ * Extra query params to be added to the authorization endpoint url before redirecting or silent signing in.
176
+ * You can provide a function that returns those extra query params, it will be called
177
+ * when login() is called.
178
+ *
179
+ * Example: extraQueryParams: ()=> ({ ui_locales: "fr" })
180
+ *
181
+ * This parameter can also be passed to login() directly.
182
+ */
183
+ extraQueryParams?: Record<string, string | undefined> | ((params: {
184
+ isSilent: boolean;
185
+ url: string;
186
+ }) => Record<string, string | undefined>);
187
+ /**
188
+ * Extra body params to be added to the /token POST request.
189
+ *
190
+ * It will be used when for the initial request, whenever the token is getting refreshed and if you call `renewTokens()`.
191
+ * You can also provide this parameter directly to the `renewTokens()` method.
192
+ *
193
+ * It can be either a string to string record or a function that returns a string to string record.
194
+ *
195
+ * Example: extraTokenParams: ()=> ({ selectedCustomer: "xxx" })
196
+ * extraTokenParams: { selectedCustomer: "xxx" }
197
+ */
198
+ extraTokenParams?: Record<string, string | undefined> | (() => Record<string, string | undefined>);
199
+ /**
200
+ * Default: false
201
+ *
202
+ * See: https://docs.oidc-spa.dev/v/v8/resources/iframe-related-issues
203
+ */
204
+ noIframe?: boolean;
205
+ debugLogs?: boolean;
206
+ /**
207
+ * WARNING: This option exists solely as a workaround
208
+ * for limitations in the Google OAuth API.
209
+ * See: https://docs.oidc-spa.dev/providers-configuration/google-oauth
210
+ *
211
+ * Do not use this for other providers.
212
+ * If you think you need a client secret in a SPA, you are likely
213
+ * trying to use a confidential (private) client in the browser,
214
+ * which is insecure and not supported.
215
+ */
216
+ __unsafe_clientSecret?: string;
217
+ /**
218
+ * This option should only be used as a last resort.
219
+ *
220
+ * If your OIDC provider is correctly configured, this should not be necessary.
221
+ *
222
+ * The metadata is normally retrieved automatically from:
223
+ * `${issuerUri}/.well-known/openid-configuration`
224
+ *
225
+ * Use this only if that endpoint is not accessible (e.g. due to missing CORS headers
226
+ * or non-standard deployments), and you cannot fix the server-side configuration.
227
+ */
228
+ __metadata?: Partial<OidcMetadata>;
229
+ /**
230
+ * WARNING: Setting this to true is a workaround for provider
231
+ * like Google OAuth that don't support JWT access token.
232
+ * Use at your own risk, this is a hack.
233
+ */
234
+ __unsafe_useIdTokenAsAccessToken?: boolean;
235
+ /**
236
+ * Let's you override the params passed to
237
+ * (if you weren't able to provide it)
238
+ */
239
+ BASE_URL?: string;
240
+ } & (AutoLogin extends true ? {} : {});
241
+ type Mock<AutoLogin, DecodedIdToken> = {
242
+ implementation: "mock";
243
+ issuerUri_mock?: string;
244
+ clientId_mock?: string;
245
+ decodedIdToken_mock?: DecodedIdToken;
246
+ /**
247
+ * Let's you override the params passed to
248
+ * (if you weren't able to provide it)
249
+ */
250
+ BASE_URL?: string;
251
+ } & (AutoLogin extends true ? {
252
+ isUserInitiallyLoggedIn?: true;
253
+ } : {
254
+ isUserInitiallyLoggedIn: boolean;
255
+ });
256
+ }
257
+ export type OidcSpaApi<AutoLogin, DecodedIdToken> = {
258
+ bootstrapOidc: (params: ParamsOfBootstrap<AutoLogin, DecodedIdToken>) => void;
259
+ useOidc: AutoLogin extends true ? UseOidc.WithAutoLogin<DecodedIdToken> : UseOidc<DecodedIdToken>;
260
+ getOidc: AutoLogin extends true ? GetOidc.WithAutoLogin<DecodedIdToken> : GetOidc<DecodedIdToken>;
261
+ } & (AutoLogin extends true ? {
262
+ OidcInitializationErrorGate: (props: {
263
+ errorComponent: ComponentType<{
264
+ oidcInitializationError: OidcInitializationError;
265
+ }>;
266
+ children: ReactNode;
267
+ }) => ReactNode;
268
+ } : {
269
+ enforceLogin: (loaderContext: {
270
+ request?: {
271
+ url?: string;
272
+ };
273
+ cause?: "preload" | string;
274
+ location?: {
275
+ href?: string;
276
+ };
277
+ }) => Promise<void | never>;
278
+ withLoginEnforced: <Props extends Record<string, unknown>>(component: ComponentType<Props>) => (props: Props) => ReactNode;
279
+ });
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/react-spa/types.tsx"],"names":[],"mappings":""}
package/src/angular.ts CHANGED
@@ -150,7 +150,7 @@ export type ParamsOfProvide = {
150
150
  assert<
151
151
  Equals<
152
152
  Omit<ParamsOfProvide, "autoLogoutWarningDurationSeconds">,
153
- Omit<ParamsOfCreateOidc<any, boolean>, "homeUrl" | "decodedIdTokenSchema">
153
+ Omit<ParamsOfCreateOidc<any, boolean>, "homeUrl" | "BASE_URL" | "decodedIdTokenSchema">
154
154
  >
155
155
  >;
156
156
 
@@ -0,0 +1,9 @@
1
+ let BASE_URL: string | undefined = undefined;
2
+
3
+ export function getBASE_URL() {
4
+ return BASE_URL;
5
+ }
6
+
7
+ export function setBASE_URL(params: { BASE_URL: string }) {
8
+ BASE_URL = params.BASE_URL;
9
+ }
@@ -51,6 +51,8 @@ import { isKeycloak } from "../keycloak/isKeycloak";
51
51
  import { INFINITY_TIME } from "../tools/INFINITY_TIME";
52
52
  import type { WELL_KNOWN_PATH } from "./diagnostic";
53
53
  import { getIsValidRemoteJson } from "../tools/getIsValidRemoteJson";
54
+ import { prShouldLoadApp } from "./prShouldLoadApp";
55
+ import { getBASE_URL } from "./BASE_URL";
54
56
 
55
57
  // NOTE: Replaced at build time
56
58
  const VERSION = "{{OIDC_SPA_VERSION}}";
@@ -59,14 +61,6 @@ export type ParamsOfCreateOidc<
59
61
  DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_OidcCoreSpec,
60
62
  AutoLogin extends boolean = false
61
63
  > = {
62
- /**
63
- * What should you put in this parameter?
64
- * - Vite project: `BASE_URL: import.meta.env.BASE_URL`
65
- * - Create React App project: `BASE_URL: process.env.PUBLIC_URL`
66
- * - Other: `BASE_URL: "/"` (Usually, or `/dashboard` if your app is not at the root of the domain)
67
- */
68
- homeUrl: string;
69
-
70
64
  /**
71
65
  * See: https://docs.oidc-spa.dev/v/v8/providers-configuration/provider-configuration
72
66
  */
@@ -194,6 +188,22 @@ export type ParamsOfCreateOidc<
194
188
  * or non-standard deployments), and you cannot fix the server-side configuration.
195
189
  */
196
190
  __metadata?: Partial<OidcMetadata>;
191
+
192
+ /**
193
+ * NOTE: This parameter is optional if you use the Vite plugin.
194
+ *
195
+ * This parameter let's you overwrite the value provided in
196
+ * oidcEarlyInit({ BASE_URL: xxx });
197
+ *
198
+ * What should you put in this parameter?
199
+ * - Vite project: `BASE_URL: import.meta.env.BASE_URL`
200
+ * - Create React App project: `BASE_URL: process.env.PUBLIC_URL`
201
+ * - Other: `BASE_URL: "/"` (Usually, or `/dashboard` if your app is not at the root of the domain)
202
+ */
203
+ BASE_URL?: string;
204
+
205
+ /** @deprecated: Use BASE_URL (same thing, just renamed). */
206
+ homeUrl?: string;
197
207
  };
198
208
 
199
209
  const globalContext = {
@@ -314,11 +324,31 @@ export async function createOidc_nonMemoized<
314
324
  log: typeof console.log | undefined;
315
325
  }
316
326
  ): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>> {
327
+ {
328
+ const timer = window.setTimeout(() => {
329
+ console.warn(
330
+ [
331
+ "oidc-spa: Setup error.",
332
+ "oidcEarlyInit() wasn't called.",
333
+ "This is supposed to be handled by the oidc-spa Vite plugin",
334
+ "or manually in other environments."
335
+ ].join(" ")
336
+ );
337
+ }, 3_000);
338
+
339
+ const shouldLoadApp = await prShouldLoadApp;
340
+
341
+ window.clearTimeout(timer);
342
+
343
+ if (!shouldLoadApp) {
344
+ return new Promise<never>(() => {});
345
+ }
346
+ }
347
+
317
348
  const {
318
349
  transformUrlBeforeRedirect,
319
350
  extraQueryParams: extraQueryParamsOrGetter,
320
351
  extraTokenParams: extraTokenParamsOrGetter,
321
- homeUrl: homeUrl_params,
322
352
  decodedIdTokenSchema,
323
353
  idleSessionLifetimeInSeconds,
324
354
  autoLogoutParams = { redirectTo: "current page" },
@@ -330,6 +360,8 @@ export async function createOidc_nonMemoized<
330
360
  noIframe = false
331
361
  } = params;
332
362
 
363
+ const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
364
+
333
365
  const { issuerUri, clientId, scopes, configId, log } = preProcessedParams;
334
366
 
335
367
  const getExtraQueryParams = (() => {
@@ -357,7 +389,29 @@ export async function createOidc_nonMemoized<
357
389
  })();
358
390
 
359
391
  const homeUrlAndRedirectUri = toFullyQualifiedUrl({
360
- urlish: homeUrl_params,
392
+ urlish: (() => {
393
+ if (BASE_URL_params !== undefined) {
394
+ return BASE_URL_params;
395
+ }
396
+
397
+ const BASE_URL = getBASE_URL();
398
+
399
+ if (BASE_URL === undefined) {
400
+ throw new Error(
401
+ [
402
+ "oidc-spa: If you do not use the oidc-spa Vite plugin",
403
+ "you must provide the BASE_URL to the earlyInit() examples:",
404
+ "oidcSpaEarlyInit({ BASE_URL: import.meta.env.BASE_URL })",
405
+ "oidcSpaEarlyInit({ BASE_URL: '/' })",
406
+ "",
407
+ "You can also pass this parameter to createOidc({ BASE_URL: '...' })",
408
+ "or bootstrapOidc({ BASE_URL: '...' })"
409
+ ].join("\n")
410
+ );
411
+ }
412
+
413
+ return BASE_URL;
414
+ })(),
361
415
  doAssertNoQueryParams: true,
362
416
  doOutputWithTrailingSlash: true
363
417
  });
@@ -7,6 +7,8 @@ import {
7
7
  preventSessionStorageSetItemOfPublicKeyByThirdParty
8
8
  } from "./iframeMessageProtection";
9
9
  import { setOidcRequiredPostHydrationReplaceNavigationUrl } from "./requiredPostHydrationReplaceNavigationUrl";
10
+ import { setBASE_URL } from "./BASE_URL";
11
+ import { resolvePrShouldLoadApp } from "./prShouldLoadApp";
10
12
  import { isBrowser } from "../tools/isBrowser";
11
13
 
12
14
  let hasEarlyInitBeenCalled = false;
@@ -18,6 +20,7 @@ export function oidcEarlyInit(params: {
18
20
  // Will be made mandatory next major.
19
21
  freezeWebSocket?: boolean;
20
22
  isPostLoginRedirectManual?: boolean;
23
+ BASE_URL?: string;
21
24
  }) {
22
25
  if (hasEarlyInitBeenCalled) {
23
26
  throw new Error("oidc-spa: oidcEarlyInit() Should be called only once");
@@ -35,8 +38,9 @@ export function oidcEarlyInit(params: {
35
38
  freezeFetch,
36
39
  freezeXMLHttpRequest,
37
40
  freezeWebSocket = false,
38
- isPostLoginRedirectManual = false
39
- } = params ?? {};
41
+ isPostLoginRedirectManual = false,
42
+ BASE_URL
43
+ } = params;
40
44
 
41
45
  const { shouldLoadApp } = handleOidcCallback({ isPostLoginRedirectManual });
42
46
 
@@ -83,8 +87,14 @@ export function oidcEarlyInit(params: {
83
87
  }
84
88
 
85
89
  preventSessionStorageSetItemOfPublicKeyByThirdParty();
90
+
91
+ if (BASE_URL !== undefined) {
92
+ setBASE_URL({ BASE_URL });
93
+ }
86
94
  }
87
95
 
96
+ resolvePrShouldLoadApp({ shouldLoadApp });
97
+
88
98
  return { shouldLoadApp };
89
99
  }
90
100
 
@@ -93,15 +103,8 @@ let redirectAuthResponse: AuthResponse | undefined = undefined;
93
103
  export function getRedirectAuthResponse():
94
104
  | { authResponse: AuthResponse; clearAuthResponse: () => void }
95
105
  | { authResponse: undefined; clearAuthResponse?: never } {
96
- if (!hasEarlyInitBeenCalled) {
97
- throw new Error(
98
- [
99
- "oidc-spa setup error.",
100
- "oidcEarlyInit() wasn't called.",
101
- "In newer version, using oidc-spa/entrypoint is no longer optional."
102
- ].join(" ")
103
- );
104
- }
106
+ assert(hasEarlyInitBeenCalled, "34933395");
107
+
105
108
  return redirectAuthResponse === undefined
106
109
  ? { authResponse: undefined }
107
110
  : {
@@ -0,0 +1,11 @@
1
+ import { assert } from "../tools/tsafe/assert";
2
+
3
+ let prShouldLoadApp_resolve: (shouldLoadApp: boolean) => void | undefined;
4
+
5
+ export const prShouldLoadApp = new Promise<boolean>(resolve => (prShouldLoadApp_resolve = resolve));
6
+
7
+ export function resolvePrShouldLoadApp(params: { shouldLoadApp: boolean }) {
8
+ const { shouldLoadApp } = params;
9
+ assert(prShouldLoadApp_resolve !== undefined);
10
+ prShouldLoadApp_resolve(shouldLoadApp);
11
+ }
@@ -23,7 +23,7 @@ import { type StatefulEvt, createStatefulEvt } from "../../tools/StatefulEvt";
23
23
  import { readExpirationTimeInJwt } from "../../tools/readExpirationTimeInJwt";
24
24
 
25
25
  type ConstructorParams = KeycloakServerConfig & {
26
- homeUrl: string;
26
+ BASE_URL?: string;
27
27
  };
28
28
 
29
29
  /**
@@ -99,7 +99,7 @@ export class Keycloak {
99
99
  let hasCreateResolved = false;
100
100
 
101
101
  const oidcOrError = await createOidc({
102
- homeUrl: constructorParams.homeUrl,
102
+ homeUrl: constructorParams.BASE_URL,
103
103
  issuerUri,
104
104
  clientId: this.#state.constructorParams.clientId,
105
105
  autoLogin,
package/src/mock/oidc.ts CHANGED
@@ -5,6 +5,7 @@ import { toFullyQualifiedUrl } from "../tools/toFullyQualifiedUrl";
5
5
  import { getSearchParam, addOrUpdateSearchParam } from "../tools/urlSearchParams";
6
6
  import { getRootRelativeOriginalLocationHref } from "../core/earlyInit";
7
7
  import { INFINITY_TIME } from "../tools/INFINITY_TIME";
8
+ import { getBASE_URL } from "../core/BASE_URL";
8
9
 
9
10
  export type ParamsOfCreateMockOidc<
10
11
  DecodedIdToken extends Record<string, unknown> = Record<string, unknown>,
@@ -18,7 +19,11 @@ export type ParamsOfCreateMockOidc<
18
19
  * In the majority of cases it should be `homeUrl: "/"` but it could aso be something like `homeUrl: "/dashboard"`
19
20
  * if your web app isn't hosted at the root of the domain.
20
21
  */
21
- homeUrl: string;
22
+ BASE_URL?: string;
23
+
24
+ /** @deprecated: Use BASE_URL (same thing, just renamed). */
25
+ homeUrl?: string;
26
+
22
27
  autoLogin?: AutoLogin;
23
28
  postLoginRedirectUrl?: string;
24
29
  } & (AutoLogin extends true
@@ -41,11 +46,12 @@ export async function createMockOidc<
41
46
  isUserInitiallyLoggedIn = true,
42
47
  mockedParams = {},
43
48
  mockedTokens = {},
44
- homeUrl: homeUrl_params,
45
49
  autoLogin = false,
46
50
  postLoginRedirectUrl
47
51
  } = params;
48
52
 
53
+ const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
54
+
49
55
  const isUserLoggedIn = (() => {
50
56
  const { wasPresent, value } = getSearchParam({
51
57
  url: toFullyQualifiedUrl({
@@ -82,7 +88,7 @@ export async function createMockOidc<
82
88
  })();
83
89
 
84
90
  const homeUrl = toFullyQualifiedUrl({
85
- urlish: homeUrl_params,
91
+ urlish: BASE_URL_params ?? getBASE_URL() ?? "/",
86
92
  doAssertNoQueryParams: true,
87
93
  doOutputWithTrailingSlash: true
88
94
  });
@@ -0,0 +1,70 @@
1
+ import type { OidcSpaApi } from "./types";
2
+ import type { Oidc as Oidc_core } from "../core";
3
+ import type { ZodSchemaLike } from "../tools/ZodSchemaLike";
4
+ import { createOidcSpaApi } from "./createOidcSpaApi";
5
+
6
+ export type OidcSpaApiBuilder<
7
+ AutoLogin extends boolean = false,
8
+ DecodedIdToken extends Record<string, unknown> = Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec,
9
+ ExcludedMethod extends
10
+ | "withAutoLogin"
11
+ | "withExpectedDecodedIdTokenShape"
12
+ | "withAccessTokenValidation"
13
+ | "finalize" = never
14
+ > = Omit<
15
+ {
16
+ withAutoLogin: () => OidcSpaApiBuilder<true, DecodedIdToken, ExcludedMethod | "withAutoLogin">;
17
+ withExpectedDecodedIdTokenShape: <DecodedIdToken extends Record<string, unknown>>(params: {
18
+ decodedIdTokenSchema: ZodSchemaLike<
19
+ Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec,
20
+ DecodedIdToken
21
+ >;
22
+ decodedIdToken_mock?: NoInfer<DecodedIdToken>;
23
+ }) => OidcSpaApiBuilder<
24
+ AutoLogin,
25
+ DecodedIdToken,
26
+ ExcludedMethod | "withExpectedDecodedIdTokenShape"
27
+ >;
28
+
29
+ finalize: () => OidcSpaApi<AutoLogin, DecodedIdToken>;
30
+ },
31
+ ExcludedMethod
32
+ >;
33
+
34
+ function createOidcSpaApiBuilder<
35
+ AutoLogin extends boolean = false,
36
+ DecodedIdToken extends Record<string, unknown> = Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec
37
+ >(params: {
38
+ autoLogin: AutoLogin;
39
+ decodedIdTokenSchema:
40
+ | ZodSchemaLike<Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec, DecodedIdToken>
41
+ | undefined;
42
+ decodedIdToken_mock: DecodedIdToken | undefined;
43
+ }): OidcSpaApiBuilder<AutoLogin, DecodedIdToken> {
44
+ return {
45
+ withAutoLogin: () =>
46
+ createOidcSpaApiBuilder({
47
+ autoLogin: true,
48
+ decodedIdTokenSchema: params.decodedIdTokenSchema,
49
+ decodedIdToken_mock: params.decodedIdToken_mock
50
+ }),
51
+ withExpectedDecodedIdTokenShape: ({ decodedIdTokenSchema, decodedIdToken_mock }) =>
52
+ createOidcSpaApiBuilder({
53
+ autoLogin: params.autoLogin,
54
+ decodedIdTokenSchema,
55
+ decodedIdToken_mock: decodedIdToken_mock
56
+ }),
57
+ finalize: () =>
58
+ createOidcSpaApi<AutoLogin, DecodedIdToken>({
59
+ autoLogin: params.autoLogin,
60
+ decodedIdTokenSchema: params.decodedIdTokenSchema,
61
+ decodedIdToken_mock: params.decodedIdToken_mock
62
+ })
63
+ };
64
+ }
65
+
66
+ export const oidcSpaApiBuilder = createOidcSpaApiBuilder({
67
+ autoLogin: false,
68
+ decodedIdToken_mock: undefined,
69
+ decodedIdTokenSchema: undefined
70
+ });