oidc-spa 8.3.6 → 8.3.8
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/core/StateDataCookie.d.ts +34 -0
- package/core/StateDataCookie.js +142 -0
- package/core/StateDataCookie.js.map +1 -0
- package/core/createOidc.js +25 -9
- package/core/createOidc.js.map +1 -1
- package/core/earlyInit.d.ts +0 -1
- package/core/earlyInit.js +4 -12
- package/core/earlyInit.js.map +1 -1
- package/core/loginOrGoToAuthServer.d.ts +1 -0
- package/core/loginOrGoToAuthServer.js +20 -9
- package/core/loginOrGoToAuthServer.js.map +1 -1
- package/entrypoint.d.ts +0 -1
- package/entrypoint.js +1 -3
- package/entrypoint.js.map +1 -1
- package/esm/core/StateDataCookie.d.ts +34 -0
- package/esm/core/StateDataCookie.js +135 -0
- package/esm/core/StateDataCookie.js.map +1 -0
- package/esm/core/createOidc.js +25 -9
- package/esm/core/createOidc.js.map +1 -1
- package/esm/core/earlyInit.d.ts +0 -1
- package/esm/core/earlyInit.js +4 -12
- package/esm/core/earlyInit.js.map +1 -1
- package/esm/core/loginOrGoToAuthServer.d.ts +1 -0
- package/esm/core/loginOrGoToAuthServer.js +20 -9
- package/esm/core/loginOrGoToAuthServer.js.map +1 -1
- package/esm/entrypoint.d.ts +0 -1
- package/esm/entrypoint.js +0 -1
- package/esm/entrypoint.js.map +1 -1
- package/esm/tanstack-start/react/createOidcSpaApi.js +2 -0
- package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -1
- package/esm/tanstack-start/react/index.d.ts +1 -1
- package/esm/tanstack-start/react/index.js +1 -1
- package/esm/tanstack-start/react/index.js.map +1 -1
- package/esm/tanstack-start/react/withOidcSpaServerEntry.d.ts +5 -0
- package/esm/tanstack-start/react/withOidcSpaServerEntry.js +38 -0
- package/esm/tanstack-start/react/withOidcSpaServerEntry.js.map +1 -0
- package/package.json +1 -1
- package/src/core/StateDataCookie.ts +217 -0
- package/src/core/createOidc.ts +34 -8
- package/src/core/earlyInit.ts +3 -15
- package/src/core/loginOrGoToAuthServer.ts +25 -9
- package/src/entrypoint.ts +0 -1
- package/src/tanstack-start/react/createOidcSpaApi.tsx +3 -0
- package/src/tanstack-start/react/index.ts +1 -1
- package/src/tanstack-start/react/withOidcSpaServerEntry.ts +60 -0
- package/src/vite-plugin/handleClientEntrypoint.ts +10 -67
- package/src/vite-plugin/handleServerEntrypoint.ts +129 -0
- package/src/vite-plugin/transformTanstackRouterCreateFileRoute.ts +0 -64
- package/src/vite-plugin/utils.ts +64 -0
- package/src/vite-plugin/vite-plugin.ts +31 -10
- package/vite-plugin/handleClientEntrypoint.d.ts +7 -5
- package/vite-plugin/handleClientEntrypoint.js +16 -62
- package/vite-plugin/handleClientEntrypoint.js.map +1 -1
- package/vite-plugin/handleServerEntrypoint.d.ts +12 -0
- package/vite-plugin/handleServerEntrypoint.js +113 -0
- package/vite-plugin/handleServerEntrypoint.js.map +1 -0
- package/vite-plugin/transformTanstackRouterCreateFileRoute.js +0 -39
- package/vite-plugin/transformTanstackRouterCreateFileRoute.js.map +1 -1
- package/vite-plugin/utils.d.ts +12 -0
- package/vite-plugin/utils.js +88 -0
- package/vite-plugin/utils.js.map +1 -0
- package/vite-plugin/vite-plugin.d.ts +1 -1
- package/vite-plugin/vite-plugin.js +21 -5
- package/vite-plugin/vite-plugin.js.map +1 -1
- package/core/requiredPostHydrationReplaceNavigationUrl.d.ts +0 -6
- package/core/requiredPostHydrationReplaceNavigationUrl.js +0 -12
- package/core/requiredPostHydrationReplaceNavigationUrl.js.map +0 -1
- package/esm/core/requiredPostHydrationReplaceNavigationUrl.d.ts +0 -6
- package/esm/core/requiredPostHydrationReplaceNavigationUrl.js +0 -8
- package/esm/core/requiredPostHydrationReplaceNavigationUrl.js.map +0 -1
- package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.d.ts +0 -2
- package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js +0 -36
- package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js.map +0 -1
- package/src/core/requiredPostHydrationReplaceNavigationUrl.ts +0 -11
- package/src/tanstack-start/react/withHandlingOidcPostLoginNavigation.tsx +0 -46
package/src/core/createOidc.ts
CHANGED
|
@@ -53,6 +53,11 @@ import {
|
|
|
53
53
|
import { getDesiredPostLoginRedirectUrl } from "./desiredPostLoginRedirectUrl";
|
|
54
54
|
import { getHomeAndRedirectUri } from "./homeAndRedirectUri";
|
|
55
55
|
import { ensureNonBlankPaint } from "../tools/ensureNonBlankPaint";
|
|
56
|
+
import {
|
|
57
|
+
setStateDataCookieIfEnabled,
|
|
58
|
+
clearStateDataCookie,
|
|
59
|
+
getIsStateDataCookieEnabled
|
|
60
|
+
} from "./StateDataCookie";
|
|
56
61
|
|
|
57
62
|
// NOTE: Replaced at build time
|
|
58
63
|
const VERSION = "{{OIDC_SPA_VERSION}}";
|
|
@@ -373,10 +378,11 @@ export async function createOidc_nonMemoized<
|
|
|
373
378
|
__unsafe_clientSecret,
|
|
374
379
|
__unsafe_useIdTokenAsAccessToken = false,
|
|
375
380
|
__metadata,
|
|
376
|
-
scopes = ["openid", "profile"],
|
|
377
381
|
sessionRestorationMethod = params.autoLogin === true ? "full page redirect" : "auto"
|
|
378
382
|
} = params;
|
|
379
383
|
|
|
384
|
+
const scopes = Array.from(new Set(["openid", ...(params.scopes ?? ["profile"])]));
|
|
385
|
+
|
|
380
386
|
const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
|
|
381
387
|
|
|
382
388
|
const { issuerUri, clientId, configId, log } = preProcessedParams;
|
|
@@ -607,9 +613,10 @@ export async function createOidc_nonMemoized<
|
|
|
607
613
|
redirect_uri: homeUrlAndRedirectUri,
|
|
608
614
|
silent_redirect_uri: homeUrlAndRedirectUri,
|
|
609
615
|
post_logout_redirect_uri: homeUrlAndRedirectUri,
|
|
610
|
-
response_mode:
|
|
616
|
+
response_mode:
|
|
617
|
+
isKeycloak({ issuerUri }) && !getIsStateDataCookieEnabled() ? "fragment" : "query",
|
|
611
618
|
response_type: "code",
|
|
612
|
-
scope:
|
|
619
|
+
scope: scopes.join(" "),
|
|
613
620
|
automaticSilentRenew: false,
|
|
614
621
|
userStore: new WebStorageStateStore({
|
|
615
622
|
store: (() => {
|
|
@@ -647,6 +654,7 @@ export async function createOidc_nonMemoized<
|
|
|
647
654
|
getExtraQueryParams,
|
|
648
655
|
getExtraTokenParams,
|
|
649
656
|
homeUrl: homeUrlAndRedirectUri,
|
|
657
|
+
stateUrlParamValue_instance,
|
|
650
658
|
evtInitializationOutcomeUserNotLoggedIn,
|
|
651
659
|
log
|
|
652
660
|
});
|
|
@@ -741,6 +749,8 @@ export async function createOidc_nonMemoized<
|
|
|
741
749
|
break handle_redirect_auth_response;
|
|
742
750
|
}
|
|
743
751
|
|
|
752
|
+
// TODO: Delete cookie if exist
|
|
753
|
+
|
|
744
754
|
const { stateData, authResponse } = stateDataAndAuthResponse;
|
|
745
755
|
|
|
746
756
|
switch (stateData.action) {
|
|
@@ -763,6 +773,8 @@ export async function createOidc_nonMemoized<
|
|
|
763
773
|
|
|
764
774
|
const authResponseUrl = authResponseToUrl(authResponse);
|
|
765
775
|
|
|
776
|
+
clearStateDataCookie({ stateUrlParamValue: authResponse.state });
|
|
777
|
+
|
|
766
778
|
let oidcClientTsUser: OidcClientTsUser | undefined = undefined;
|
|
767
779
|
|
|
768
780
|
try {
|
|
@@ -786,7 +798,10 @@ export async function createOidc_nonMemoized<
|
|
|
786
798
|
|
|
787
799
|
if (authResponse_error !== undefined) {
|
|
788
800
|
log?.(
|
|
789
|
-
|
|
801
|
+
[
|
|
802
|
+
`The auth server responded with: ${authResponse_error},`,
|
|
803
|
+
`trying to restore session as if we didn't had a auth response.`
|
|
804
|
+
].join(" ")
|
|
790
805
|
);
|
|
791
806
|
break handle_redirect_auth_response;
|
|
792
807
|
}
|
|
@@ -943,6 +958,8 @@ export async function createOidc_nonMemoized<
|
|
|
943
958
|
)}`
|
|
944
959
|
);
|
|
945
960
|
|
|
961
|
+
clearStateDataCookie({ stateUrlParamValue: authResponse.state });
|
|
962
|
+
|
|
946
963
|
authResponse_error = authResponse.error;
|
|
947
964
|
|
|
948
965
|
try {
|
|
@@ -1006,9 +1023,7 @@ export async function createOidc_nonMemoized<
|
|
|
1006
1023
|
|
|
1007
1024
|
return getDesiredPostLoginRedirectUrl() ?? window.location.href;
|
|
1008
1025
|
})(),
|
|
1009
|
-
|
|
1010
|
-
// only works on user interaction so it have to be false
|
|
1011
|
-
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: false,
|
|
1026
|
+
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: true,
|
|
1012
1027
|
extraQueryParams_local: undefined,
|
|
1013
1028
|
transformUrlBeforeRedirect_local: undefined,
|
|
1014
1029
|
interaction: (() => {
|
|
@@ -1364,6 +1379,15 @@ export async function createOidc_nonMemoized<
|
|
|
1364
1379
|
location.reload();
|
|
1365
1380
|
});
|
|
1366
1381
|
|
|
1382
|
+
setStateDataCookieIfEnabled({
|
|
1383
|
+
homeUrl: homeUrlAndRedirectUri,
|
|
1384
|
+
stateUrlParamValue_instance,
|
|
1385
|
+
stateDataCookie: {
|
|
1386
|
+
action: "logout",
|
|
1387
|
+
rootRelativeRedirectUrl: rootRelativePostLogoutRedirectUrl
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1367
1391
|
try {
|
|
1368
1392
|
await oidcClientTsUserManager.signoutRedirect({
|
|
1369
1393
|
state: id<StateData.Redirect>({
|
|
@@ -1401,7 +1425,7 @@ export async function createOidc_nonMemoized<
|
|
|
1401
1425
|
doForceReloadOnBfCache: true,
|
|
1402
1426
|
extraQueryParams_local: undefined,
|
|
1403
1427
|
transformUrlBeforeRedirect_local: undefined,
|
|
1404
|
-
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack:
|
|
1428
|
+
doNavigateBackToLastPublicUrlIfTheTheUserNavigateBack: true,
|
|
1405
1429
|
interaction: "directly redirect if active session show login otherwise",
|
|
1406
1430
|
preRedirectHook: undefined
|
|
1407
1431
|
});
|
|
@@ -1465,6 +1489,8 @@ export async function createOidc_nonMemoized<
|
|
|
1465
1489
|
|
|
1466
1490
|
log?.("Tokens refresh using iframe", authResponse);
|
|
1467
1491
|
|
|
1492
|
+
clearStateDataCookie({ stateUrlParamValue: authResponse.state });
|
|
1493
|
+
|
|
1468
1494
|
const authResponse_error = authResponse.error;
|
|
1469
1495
|
|
|
1470
1496
|
let oidcClientTsUser_scope: OidcClientTsUser | undefined = undefined;
|
package/src/core/earlyInit.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getStateData, getIsStatQueryParamValue } from "./StateData";
|
|
2
2
|
import { assert, type Equals } from "../tools/tsafe/assert";
|
|
3
3
|
import type { AuthResponse } from "./AuthResponse";
|
|
4
|
-
import { setOidcRequiredPostHydrationReplaceNavigationUrl } from "./requiredPostHydrationReplaceNavigationUrl";
|
|
5
4
|
import { setBASE_URL } from "./BASE_URL";
|
|
6
5
|
import { resolvePrShouldLoadApp } from "./prShouldLoadApp";
|
|
7
6
|
import { isBrowser } from "../tools/isBrowser";
|
|
@@ -17,7 +16,6 @@ export function oidcEarlyInit(params: {
|
|
|
17
16
|
freezeWebSocket?: boolean;
|
|
18
17
|
freezePromise?: boolean;
|
|
19
18
|
safeMode?: boolean;
|
|
20
|
-
isPostLoginRedirectManual?: boolean;
|
|
21
19
|
BASE_URL?: string;
|
|
22
20
|
}) {
|
|
23
21
|
if (hasEarlyInitBeenCalled) {
|
|
@@ -36,11 +34,10 @@ export function oidcEarlyInit(params: {
|
|
|
36
34
|
freezeWebSocket,
|
|
37
35
|
freezePromise,
|
|
38
36
|
safeMode = false,
|
|
39
|
-
isPostLoginRedirectManual = false,
|
|
40
37
|
BASE_URL
|
|
41
38
|
} = params;
|
|
42
39
|
|
|
43
|
-
const { shouldLoadApp } = handleOidcCallback(
|
|
40
|
+
const { shouldLoadApp } = handleOidcCallback();
|
|
44
41
|
|
|
45
42
|
if (shouldLoadApp) {
|
|
46
43
|
const createWriteError = (target: string) =>
|
|
@@ -285,11 +282,9 @@ export function getRootRelativeOriginalLocationHref() {
|
|
|
285
282
|
return rootRelativeOriginalLocationHref;
|
|
286
283
|
}
|
|
287
284
|
|
|
288
|
-
function handleOidcCallback(
|
|
285
|
+
function handleOidcCallback(): {
|
|
289
286
|
shouldLoadApp: boolean;
|
|
290
287
|
} {
|
|
291
|
-
const { isPostLoginRedirectManual } = params;
|
|
292
|
-
|
|
293
288
|
const location_urlObj = new URL(window.location.href);
|
|
294
289
|
|
|
295
290
|
const locationHrefAssessment = (() => {
|
|
@@ -390,7 +385,6 @@ function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
|
|
|
390
385
|
return { shouldLoadApp: false };
|
|
391
386
|
case "redirect": {
|
|
392
387
|
redirectAuthResponse = authResponse;
|
|
393
|
-
|
|
394
388
|
const rootRelativeRedirectUrl = (() => {
|
|
395
389
|
if (stateData.action === "login" && authResponse.error === "consent_required") {
|
|
396
390
|
return stateData.rootRelativeRedirectUrl_consentRequiredCase;
|
|
@@ -398,13 +392,7 @@ function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
|
|
|
398
392
|
return stateData.rootRelativeRedirectUrl;
|
|
399
393
|
})();
|
|
400
394
|
|
|
401
|
-
|
|
402
|
-
setOidcRequiredPostHydrationReplaceNavigationUrl({ rootRelativeRedirectUrl });
|
|
403
|
-
history.replaceState({}, "", rootRelativeOriginalLocationHref);
|
|
404
|
-
} else {
|
|
405
|
-
history.replaceState({}, "", rootRelativeRedirectUrl);
|
|
406
|
-
}
|
|
407
|
-
|
|
395
|
+
history.replaceState({}, "", rootRelativeRedirectUrl);
|
|
408
396
|
return { shouldLoadApp: true };
|
|
409
397
|
}
|
|
410
398
|
default:
|
|
@@ -8,6 +8,7 @@ import { createStatefulEvt } from "../tools/StatefulEvt";
|
|
|
8
8
|
import { Deferred } from "../tools/Deferred";
|
|
9
9
|
import { addOrUpdateSearchParam, getAllSearchParams } from "../tools/urlSearchParams";
|
|
10
10
|
import { getIsOnline } from "../tools/getIsOnline";
|
|
11
|
+
import { setStateDataCookieIfEnabled } from "./StateDataCookie";
|
|
11
12
|
|
|
12
13
|
const globalContext = {
|
|
13
14
|
evtHasLoginBeenCalled: createStatefulEvt(() => false)
|
|
@@ -65,7 +66,9 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
65
66
|
getExtraTokenParams: (() => Record<string, string | undefined>) | undefined;
|
|
66
67
|
|
|
67
68
|
homeUrl: string;
|
|
69
|
+
stateUrlParamValue_instance: string;
|
|
68
70
|
evtInitializationOutcomeUserNotLoggedIn: NonPostableEvt<void>;
|
|
71
|
+
|
|
69
72
|
log: typeof console.log | undefined;
|
|
70
73
|
}) {
|
|
71
74
|
const {
|
|
@@ -78,6 +81,7 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
78
81
|
getExtraTokenParams,
|
|
79
82
|
|
|
80
83
|
homeUrl,
|
|
84
|
+
stateUrlParamValue_instance,
|
|
81
85
|
evtInitializationOutcomeUserNotLoggedIn,
|
|
82
86
|
|
|
83
87
|
log
|
|
@@ -204,20 +208,32 @@ export function createLoginOrGoToAuthServer(params: {
|
|
|
204
208
|
|
|
205
209
|
log?.(`redirectUrl: ${rootRelativeRedirectUrl}`);
|
|
206
210
|
|
|
207
|
-
const
|
|
211
|
+
const rootRelativeRedirectUrl_consentRequiredCase = (() => {
|
|
212
|
+
switch (rest.action) {
|
|
213
|
+
case "login":
|
|
214
|
+
return (lastPublicUrl ?? homeUrl).slice(window.location.origin.length);
|
|
215
|
+
case "go to auth server":
|
|
216
|
+
return rootRelativeRedirectUrl;
|
|
217
|
+
}
|
|
218
|
+
})();
|
|
219
|
+
|
|
220
|
+
setStateDataCookieIfEnabled({
|
|
221
|
+
homeUrl,
|
|
222
|
+
stateUrlParamValue_instance,
|
|
223
|
+
stateDataCookie: {
|
|
224
|
+
action: "login",
|
|
225
|
+
rootRelativeRedirectUrl,
|
|
226
|
+
rootRelativeRedirectUrl_consentRequiredCase
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const stateData: StateData.Redirect = {
|
|
208
231
|
context: "redirect",
|
|
209
232
|
rootRelativeRedirectUrl,
|
|
210
233
|
extraQueryParams: {},
|
|
211
234
|
configId,
|
|
212
235
|
action: "login",
|
|
213
|
-
rootRelativeRedirectUrl_consentRequiredCase
|
|
214
|
-
switch (rest.action) {
|
|
215
|
-
case "login":
|
|
216
|
-
return (lastPublicUrl ?? homeUrl).slice(window.location.origin.length);
|
|
217
|
-
case "go to auth server":
|
|
218
|
-
return rootRelativeRedirectUrl;
|
|
219
|
-
}
|
|
220
|
-
})()
|
|
236
|
+
rootRelativeRedirectUrl_consentRequiredCase
|
|
221
237
|
};
|
|
222
238
|
|
|
223
239
|
const isSilent = rest.action === "login" && rest.interaction === "ensure no interaction";
|
package/src/entrypoint.ts
CHANGED
|
@@ -25,6 +25,7 @@ import { toFullyQualifiedUrl } from "../../tools/toFullyQualifiedUrl";
|
|
|
25
25
|
import { BEFORE_LOAD_FN_BRAND_PROPERTY_NAME } from "./disableSsrIfLoginEnforced";
|
|
26
26
|
import { setDesiredPostLoginRedirectUrl } from "../../core/desiredPostLoginRedirectUrl";
|
|
27
27
|
import type { MaybeAsync } from "../../tools/MaybeAsync";
|
|
28
|
+
import { enableStateDataCookie } from "../../core/StateDataCookie";
|
|
28
29
|
|
|
29
30
|
export function createOidcSpaApi<
|
|
30
31
|
AutoLogin extends boolean,
|
|
@@ -640,6 +641,8 @@ export function createOidcSpaApi<
|
|
|
640
641
|
break;
|
|
641
642
|
case "real":
|
|
642
643
|
{
|
|
644
|
+
enableStateDataCookie();
|
|
645
|
+
|
|
643
646
|
const { createOidc } = await prModuleCore;
|
|
644
647
|
|
|
645
648
|
let oidcCoreOrInitializationError:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { withHandlingOidcPostLoginNavigation } from "./withHandlingOidcPostLoginNavigation";
|
|
2
1
|
export { __disableSsrIfLoginEnforced } from "./disableSsrIfLoginEnforced";
|
|
2
|
+
export { __withOidcSpaServerEntry } from "./withOidcSpaServerEntry";
|
|
3
3
|
export type * from "./types";
|
|
4
4
|
import { oidcSpaApiBuilder } from "./apiBuilder";
|
|
5
5
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Register } from "@tanstack/react-router";
|
|
2
|
+
// NOTE: This is actually "@tanstack/react-start/server" but since our module is not labeled as ESM we import it from here.
|
|
3
|
+
// it does not matter since it's type level only.
|
|
4
|
+
import type { RequestHandler } from "@tanstack/react-start-server";
|
|
5
|
+
import { getStateDataCookies } from "../../core/StateDataCookie";
|
|
6
|
+
|
|
7
|
+
export function __withOidcSpaServerEntry<T extends { fetch: RequestHandler<Register> }>(
|
|
8
|
+
serverEntry_original: T
|
|
9
|
+
): T {
|
|
10
|
+
return {
|
|
11
|
+
...serverEntry_original,
|
|
12
|
+
fetch: async (request, requestOpts) => {
|
|
13
|
+
render_deepLink_instead_of_home_on_authResponse: {
|
|
14
|
+
const url = new URL(request.url);
|
|
15
|
+
|
|
16
|
+
const stateUrlParamValue = url.searchParams.get("state");
|
|
17
|
+
|
|
18
|
+
if (stateUrlParamValue === null) {
|
|
19
|
+
break render_deepLink_instead_of_home_on_authResponse;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { stateDataCookies } = getStateDataCookies({
|
|
23
|
+
cookieHeaderParamValue: request.headers.get("cookie")
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const entry = stateDataCookies.find(
|
|
27
|
+
entry => entry.stateUrlParamValue === stateUrlParamValue
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (entry === undefined) {
|
|
31
|
+
break render_deepLink_instead_of_home_on_authResponse;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { stateDataCookie } = entry;
|
|
35
|
+
|
|
36
|
+
const rootRelativeRedirectUrl = (() => {
|
|
37
|
+
if (
|
|
38
|
+
stateDataCookie.action === "login" &&
|
|
39
|
+
url.searchParams.get("error") === "consent_required"
|
|
40
|
+
) {
|
|
41
|
+
return stateDataCookie.rootRelativeRedirectUrl_consentRequiredCase;
|
|
42
|
+
}
|
|
43
|
+
return stateDataCookie.rootRelativeRedirectUrl;
|
|
44
|
+
})();
|
|
45
|
+
|
|
46
|
+
url.pathname = "/";
|
|
47
|
+
url.search = "";
|
|
48
|
+
url.hash = "";
|
|
49
|
+
|
|
50
|
+
const url_str_new = `${url.href.slice(0, -1)}${rootRelativeRedirectUrl}`;
|
|
51
|
+
|
|
52
|
+
const request_new = new Request(url_str_new, request);
|
|
53
|
+
|
|
54
|
+
return serverEntry_original.fetch(request_new, requestOpts);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return serverEntry_original.fetch(request, requestOpts);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import type { OidcSpaVitePluginParams } from "./vite-plugin";
|
|
2
2
|
import type { ResolvedConfig } from "vite";
|
|
3
3
|
import type { PluginContext } from "rollup";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
5
4
|
import { promises as fs } from "node:fs";
|
|
6
5
|
import * as path from "node:path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
import { normalizePath } from "vite";
|
|
9
6
|
import { assert } from "../tools/tsafe/assert";
|
|
10
7
|
import type { Equals } from "../tools/tsafe/Equals";
|
|
11
8
|
import type { ProjectType } from "./projectType";
|
|
9
|
+
import {
|
|
10
|
+
resolveCandidate,
|
|
11
|
+
resolvePackageFile,
|
|
12
|
+
normalizeAbsolute,
|
|
13
|
+
splitId,
|
|
14
|
+
normalizeRequestPath
|
|
15
|
+
} from "./utils";
|
|
12
16
|
|
|
13
17
|
type EntryResolution = {
|
|
14
18
|
absolutePath: string;
|
|
@@ -29,7 +33,7 @@ const REACT_ROUTER_ENTRY_CANDIDATES = [
|
|
|
29
33
|
|
|
30
34
|
const TANSTACK_ENTRY_CANDIDATES = ["client.tsx", "client.ts", "client.jsx", "client.js"];
|
|
31
35
|
|
|
32
|
-
export function
|
|
36
|
+
export function createHandleClientEntrypoint(params: {
|
|
33
37
|
oidcSpaVitePluginParams: OidcSpaVitePluginParams;
|
|
34
38
|
resolvedConfig: ResolvedConfig;
|
|
35
39
|
projectType: ProjectType;
|
|
@@ -41,7 +45,7 @@ export function createLoadHandleEntrypoint(params: {
|
|
|
41
45
|
projectType
|
|
42
46
|
});
|
|
43
47
|
|
|
44
|
-
async function
|
|
48
|
+
async function load_handleClientEntrypoint(params: {
|
|
45
49
|
id: string;
|
|
46
50
|
pluginContext: PluginContext;
|
|
47
51
|
}): Promise<null | string> {
|
|
@@ -77,7 +81,6 @@ export function createLoadHandleEntrypoint(params: {
|
|
|
77
81
|
` freezeWebSocket: ${freezeWebSocket},`,
|
|
78
82
|
` freezePromise: ${freezePromise},`,
|
|
79
83
|
` safeMode: ${safeMode},`,
|
|
80
|
-
` isPostLoginRedirectManual: ${projectType === "tanstack-start"},`,
|
|
81
84
|
` BASE_URL: "${resolvedConfig.base}"`,
|
|
82
85
|
`});`,
|
|
83
86
|
``,
|
|
@@ -93,7 +96,7 @@ export function createLoadHandleEntrypoint(params: {
|
|
|
93
96
|
return stubSourceCache;
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
return
|
|
99
|
+
return { load_handleClientEntrypoint };
|
|
97
100
|
}
|
|
98
101
|
|
|
99
102
|
function resolveEntryForProject({
|
|
@@ -192,63 +195,3 @@ function loadOriginalModule(
|
|
|
192
195
|
entry.watchFiles.forEach(file => context.addWatchFile(file));
|
|
193
196
|
return fs.readFile(entry.absolutePath, "utf8");
|
|
194
197
|
}
|
|
195
|
-
|
|
196
|
-
function resolveCandidate({
|
|
197
|
-
root,
|
|
198
|
-
subDirectories,
|
|
199
|
-
filenames
|
|
200
|
-
}: {
|
|
201
|
-
root: string;
|
|
202
|
-
subDirectories: string[];
|
|
203
|
-
filenames: string[];
|
|
204
|
-
}): string | undefined {
|
|
205
|
-
for (const subDirectory of subDirectories) {
|
|
206
|
-
for (const filename of filenames) {
|
|
207
|
-
const candidate = path.resolve(root, subDirectory, filename);
|
|
208
|
-
if (existsSync(candidate)) {
|
|
209
|
-
return candidate;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return undefined;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function resolvePackageFile(packageName: string, segments: string[]): string {
|
|
217
|
-
const pkgPath = require.resolve(`${packageName}/package.json`);
|
|
218
|
-
return path.resolve(path.dirname(pkgPath), ...segments);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function normalizeAbsolute(filePath: string): string {
|
|
222
|
-
return normalizePath(filePath);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function splitId(id: string): { path: string; queryParams: URLSearchParams } {
|
|
226
|
-
const queryIndex = id.indexOf("?");
|
|
227
|
-
if (queryIndex === -1) {
|
|
228
|
-
return { path: id, queryParams: new URLSearchParams() };
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const pathPart = id.slice(0, queryIndex);
|
|
232
|
-
const queryString = id.slice(queryIndex + 1);
|
|
233
|
-
return { path: pathPart, queryParams: new URLSearchParams(queryString) };
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function normalizeRequestPath(id: string): string {
|
|
237
|
-
let requestPath = id;
|
|
238
|
-
|
|
239
|
-
if (requestPath.startsWith("\0")) {
|
|
240
|
-
requestPath = requestPath.slice(1);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (requestPath.startsWith("/@fs/")) {
|
|
244
|
-
requestPath = requestPath.slice("/@fs/".length);
|
|
245
|
-
} else if (requestPath.startsWith("file://")) {
|
|
246
|
-
requestPath = fileURLToPath(requestPath);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (path.isAbsolute(requestPath) || requestPath.startsWith(".")) {
|
|
250
|
-
return normalizePath(requestPath);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return normalizePath(requestPath);
|
|
254
|
-
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { ResolvedConfig } from "vite";
|
|
2
|
+
import type { PluginContext } from "rollup";
|
|
3
|
+
import { promises as fs } from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { assert } from "../tools/tsafe/assert";
|
|
6
|
+
import type { Equals } from "../tools/tsafe/Equals";
|
|
7
|
+
import type { ProjectType } from "./projectType";
|
|
8
|
+
import {
|
|
9
|
+
resolveCandidate,
|
|
10
|
+
resolvePackageFile,
|
|
11
|
+
normalizeAbsolute,
|
|
12
|
+
splitId,
|
|
13
|
+
normalizeRequestPath
|
|
14
|
+
} from "./utils";
|
|
15
|
+
|
|
16
|
+
type EntryResolution = {
|
|
17
|
+
absolutePath: string;
|
|
18
|
+
normalizedPath: string;
|
|
19
|
+
watchFiles: string[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const ORIGINAL_QUERY_PARAM = "oidc-spa-original";
|
|
23
|
+
|
|
24
|
+
export function createHandleServerEntrypoint(params: {
|
|
25
|
+
resolvedConfig: ResolvedConfig;
|
|
26
|
+
projectType: ProjectType;
|
|
27
|
+
}) {
|
|
28
|
+
const { resolvedConfig, projectType } = params;
|
|
29
|
+
|
|
30
|
+
const entryResolution = resolveEntryForProject({
|
|
31
|
+
config: resolvedConfig,
|
|
32
|
+
projectType
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
async function load_handleServerEntrypoint(params: {
|
|
36
|
+
id: string;
|
|
37
|
+
pluginContext: PluginContext;
|
|
38
|
+
}): Promise<null | string> {
|
|
39
|
+
if (entryResolution === undefined) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { id, pluginContext } = params;
|
|
44
|
+
const { path: rawPath, queryParams } = splitId(id);
|
|
45
|
+
const normalizedRequestPath = normalizeRequestPath(rawPath);
|
|
46
|
+
if (!normalizedRequestPath) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (normalizedRequestPath !== entryResolution.normalizedPath) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const isOriginalRequest = queryParams.getAll(ORIGINAL_QUERY_PARAM).includes("true");
|
|
55
|
+
|
|
56
|
+
if (isOriginalRequest) {
|
|
57
|
+
return loadOriginalModule(entryResolution, pluginContext);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
entryResolution.watchFiles.forEach(file => pluginContext.addWatchFile(file));
|
|
61
|
+
|
|
62
|
+
const stubSourceCache = [
|
|
63
|
+
`import serverEntry_original from "./${path.basename(
|
|
64
|
+
entryResolution.absolutePath
|
|
65
|
+
)}?${ORIGINAL_QUERY_PARAM}=true";`,
|
|
66
|
+
`import { __withOidcSpaServerEntry } from "oidc-spa/react-tanstack-start";`,
|
|
67
|
+
``,
|
|
68
|
+
`const serverEntry = __withOidcSpaServerEntry(serverEntry_original);`,
|
|
69
|
+
``,
|
|
70
|
+
`export default serverEntry;`
|
|
71
|
+
].join("\n");
|
|
72
|
+
|
|
73
|
+
return stubSourceCache;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return { load_handleServerEntrypoint };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function resolveEntryForProject({
|
|
80
|
+
config,
|
|
81
|
+
projectType
|
|
82
|
+
}: {
|
|
83
|
+
config: ResolvedConfig;
|
|
84
|
+
projectType: ProjectType;
|
|
85
|
+
}): EntryResolution | undefined {
|
|
86
|
+
const root = config.root;
|
|
87
|
+
|
|
88
|
+
switch (projectType) {
|
|
89
|
+
case "tanstack-start": {
|
|
90
|
+
const candidate = resolveCandidate({
|
|
91
|
+
root,
|
|
92
|
+
subDirectories: ["src"],
|
|
93
|
+
filenames: ["server.ts", "server.js", "server.tsx", "server.jsx"]
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const entryPath =
|
|
97
|
+
candidate ??
|
|
98
|
+
resolvePackageFile("@tanstack/react-start", [
|
|
99
|
+
"dist",
|
|
100
|
+
"plugin",
|
|
101
|
+
"default-entry",
|
|
102
|
+
"server.ts"
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
const normalized = normalizeAbsolute(entryPath);
|
|
106
|
+
|
|
107
|
+
const resolution: EntryResolution = {
|
|
108
|
+
absolutePath: entryPath,
|
|
109
|
+
normalizedPath: normalized,
|
|
110
|
+
watchFiles: [entryPath]
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return resolution;
|
|
114
|
+
}
|
|
115
|
+
case "react-router-framework":
|
|
116
|
+
case "other":
|
|
117
|
+
return undefined;
|
|
118
|
+
default:
|
|
119
|
+
assert<Equals<typeof projectType, never>>(false);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function loadOriginalModule(
|
|
124
|
+
entry: EntryResolution,
|
|
125
|
+
context: { addWatchFile(id: string): void }
|
|
126
|
+
): Promise<string> {
|
|
127
|
+
entry.watchFiles.forEach(file => context.addWatchFile(file));
|
|
128
|
+
return fs.readFile(entry.absolutePath, "utf8");
|
|
129
|
+
}
|