oidc-spa 8.3.5 → 8.3.7

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 (75) hide show
  1. package/core/StateDataCookie.d.ts +34 -0
  2. package/core/StateDataCookie.js +142 -0
  3. package/core/StateDataCookie.js.map +1 -0
  4. package/core/createOidc.js +23 -5
  5. package/core/createOidc.js.map +1 -1
  6. package/core/earlyInit.d.ts +0 -1
  7. package/core/earlyInit.js +4 -13
  8. package/core/earlyInit.js.map +1 -1
  9. package/core/loginOrGoToAuthServer.d.ts +1 -0
  10. package/core/loginOrGoToAuthServer.js +20 -9
  11. package/core/loginOrGoToAuthServer.js.map +1 -1
  12. package/entrypoint.d.ts +0 -1
  13. package/entrypoint.js +1 -3
  14. package/entrypoint.js.map +1 -1
  15. package/esm/core/StateDataCookie.d.ts +34 -0
  16. package/esm/core/StateDataCookie.js +135 -0
  17. package/esm/core/StateDataCookie.js.map +1 -0
  18. package/esm/core/createOidc.js +23 -5
  19. package/esm/core/createOidc.js.map +1 -1
  20. package/esm/core/earlyInit.d.ts +0 -1
  21. package/esm/core/earlyInit.js +4 -13
  22. package/esm/core/earlyInit.js.map +1 -1
  23. package/esm/core/loginOrGoToAuthServer.d.ts +1 -0
  24. package/esm/core/loginOrGoToAuthServer.js +20 -9
  25. package/esm/core/loginOrGoToAuthServer.js.map +1 -1
  26. package/esm/entrypoint.d.ts +0 -1
  27. package/esm/entrypoint.js +0 -1
  28. package/esm/entrypoint.js.map +1 -1
  29. package/esm/tanstack-start/react/createOidcSpaApi.js +2 -0
  30. package/esm/tanstack-start/react/createOidcSpaApi.js.map +1 -1
  31. package/esm/tanstack-start/react/index.d.ts +1 -1
  32. package/esm/tanstack-start/react/index.js +1 -1
  33. package/esm/tanstack-start/react/index.js.map +1 -1
  34. package/esm/tanstack-start/react/withOidcSpaServerEntry.d.ts +5 -0
  35. package/esm/tanstack-start/react/withOidcSpaServerEntry.js +38 -0
  36. package/esm/tanstack-start/react/withOidcSpaServerEntry.js.map +1 -0
  37. package/package.json +1 -1
  38. package/src/core/StateDataCookie.ts +217 -0
  39. package/src/core/createOidc.ts +32 -4
  40. package/src/core/earlyInit.ts +3 -17
  41. package/src/core/loginOrGoToAuthServer.ts +25 -9
  42. package/src/entrypoint.ts +0 -1
  43. package/src/tanstack-start/react/createOidcSpaApi.tsx +3 -0
  44. package/src/tanstack-start/react/index.ts +1 -1
  45. package/src/tanstack-start/react/withOidcSpaServerEntry.ts +60 -0
  46. package/src/vite-plugin/handleClientEntrypoint.ts +10 -67
  47. package/src/vite-plugin/handleServerEntrypoint.ts +129 -0
  48. package/src/vite-plugin/transformTanstackRouterCreateFileRoute.ts +0 -64
  49. package/src/vite-plugin/utils.ts +64 -0
  50. package/src/vite-plugin/vite-plugin.ts +31 -10
  51. package/vite-plugin/handleClientEntrypoint.d.ts +7 -5
  52. package/vite-plugin/handleClientEntrypoint.js +16 -62
  53. package/vite-plugin/handleClientEntrypoint.js.map +1 -1
  54. package/vite-plugin/handleServerEntrypoint.d.ts +12 -0
  55. package/vite-plugin/handleServerEntrypoint.js +113 -0
  56. package/vite-plugin/handleServerEntrypoint.js.map +1 -0
  57. package/vite-plugin/transformTanstackRouterCreateFileRoute.js +0 -39
  58. package/vite-plugin/transformTanstackRouterCreateFileRoute.js.map +1 -1
  59. package/vite-plugin/utils.d.ts +12 -0
  60. package/vite-plugin/utils.js +88 -0
  61. package/vite-plugin/utils.js.map +1 -0
  62. package/vite-plugin/vite-plugin.d.ts +1 -1
  63. package/vite-plugin/vite-plugin.js +21 -5
  64. package/vite-plugin/vite-plugin.js.map +1 -1
  65. package/core/requiredPostHydrationReplaceNavigationUrl.d.ts +0 -6
  66. package/core/requiredPostHydrationReplaceNavigationUrl.js +0 -12
  67. package/core/requiredPostHydrationReplaceNavigationUrl.js.map +0 -1
  68. package/esm/core/requiredPostHydrationReplaceNavigationUrl.d.ts +0 -6
  69. package/esm/core/requiredPostHydrationReplaceNavigationUrl.js +0 -8
  70. package/esm/core/requiredPostHydrationReplaceNavigationUrl.js.map +0 -1
  71. package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.d.ts +0 -2
  72. package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js +0 -36
  73. package/esm/tanstack-start/react/withHandlingOidcPostLoginNavigation.js.map +0 -1
  74. package/src/core/requiredPostHydrationReplaceNavigationUrl.ts +0 -11
  75. package/src/tanstack-start/react/withHandlingOidcPostLoginNavigation.tsx +0 -46
@@ -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({ isPostLoginRedirectManual });
40
+ const { shouldLoadApp } = handleOidcCallback();
44
41
 
45
42
  if (shouldLoadApp) {
46
43
  const createWriteError = (target: string) =>
@@ -160,8 +157,6 @@ export function oidcEarlyInit(params: {
160
157
  }
161
158
  }
162
159
 
163
- Object.freeze(original);
164
-
165
160
  Object.defineProperty(window, name, {
166
161
  configurable: false,
167
162
  enumerable: true,
@@ -287,11 +282,9 @@ export function getRootRelativeOriginalLocationHref() {
287
282
  return rootRelativeOriginalLocationHref;
288
283
  }
289
284
 
290
- function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
285
+ function handleOidcCallback(): {
291
286
  shouldLoadApp: boolean;
292
287
  } {
293
- const { isPostLoginRedirectManual } = params;
294
-
295
288
  const location_urlObj = new URL(window.location.href);
296
289
 
297
290
  const locationHrefAssessment = (() => {
@@ -392,7 +385,6 @@ function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
392
385
  return { shouldLoadApp: false };
393
386
  case "redirect": {
394
387
  redirectAuthResponse = authResponse;
395
-
396
388
  const rootRelativeRedirectUrl = (() => {
397
389
  if (stateData.action === "login" && authResponse.error === "consent_required") {
398
390
  return stateData.rootRelativeRedirectUrl_consentRequiredCase;
@@ -400,13 +392,7 @@ function handleOidcCallback(params: { isPostLoginRedirectManual?: boolean }): {
400
392
  return stateData.rootRelativeRedirectUrl;
401
393
  })();
402
394
 
403
- if (isPostLoginRedirectManual) {
404
- setOidcRequiredPostHydrationReplaceNavigationUrl({ rootRelativeRedirectUrl });
405
- history.replaceState({}, "", rootRelativeOriginalLocationHref);
406
- } else {
407
- history.replaceState({}, "", rootRelativeRedirectUrl);
408
- }
409
-
395
+ history.replaceState({}, "", rootRelativeRedirectUrl);
410
396
  return { shouldLoadApp: true };
411
397
  }
412
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 stateData: StateData = {
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
@@ -1,2 +1 @@
1
1
  export { oidcEarlyInit } from "./core/earlyInit";
2
- export { getOidcRequiredPostHydrationReplaceNavigationUrl } from "./core/requiredPostHydrationReplaceNavigationUrl";
@@ -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 createLoadHandleEntrypoint(params: {
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 loadHandleEntrypoint(params: {
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 loadHandleEntrypoint;
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
+ }
@@ -4,8 +4,6 @@ import { babelParser, babelTraverse, babelTypes as t } from "../vendor/build-run
4
4
  const DISABLE_SSR_SPECIFIER = "__disableSsrIfLoginEnforced";
5
5
  const DISABLE_SSR_SOURCE = "oidc-spa/react-tanstack-start";
6
6
  const CREATE_FILE_ROUTE_IDENTIFIER = "createFileRoute";
7
- const POST_LOGIN_IMPORT_SPECIFIER = "withHandlingOidcPostLoginNavigation";
8
- const POST_LOGIN_IMPORT_SOURCE = "oidc-spa/react-tanstack-start";
9
7
 
10
8
  type TransformParams = {
11
9
  code: string;
@@ -38,9 +36,7 @@ export function transformCreateFileRoute(params: TransformParams): TransformResu
38
36
  const magicString = new MagicString(code);
39
37
  let hasCreateFileRouteImport = false;
40
38
  let hasEnableImport = false;
41
- let hasPostLoginImport = false;
42
39
  let requiresEnableImport = false;
43
- let requiresPostLoginImport = false;
44
40
  let lastImportEnd: number | undefined;
45
41
  let mutated = false;
46
42
 
@@ -79,18 +75,6 @@ export function transformCreateFileRoute(params: TransformParams): TransformResu
79
75
  hasEnableImport = true;
80
76
  }
81
77
  }
82
-
83
- if (sourceValue === POST_LOGIN_IMPORT_SOURCE) {
84
- if (
85
- path.node.specifiers.some(
86
- specifier =>
87
- t.isImportSpecifier(specifier) &&
88
- t.isIdentifier(specifier.imported, { name: POST_LOGIN_IMPORT_SPECIFIER })
89
- )
90
- ) {
91
- hasPostLoginImport = true;
92
- }
93
- }
94
78
  },
95
79
  CallExpression(path) {
96
80
  const callee = path.get("callee");
@@ -128,33 +112,6 @@ export function transformCreateFileRoute(params: TransformParams): TransformResu
128
112
  }
129
113
  }
130
114
 
131
- const innerArgs = callee.node.arguments ?? [];
132
- const isRootRoute =
133
- innerArgs.length > 0 && t.isStringLiteral(innerArgs[0]) && innerArgs[0].value === "/";
134
-
135
- if (isRootRoute) {
136
- const componentProp = findComponentProperty(configNode);
137
- if (componentProp) {
138
- const valueNode = componentProp.value as t.Expression;
139
-
140
- if (!isWrappedWithHandling(valueNode)) {
141
- const start = valueNode.start ?? undefined;
142
- const end = valueNode.end ?? undefined;
143
-
144
- if (typeof start === "number" && typeof end === "number") {
145
- const original = code.slice(start, end);
146
- magicString.overwrite(
147
- start,
148
- end,
149
- `${POST_LOGIN_IMPORT_SPECIFIER}(${original})`
150
- );
151
- requiresPostLoginImport = true;
152
- localMutated = true;
153
- }
154
- }
155
- }
156
- }
157
-
158
115
  if (localMutated) {
159
116
  mutated = true;
160
117
  }
@@ -171,12 +128,6 @@ export function transformCreateFileRoute(params: TransformParams): TransformResu
171
128
  importStatements.push(`import { ${DISABLE_SSR_SPECIFIER} } from "${DISABLE_SSR_SOURCE}";`);
172
129
  }
173
130
 
174
- if (requiresPostLoginImport && !hasPostLoginImport) {
175
- importStatements.push(
176
- `import { ${POST_LOGIN_IMPORT_SPECIFIER} } from "${POST_LOGIN_IMPORT_SOURCE}";`
177
- );
178
- }
179
-
180
131
  if (importStatements.length > 0) {
181
132
  const insertionPoint = lastImportEnd ?? 0;
182
133
  const prefix = insertionPoint === 0 ? "" : "\n";
@@ -190,15 +141,6 @@ export function transformCreateFileRoute(params: TransformParams): TransformResu
190
141
  };
191
142
  }
192
143
 
193
- function findComponentProperty(node: t.ObjectExpression): t.ObjectProperty | undefined {
194
- return node.properties.find(
195
- prop =>
196
- t.isObjectProperty(prop) &&
197
- ((t.isIdentifier(prop.key) && prop.key.name === "component") ||
198
- (t.isStringLiteral(prop.key) && prop.key.value === "component"))
199
- ) as t.ObjectProperty | undefined;
200
- }
201
-
202
144
  function objectContainsLoaderOrBeforeLoad(node: t.ObjectExpression): boolean {
203
145
  return node.properties.some(prop => {
204
146
  if (!t.isObjectProperty(prop)) {
@@ -218,12 +160,6 @@ function objectContainsLoaderOrBeforeLoad(node: t.ObjectExpression): boolean {
218
160
  });
219
161
  }
220
162
 
221
- function isWrappedWithHandling(node: t.Node): boolean {
222
- return (
223
- t.isCallExpression(node) && t.isIdentifier(node.callee, { name: POST_LOGIN_IMPORT_SPECIFIER })
224
- );
225
- }
226
-
227
163
  function isCandidateFile(id: string): boolean {
228
164
  if (id.includes("node_modules")) {
229
165
  return false;
@@ -0,0 +1,64 @@
1
+ import { existsSync } from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { normalizePath } from "vite";
5
+
6
+ export function resolveCandidate({
7
+ root,
8
+ subDirectories,
9
+ filenames
10
+ }: {
11
+ root: string;
12
+ subDirectories: string[];
13
+ filenames: string[];
14
+ }): string | undefined {
15
+ for (const subDirectory of subDirectories) {
16
+ for (const filename of filenames) {
17
+ const candidate = path.resolve(root, subDirectory, filename);
18
+ if (existsSync(candidate)) {
19
+ return candidate;
20
+ }
21
+ }
22
+ }
23
+ return undefined;
24
+ }
25
+
26
+ export function resolvePackageFile(packageName: string, segments: string[]): string {
27
+ const pkgPath = require.resolve(`${packageName}/package.json`);
28
+ return path.resolve(path.dirname(pkgPath), ...segments);
29
+ }
30
+
31
+ export function normalizeAbsolute(filePath: string): string {
32
+ return normalizePath(filePath);
33
+ }
34
+
35
+ export function splitId(id: string): { path: string; queryParams: URLSearchParams } {
36
+ const queryIndex = id.indexOf("?");
37
+ if (queryIndex === -1) {
38
+ return { path: id, queryParams: new URLSearchParams() };
39
+ }
40
+
41
+ const pathPart = id.slice(0, queryIndex);
42
+ const queryString = id.slice(queryIndex + 1);
43
+ return { path: pathPart, queryParams: new URLSearchParams(queryString) };
44
+ }
45
+
46
+ export function normalizeRequestPath(id: string): string {
47
+ let requestPath = id;
48
+
49
+ if (requestPath.startsWith("\0")) {
50
+ requestPath = requestPath.slice(1);
51
+ }
52
+
53
+ if (requestPath.startsWith("/@fs/")) {
54
+ requestPath = requestPath.slice("/@fs/".length);
55
+ } else if (requestPath.startsWith("file://")) {
56
+ requestPath = fileURLToPath(requestPath);
57
+ }
58
+
59
+ if (path.isAbsolute(requestPath) || requestPath.startsWith(".")) {
60
+ return normalizePath(requestPath);
61
+ }
62
+
63
+ return normalizePath(requestPath);
64
+ }