@stackframe/tanstack-start 2.8.93 → 2.8.94

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 (31) hide show
  1. package/dist/esm/lib/auth.d.ts +3 -1
  2. package/dist/esm/lib/auth.d.ts.map +1 -1
  3. package/dist/esm/lib/auth.js +4 -4
  4. package/dist/esm/lib/auth.js.map +1 -1
  5. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  6. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.d.ts +30 -3
  7. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  8. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +193 -30
  9. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  10. package/dist/esm/lib/stack-app/apps/implementations/common.js +1 -1
  11. package/dist/esm/lib/stack-app/url-targets.d.ts.map +1 -1
  12. package/dist/esm/lib/stack-app/url-targets.js +10 -1
  13. package/dist/esm/lib/stack-app/url-targets.js.map +1 -1
  14. package/dist/esm/lib/stack-app/url-targets.test.js +32 -0
  15. package/dist/esm/lib/stack-app/url-targets.test.js.map +1 -1
  16. package/dist/lib/auth.d.ts +3 -1
  17. package/dist/lib/auth.d.ts.map +1 -1
  18. package/dist/lib/auth.js +4 -4
  19. package/dist/lib/auth.js.map +1 -1
  20. package/dist/lib/stack-app/apps/implementations/admin-app-impl.d.ts.map +1 -1
  21. package/dist/lib/stack-app/apps/implementations/client-app-impl.d.ts +30 -3
  22. package/dist/lib/stack-app/apps/implementations/client-app-impl.d.ts.map +1 -1
  23. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +191 -28
  24. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  25. package/dist/lib/stack-app/apps/implementations/common.js +1 -1
  26. package/dist/lib/stack-app/url-targets.d.ts.map +1 -1
  27. package/dist/lib/stack-app/url-targets.js +10 -1
  28. package/dist/lib/stack-app/url-targets.js.map +1 -1
  29. package/dist/lib/stack-app/url-targets.test.js +32 -0
  30. package/dist/lib/stack-app/url-targets.test.js.map +1 -1
  31. package/package.json +3 -3
@@ -21,6 +21,7 @@ let _simplewebauthn_browser = require("@simplewebauthn/browser");
21
21
  let _stackframe_stack_shared_dist_sessions = require("@stackframe/stack-shared/dist/sessions");
22
22
  let _stackframe_stack_shared_dist_utils_json = require("@stackframe/stack-shared/dist/utils/json");
23
23
  let _stackframe_stack_shared_dist_utils_maps = require("@stackframe/stack-shared/dist/utils/maps");
24
+ let _stackframe_stack_shared_dist_utils_redirect_urls = require("@stackframe/stack-shared/dist/utils/redirect-urls");
24
25
  let _stackframe_stack_shared_dist_utils_stores = require("@stackframe/stack-shared/dist/utils/stores");
25
26
  let _stackframe_stack_shared_dist_utils_turnstile_flow = require("@stackframe/stack-shared/dist/utils/turnstile-flow");
26
27
  let _stackframe_stack_shared_dist_utils_uuids = require("@stackframe/stack-shared/dist/utils/uuids");
@@ -45,6 +46,24 @@ let ____________dev_tool_index_js = require("../../../../dev-tool/index.js");
45
46
 
46
47
  //#region src/lib/stack-app/apps/implementations/client-app-impl.ts
47
48
  const prefetchedCrossDomainHandoffTtlMs = 3300 * 1e3;
49
+ const nestedCrossDomainAuthQueryParams = {
50
+ refreshTokenId: "stack_nested_cross_domain_auth_refresh_token_id",
51
+ callbackUrl: "stack_nested_cross_domain_auth_callback_url",
52
+ redirectUri: "redirect_uri",
53
+ state: "state",
54
+ codeChallenge: "code_challenge",
55
+ codeChallengeMethod: "code_challenge_method",
56
+ afterCallbackRedirectUrl: "after_callback_redirect_url"
57
+ };
58
+ const oauthCallbackResponseQueryParams = [
59
+ "code",
60
+ "state",
61
+ "error",
62
+ "error_description",
63
+ "errorCode",
64
+ "message",
65
+ "details"
66
+ ];
48
67
  const allClientApps = /* @__PURE__ */ new Map();
49
68
  const STACK_AUTHORIZATION_VALUE_PREFIX = "stackauth_";
50
69
  function getAuthorizationHeaderValueFromAuthJson(authJson) {
@@ -112,7 +131,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
112
131
  `);
113
132
  const location = await (0, _________auth_js.getNewOAuthProviderOrScopeUrl)(this._interface, {
114
133
  provider: options.providerId,
115
- redirectUrl: this.urls.oauthCallback,
134
+ redirectUrl: this._getOAuthCallbackRedirectUri(),
116
135
  errorRedirectUrl: this.urls.error,
117
136
  providerScope: (0, _stackframe_stack_shared_dist_utils_strings.mergeScopeStrings)(options.scope || "", (this._oauthScopesOnSignIn[options.providerId] ?? []).join(" "))
118
137
  }, options.session);
@@ -247,7 +266,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
247
266
  for (const account of matchingAccounts) if ((await account.getAccessToken({ scopes })).status === "ok") return account;
248
267
  const location = await (0, _________auth_js.getNewOAuthProviderOrScopeUrl)(this._interface, {
249
268
  provider,
250
- redirectUrl: this.urls.oauthCallback,
269
+ redirectUrl: this._getOAuthCallbackRedirectUri(),
251
270
  errorRedirectUrl: this.urls.error,
252
271
  providerScope: (0, _stackframe_stack_shared_dist_utils_strings.mergeScopeStrings)(scopeString, (this._oauthScopesOnSignIn[provider] ?? []).join(" "))
253
272
  }, session);
@@ -351,6 +370,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
351
370
  this._prefetchedCrossDomainHandoffParams = null;
352
371
  this._prefetchedCrossDomainHandoffParamsFetchedAt = 0;
353
372
  this._isPrefetchingCrossDomainHandoffParams = false;
373
+ this._pendingAuthResolutionPromises = [];
354
374
  this._memoryTokenStore = (0, __common_js.createEmptyTokenStore)();
355
375
  this._nextServerCookiesTokenStores = /* @__PURE__ */ new WeakMap();
356
376
  this._requestTokenStores = /* @__PURE__ */ new WeakMap();
@@ -420,6 +440,12 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
420
440
  });
421
441
  this._eventTracker.start();
422
442
  }
443
+ if ((0, _stackframe_stack_shared_dist_utils_env.isBrowserLike)() && this._isOAuthCallbackUrlHosted() && this._currentUrlLooksLikeStackOAuthCallback()) this._trackPendingAuthResolution(async () => {
444
+ if ((0, _stackframe_stack_shared_dist_utils_env.isBrowserLike)()) await this.callOAuthCallback({ dontWarnAboutMissingQueryParams: true });
445
+ });
446
+ if ((0, _stackframe_stack_shared_dist_utils_env.isBrowserLike)()) this._trackPendingAuthResolution(async () => {
447
+ await this._maybeHandleNestedCrossDomainAuth();
448
+ });
423
449
  if ((0, _stackframe_stack_shared_dist_utils_env.isBrowserLike)() && resolvedOptions.devTool !== false) (0, ____________dev_tool_index_js.mountDevTool)(this);
424
450
  }
425
451
  _initUniqueIdentifier() {
@@ -427,6 +453,126 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
427
453
  if (allClientApps.has(this._uniqueIdentifier)) throw new _stackframe_stack_shared_dist_utils_errors.StackAssertionError("A Stack client app with the same unique identifier already exists");
428
454
  allClientApps.set(this._uniqueIdentifier, [this._extraOptions?.checkString ?? void 0, this]);
429
455
  }
456
+ _trackPendingAuthResolution(callback) {
457
+ const promise = (async () => {
458
+ await Promise.resolve();
459
+ try {
460
+ await callback();
461
+ } catch (error) {
462
+ (0, _stackframe_stack_shared_dist_utils_errors.captureError)("pending-auth-resolution-failed", error);
463
+ }
464
+ })();
465
+ this._pendingAuthResolutionPromises.push(promise);
466
+ (0, _stackframe_stack_shared_dist_utils_promises.runAsynchronously)(async () => {
467
+ try {
468
+ await promise;
469
+ } finally {
470
+ this._pendingAuthResolutionPromises = this._pendingAuthResolutionPromises.filter((p) => p !== promise);
471
+ }
472
+ });
473
+ }
474
+ async _awaitPendingAuthResolutions(overrideTokenStoreInit, options) {
475
+ if (options?.awaitPendingAuthResolutions === false || overrideTokenStoreInit !== void 0 || !this._hasPersistentTokenStore() || this._pendingAuthResolutionPromises.length === 0) return;
476
+ await Promise.all(this._pendingAuthResolutionPromises);
477
+ }
478
+ _usePendingAuthResolutions(overrideTokenStoreInit) {
479
+ if (overrideTokenStoreInit !== void 0 || !this._hasPersistentTokenStore() || this._pendingAuthResolutionPromises.length === 0) return;
480
+ (0, _stackframe_stack_shared_dist_utils_react.use)(Promise.all(this._pendingAuthResolutionPromises));
481
+ }
482
+ _isOAuthCallbackUrlHosted() {
483
+ const oauthCallbackTarget = this._urlOptions.oauthCallback ?? this._urlOptions.default;
484
+ return typeof oauthCallbackTarget !== "string" && oauthCallbackTarget?.type === "hosted";
485
+ }
486
+ _currentUrlLooksLikeOAuthCallback() {
487
+ if (typeof window === "undefined") return false;
488
+ const currentUrl = new URL(window.location.href);
489
+ return currentUrl.searchParams.has("code") && currentUrl.searchParams.has("state") || currentUrl.searchParams.has("errorCode") && currentUrl.searchParams.has("message");
490
+ }
491
+ _currentUrlLooksLikeStackOAuthCallback() {
492
+ if (typeof window === "undefined") return false;
493
+ const currentUrl = new URL(window.location.href);
494
+ const state = currentUrl.searchParams.get("state");
495
+ if (!currentUrl.searchParams.has("code") || state == null) return false;
496
+ return (0, _________cookie_js.getCookieClient)(`stack-oauth-outer-${state}`) != null;
497
+ }
498
+ _getOAuthCallbackRedirectUri() {
499
+ if (!this._isOAuthCallbackUrlHosted()) return this.urls.oauthCallback;
500
+ if (typeof window === "undefined") throw new _stackframe_stack_shared_dist_utils_errors.StackAssertionError("Hosted OAuth callback URLs require a browser environment to use the current URL as the redirect URI");
501
+ const currentUrl = new URL(window.location.href);
502
+ for (const param of oauthCallbackResponseQueryParams) currentUrl.searchParams.delete(param);
503
+ return currentUrl.toString();
504
+ }
505
+ async _getCurrentRefreshTokenIdIfSignedIn(options) {
506
+ const tokens = await (await this._getSession(void 0, options)).getOrFetchLikelyValidTokens(0, null);
507
+ if (tokens?.refreshToken == null) return null;
508
+ return tokens.accessToken.payload.refresh_token_id;
509
+ }
510
+ async _addNestedCrossDomainAuthParamsToRedirectUrl(options) {
511
+ const targetUrl = new URL(options.url, options.currentUrl);
512
+ if (targetUrl.origin === options.currentUrl.origin) return options.url;
513
+ const refreshTokenId = await this._getCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: options.awaitPendingAuthResolutions });
514
+ if (refreshTokenId == null) return options.url;
515
+ targetUrl.searchParams.set(nestedCrossDomainAuthQueryParams.refreshTokenId, refreshTokenId);
516
+ targetUrl.searchParams.set(nestedCrossDomainAuthQueryParams.callbackUrl, new URL(this._getOAuthCallbackRedirectUri(), options.currentUrl).toString());
517
+ return targetUrl.toString();
518
+ }
519
+ async _maybeHandleNestedCrossDomainAuth() {
520
+ if (typeof window === "undefined") return false;
521
+ const currentUrl = new URL(window.location.href);
522
+ if (currentUrl.searchParams.has("code") && currentUrl.searchParams.has("state")) return false;
523
+ const refreshTokenId = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.refreshTokenId);
524
+ if (refreshTokenId == null) return false;
525
+ const redirectUri = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.redirectUri);
526
+ const state = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.state);
527
+ const codeChallenge = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.codeChallenge);
528
+ if (redirectUri != null || state != null || codeChallenge != null) {
529
+ if (redirectUri == null || state == null || codeChallenge == null) throw new _stackframe_stack_shared_dist_utils_errors.StackAssertionError("Nested cross-domain auth callback URL is missing OAuth request parameters", {
530
+ redirectUri,
531
+ state,
532
+ codeChallenge
533
+ });
534
+ if ((currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.codeChallengeMethod) ?? "S256") !== "S256") throw new _stackframe_stack_shared_dist_utils_errors.StackAssertionError("Nested cross-domain auth only supports S256 PKCE");
535
+ if ((0, _stackframe_stack_shared_dist_utils_urls.isRelative)(redirectUri)) throw new Error("Nested cross-domain auth redirect URI must be absolute.");
536
+ const redirectUriUrl = new URL(redirectUri);
537
+ if (!await this._isTrusted(redirectUriUrl.toString())) throw new Error(`Nested cross-domain auth redirect URI ${redirectUri} is not trusted.`);
538
+ const afterCallbackRedirectUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.afterCallbackRedirectUrl);
539
+ const afterCallbackRedirectUrl = afterCallbackRedirectUrlString == null ? redirectUriUrl : new URL(afterCallbackRedirectUrlString, redirectUriUrl);
540
+ if (!await this._isTrusted(afterCallbackRedirectUrl.toString())) throw new Error(`Nested cross-domain auth after-callback redirect URL ${afterCallbackRedirectUrlString} is not trusted.`);
541
+ if (await this._getCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false }) !== refreshTokenId) throw new Error("Nested cross-domain auth source session does not match the requested refresh token ID.");
542
+ await this._redirectTo({
543
+ url: await this._createCrossDomainAuthRedirectUrl({
544
+ redirectUri: redirectUriUrl.toString(),
545
+ state,
546
+ codeChallenge,
547
+ afterCallbackRedirectUrl: afterCallbackRedirectUrl.toString(),
548
+ awaitPendingAuthResolutions: false
549
+ }),
550
+ replace: true
551
+ });
552
+ return true;
553
+ }
554
+ if (await this._getCurrentRefreshTokenIdIfSignedIn({ awaitPendingAuthResolutions: false }) === refreshTokenId) return false;
555
+ const callbackUrlString = currentUrl.searchParams.get(nestedCrossDomainAuthQueryParams.callbackUrl);
556
+ if (callbackUrlString == null) throw new _stackframe_stack_shared_dist_utils_errors.StackAssertionError("Nested cross-domain auth URL is missing callback URL");
557
+ if ((0, _stackframe_stack_shared_dist_utils_urls.isRelative)(callbackUrlString)) throw new Error("Nested cross-domain auth callback URL must be absolute.");
558
+ const callbackUrl = new URL(callbackUrlString);
559
+ if (!await this._isTrusted(callbackUrl.toString())) throw new Error(`Nested cross-domain auth callback URL ${callbackUrlString} is not trusted.`);
560
+ const afterCallbackRedirectUrl = new URL(currentUrl);
561
+ afterCallbackRedirectUrl.searchParams.delete(nestedCrossDomainAuthQueryParams.refreshTokenId);
562
+ afterCallbackRedirectUrl.searchParams.delete(nestedCrossDomainAuthQueryParams.callbackUrl);
563
+ const { state: newState, codeChallenge: newCodeChallenge } = await this._getCrossDomainHandoffParamsForRedirect(currentUrl);
564
+ callbackUrl.searchParams.set(nestedCrossDomainAuthQueryParams.refreshTokenId, refreshTokenId);
565
+ callbackUrl.searchParams.set(nestedCrossDomainAuthQueryParams.redirectUri, new URL(this._getOAuthCallbackRedirectUri(), currentUrl).toString());
566
+ callbackUrl.searchParams.set(nestedCrossDomainAuthQueryParams.state, newState);
567
+ callbackUrl.searchParams.set(nestedCrossDomainAuthQueryParams.codeChallenge, newCodeChallenge);
568
+ callbackUrl.searchParams.set(nestedCrossDomainAuthQueryParams.codeChallengeMethod, "S256");
569
+ callbackUrl.searchParams.set(nestedCrossDomainAuthQueryParams.afterCallbackRedirectUrl, afterCallbackRedirectUrl.toString());
570
+ await this._redirectTo({
571
+ url: callbackUrl,
572
+ replace: true
573
+ });
574
+ return true;
575
+ }
430
576
  /**
431
577
  * Cloudflare workers does not allow use of randomness on the global scope (on which the Stack app is probably
432
578
  * initialized). For that reason, we generate the unique identifier lazily when it is first needed instead of in the
@@ -619,15 +765,15 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
619
765
  await (0, _________cookie_js.setOrDeleteCookie)(this._getRefreshTokenDefaultCookieNameForSecure(isSecure), null, cookieOptions);
620
766
  });
621
767
  }
768
+ async _getTrustedRedirectConfig() {
769
+ const project = _stackframe_stack_shared_dist_utils_results.Result.orThrow(await this._currentProjectCache.getOrWait([], "write-only"));
770
+ return {
771
+ allowLocalhost: project.config.allow_localhost,
772
+ trustedDomains: project.config.domains.map((d) => d.domain)
773
+ };
774
+ }
622
775
  async _getTrustedParentDomain(currentDomain) {
623
- const domains = _stackframe_stack_shared_dist_utils_results.Result.orThrow(await this._interface.getClientProject()).config.domains.map((d) => d.domain.trim().replace(/^https?:\/\//, "").split("/")[0]?.toLowerCase());
624
- const trustedWildcards = domains.filter((d) => d.startsWith("**."));
625
- const parts = currentDomain.split(".");
626
- for (let i = parts.length - 2; i >= 0; i--) {
627
- const parentDomain = parts.slice(i).join(".");
628
- if (domains.includes(parentDomain) && trustedWildcards.includes("**." + parentDomain)) return parentDomain;
629
- }
630
- return null;
776
+ return (0, _stackframe_stack_shared_dist_utils_redirect_urls.getTrustedParentDomain)(currentDomain, (await this._getTrustedRedirectConfig()).trustedDomains);
631
777
  }
632
778
  _getBrowserCookieTokenStore() {
633
779
  if (!(0, _stackframe_stack_shared_dist_utils_env.isBrowserLike)()) throw new Error("Cannot use cookie token store on the server!");
@@ -784,11 +930,13 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
784
930
  sessionsBySessionKey.set(sessionKey, session);
785
931
  return session;
786
932
  }
787
- async _getSession(overrideTokenStoreInit) {
933
+ async _getSession(overrideTokenStoreInit, options) {
934
+ await this._awaitPendingAuthResolutions(overrideTokenStoreInit, options);
788
935
  const tokenStore = this._getOrCreateTokenStore(await this._createCookieHelper(overrideTokenStoreInit), overrideTokenStoreInit);
789
936
  return this._getSessionFromTokenStore(tokenStore);
790
937
  }
791
938
  _useSession(overrideTokenStoreInit) {
939
+ this._usePendingAuthResolutions(overrideTokenStoreInit);
792
940
  const tokenStore = this._useTokenStore(overrideTokenStoreInit);
793
941
  const subscribe = (0, react.useCallback)((cb) => {
794
942
  return (0, __session_refresh_subscription_js.subscribeSessionRefresh)({
@@ -1244,7 +1392,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1244
1392
  const scopeString = options?.scopes?.join(" ") ?? "";
1245
1393
  const location = await (0, _________auth_js.getNewOAuthProviderOrScopeUrl)(app._interface, {
1246
1394
  provider,
1247
- redirectUrl: app.urls.oauthCallback,
1395
+ redirectUrl: app._getOAuthCallbackRedirectUri(),
1248
1396
  errorRedirectUrl: app.urls.error,
1249
1397
  providerScope: (0, _stackframe_stack_shared_dist_utils_strings.mergeScopeStrings)(scopeString, (app._oauthScopesOnSignIn[provider] ?? []).join(" "))
1250
1398
  }, session);
@@ -1778,10 +1926,17 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1778
1926
  }
1779
1927
  async _isTrusted(url) {
1780
1928
  if ((0, _stackframe_stack_shared_dist_utils_urls.isRelative)(url)) return true;
1781
- if (typeof window !== "undefined" && window.location.origin === new URL(url).origin) return true;
1782
- return (0, ______url_targets_js.isHostedHandlerUrlForProject)({
1929
+ const parsedUrl = (0, _stackframe_stack_shared_dist_utils_urls.createUrlIfValid)(url);
1930
+ if (parsedUrl == null) return false;
1931
+ if (typeof window !== "undefined" && window.location.origin === parsedUrl.origin) return true;
1932
+ if ((0, ______url_targets_js.isHostedHandlerUrlForProject)({
1783
1933
  url,
1784
1934
  projectId: this.projectId
1935
+ })) return true;
1936
+ const trustedRedirectConfig = await this._getTrustedRedirectConfig();
1937
+ return (0, _stackframe_stack_shared_dist_utils_redirect_urls.validateRedirectUrl)(parsedUrl, {
1938
+ allowLocalhost: trustedRedirectConfig.allowLocalhost,
1939
+ trustedDomains: trustedRedirectConfig.trustedDomains
1785
1940
  });
1786
1941
  }
1787
1942
  get urls() {
@@ -1830,6 +1985,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1830
1985
  };
1831
1986
  }
1832
1987
  _getLocalOAuthCallbackHandlerUrl() {
1988
+ if (this._isOAuthCallbackUrlHosted()) return this._getOAuthCallbackRedirectUri();
1833
1989
  return (0, ______url_targets_js.resolveHandlerUrls)({
1834
1990
  urls: {
1835
1991
  ...this._urlOptions,
@@ -1840,7 +1996,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1840
1996
  }).oauthCallback;
1841
1997
  }
1842
1998
  async _createCrossDomainAuthRedirectUrl(options) {
1843
- const session = await this._getSession();
1999
+ const session = await this._getSession(void 0, { awaitPendingAuthResolutions: options.awaitPendingAuthResolutions });
1844
2000
  const response = await this._interface.sendClientRequest("/auth/oauth/cross-domain/authorize", {
1845
2001
  method: "POST",
1846
2002
  headers: { "Content-Type": "application/json" },
@@ -1894,7 +2050,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1894
2050
  ...options
1895
2051
  });
1896
2052
  }
1897
- async _redirectToHandler(handlerName, options) {
2053
+ async _redirectToHandler(handlerName, options, internalOptions) {
1898
2054
  const rawHandlerUrl = (0, __common_js.getUrls)(this._urlOptions, { projectId: this.projectId })[handlerName];
1899
2055
  if (!rawHandlerUrl) throw new Error(`No URL for handler name ${handlerName}`);
1900
2056
  const currentUrl = typeof window === "undefined" ? null : new URL(window.location.href);
@@ -1911,7 +2067,8 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1911
2067
  redirectUri: plan.redirectUri,
1912
2068
  state: plan.state,
1913
2069
  codeChallenge: plan.codeChallenge,
1914
- afterCallbackRedirectUrl: plan.afterCallbackRedirectUrl
2070
+ afterCallbackRedirectUrl: plan.afterCallbackRedirectUrl,
2071
+ awaitPendingAuthResolutions: internalOptions?.awaitPendingAuthResolutions
1915
2072
  });
1916
2073
  await this._redirectTo({
1917
2074
  url: crossDomainRedirectUrl,
@@ -1919,7 +2076,12 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
1919
2076
  });
1920
2077
  return;
1921
2078
  }
1922
- await this._redirectIfTrusted(plan.url, options);
2079
+ const redirectUrl = currentUrl != null && handlerName !== "signOut" && handlerName !== "afterSignOut" && handlerName !== "oauthCallback" ? await this._addNestedCrossDomainAuthParamsToRedirectUrl({
2080
+ url: plan.url,
2081
+ currentUrl,
2082
+ awaitPendingAuthResolutions: internalOptions?.awaitPendingAuthResolutions
2083
+ }) : plan.url;
2084
+ await this._redirectIfTrusted(redirectUrl, options);
1923
2085
  }
1924
2086
  _redirectToHandlerDuringRender(handlerName, options) {
1925
2087
  if (this._redirectMethod === "tanstack-start" && !(0, _stackframe_stack_shared_dist_utils_env.isBrowserLike)()) {
@@ -2176,7 +2338,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2176
2338
  const executeOAuth = async (challenge) => {
2177
2339
  return await this._interface.authorizeOAuth({
2178
2340
  provider,
2179
- redirectUrl: (0, ____________utils_url_js.constructRedirectUrl)(this.urls.oauthCallback, "redirectUrl"),
2341
+ redirectUrl: (0, ____________utils_url_js.constructRedirectUrl)(this._getOAuthCallbackRedirectUri(), "redirectUrl"),
2180
2342
  errorRedirectUrl: (0, ____________utils_url_js.constructRedirectUrl)(this.urls.error, "errorRedirectUrl"),
2181
2343
  afterCallbackRedirectUrl,
2182
2344
  type: "authenticate",
@@ -2224,7 +2386,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2224
2386
  try {
2225
2387
  return await callback();
2226
2388
  } catch (e) {
2227
- if (_stackframe_stack_shared.KnownErrors.MultiFactorAuthenticationRequired.isInstance(e)) return _stackframe_stack_shared_dist_utils_results.Result.ok(await this._experimentalMfa(e, await this._getSession()));
2389
+ if (_stackframe_stack_shared.KnownErrors.MultiFactorAuthenticationRequired.isInstance(e)) return _stackframe_stack_shared_dist_utils_results.Result.ok(await this._experimentalMfa(e, await this._getSession(void 0, { awaitPendingAuthResolutions: false })));
2228
2390
  throw e;
2229
2391
  }
2230
2392
  }
@@ -2299,8 +2461,8 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2299
2461
  }
2300
2462
  if (result.status === "ok") {
2301
2463
  await this._signInToAccountWithTokens(result.data);
2302
- if (!options?.noRedirect) if (result.data.newUser) await this.redirectToAfterSignUp({ replace: true });
2303
- else await this.redirectToAfterSignIn({ replace: true });
2464
+ if (!options?.noRedirect) if (result.data.newUser) await this._redirectToHandler("afterSignUp", { replace: true }, { awaitPendingAuthResolutions: false });
2465
+ else await this._redirectToHandler("afterSignIn", { replace: true }, { awaitPendingAuthResolutions: false });
2304
2466
  return _stackframe_stack_shared_dist_utils_results.Result.ok(void 0);
2305
2467
  } else return _stackframe_stack_shared_dist_utils_results.Result.error(result.error);
2306
2468
  }
@@ -2415,10 +2577,10 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2415
2577
  return _stackframe_stack_shared_dist_utils_results.Result.ok(void 0);
2416
2578
  } else return _stackframe_stack_shared_dist_utils_results.Result.error(result.error);
2417
2579
  }
2418
- async callOAuthCallback() {
2580
+ async callOAuthCallback(options) {
2419
2581
  if (typeof window === "undefined") throw new Error("callOAuthCallback can currently only be called in a browser environment");
2420
- this._ensurePersistentTokenStore();
2421
- let oauthCallbackRedirectUri = this.urls.oauthCallback;
2582
+ if (this._currentUrlLooksLikeOAuthCallback()) this._ensurePersistentTokenStore();
2583
+ let oauthCallbackRedirectUri = this._getOAuthCallbackRedirectUri();
2422
2584
  const currentUrl = new URL(window.location.href);
2423
2585
  if (currentUrl.searchParams.get(__redirect_page_urls_js.crossDomainAuthQueryParams.marker) === "1") {
2424
2586
  currentUrl.searchParams.delete("code");
@@ -2428,7 +2590,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2428
2590
  let result;
2429
2591
  try {
2430
2592
  result = await this._catchMfaRequiredError(async () => {
2431
- return await (0, _________auth_js.callOAuthCallback)(this._interface, oauthCallbackRedirectUri);
2593
+ return await (0, _________auth_js.callOAuthCallback)(this._interface, oauthCallbackRedirectUri, options);
2432
2594
  });
2433
2595
  } catch (e) {
2434
2596
  if (_stackframe_stack_shared.KnownErrors.InvalidTotpCode.isInstance(e)) {
@@ -2437,6 +2599,7 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2437
2599
  } else throw e;
2438
2600
  }
2439
2601
  if (result.status === "ok" && result.data) {
2602
+ this._ensurePersistentTokenStore();
2440
2603
  await this._signInToAccountWithTokens(result.data);
2441
2604
  if ("afterCallbackRedirectUrl" in result.data && result.data.afterCallbackRedirectUrl) {
2442
2605
  await this._redirectTo({
@@ -2445,10 +2608,10 @@ var _StackClientAppImplIncomplete = class _StackClientAppImplIncomplete {
2445
2608
  });
2446
2609
  return true;
2447
2610
  } else if (result.data.newUser) {
2448
- await this.redirectToAfterSignUp({ replace: true });
2611
+ await this._redirectToHandler("afterSignUp", { replace: true }, { awaitPendingAuthResolutions: false });
2449
2612
  return true;
2450
2613
  } else {
2451
- await this.redirectToAfterSignIn({ replace: true });
2614
+ await this._redirectToHandler("afterSignIn", { replace: true }, { awaitPendingAuthResolutions: false });
2452
2615
  return true;
2453
2616
  }
2454
2617
  }