@burdenoff/microfe-auth 2026.522.1 → 2026.524.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useOAuthOperations.d.ts","sourceRoot":"","sources":["../../../src/auth/hooks/useOAuthOperations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,UAAU,CAAC;AAgBvD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AAyC9D;;GAEG;AACH,wBAAgB,kBAAkB;8BAWC,aAAa;0BAuDtC,MAAM,SACL,MAAM,KACZ,OAAO,CAAC,UAAU,CAAC;;;;qCAmGkB,aAAa,KAAG,OAAO;;EAoBhE"}
1
+ {"version":3,"file":"useOAuthOperations.d.ts","sourceRoot":"","sources":["../../../src/auth/hooks/useOAuthOperations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,UAAU,CAAC;AAgBvD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;AA0G9D;;GAEG;AACH,wBAAgB,kBAAkB;8BAWC,aAAa;0BA+DtC,MAAM,SACL,MAAM,KACZ,OAAO,CAAC,UAAU,CAAC;;;;qCAmGkB,aAAa,KAAG,OAAO;;EAoBhE"}
@@ -33,7 +33,24 @@ function a() {
33
33
  return crypto.getRandomValues(e), Array.from(e, (e) => e.toString(16).padStart(2, "0")).join("");
34
34
  }
35
35
  function o() {
36
- let o = e(), [s, { loading: c }] = r(n), l = (e) => {
36
+ if (typeof window > "u") return !1;
37
+ let e = window;
38
+ if (typeof e.Capacitor?.isNativePlatform == "function") try {
39
+ if (e.Capacitor.isNativePlatform()) return !0;
40
+ } catch {}
41
+ return !!(typeof navigator < "u" && /Electron/i.test(navigator.userAgent || ""));
42
+ }
43
+ var s = "vibecontrols://app/auth/oauth/callback";
44
+ async function c(e) {
45
+ if (typeof window > "u") return;
46
+ let t = window.__burdenoffOpenExternal;
47
+ if (typeof t == "function") try {
48
+ if (await t(e)) return;
49
+ } catch {}
50
+ window.location.href = e;
51
+ }
52
+ function l() {
53
+ let l = e(), [u, { loading: d }] = r(n), f = (e) => {
37
54
  let t = i[e], n = {
38
55
  VITE_GOOGLE_CLIENT_ID: void 0,
39
56
  VITE_GITHUB_CLIENT_ID: void 0,
@@ -42,43 +59,43 @@ function o() {
42
59
  if (!n) throw console.error(`OAuth client ID not configured for ${e}`), Error(`${e} OAuth is not configured. Please set ${t.clientIdEnvKey} environment variable.`);
43
60
  let r = a();
44
61
  localStorage.setItem("oauth_state", r), localStorage.setItem("oauth_provider", e);
45
- let o = `${window.location.origin}/auth/oauth/callback`;
46
- localStorage.setItem("oauth_redirect_uri", o);
47
- let s = new URLSearchParams({
62
+ let l = o() ? s : `${window.location.origin}/auth/oauth/callback`;
63
+ localStorage.setItem("oauth_redirect_uri", l);
64
+ let u = new URLSearchParams({
48
65
  client_id: n,
49
- redirect_uri: o,
66
+ redirect_uri: l,
50
67
  response_type: "code",
51
68
  scope: t.scopes.join(" "),
52
69
  state: r,
53
70
  ...e === "google" && { prompt: "select_account" },
54
71
  ...e === "google" && { access_type: "offline" }
55
- }), c = `${t.authorizationUrl}?${s.toString()}`;
56
- window.location.href = c;
72
+ });
73
+ c(`${t.authorizationUrl}?${u.toString()}`);
57
74
  };
58
75
  return {
59
- initiateOAuth: l,
76
+ initiateOAuth: f,
60
77
  completeOAuth: async (e, n) => {
61
78
  let r = t.getState(), i = localStorage.getItem("oauth_state");
62
79
  if (!i || i !== n) throw console.error("[OAuth Complete] State mismatch!", {
63
80
  storedState: i,
64
81
  urlState: n
65
82
  }), Error("Invalid OAuth state. Please try again.");
66
- let a = localStorage.getItem("oauth_provider"), c = localStorage.getItem("oauth_redirect_uri");
67
- if (!a || !c) throw console.error("[OAuth Complete] Missing provider or redirectUri"), Error("OAuth session data missing. Please try again.");
83
+ let a = localStorage.getItem("oauth_provider"), o = localStorage.getItem("oauth_redirect_uri");
84
+ if (!a || !o) throw console.error("[OAuth Complete] Missing provider or redirectUri"), Error("OAuth session data missing. Please try again.");
68
85
  localStorage.removeItem("oauth_state"), localStorage.removeItem("oauth_provider"), localStorage.removeItem("oauth_redirect_uri");
69
86
  try {
70
87
  r.setLoading(!0), r.setError(null);
71
- let { data: t, error: n } = await s({ variables: { input: {
88
+ let { data: t, error: n } = await u({ variables: { input: {
72
89
  provider: a.toUpperCase(),
73
90
  code: e,
74
- redirectUri: c
91
+ redirectUri: o
75
92
  } } });
76
93
  if (!t?.authenticateOAuth) {
77
94
  let e = n?.message ?? "OAuth authentication failed. Please try again.";
78
95
  throw Error(e);
79
96
  }
80
97
  let i = t.authenticateOAuth;
81
- return i.requiresMFA ? (r.setMfaRequired(!0, i.mfaChallengeId || void 0), i) : (i.success && i.user && i.token ? (r.setUser(i.user), r.setAuthTokens(i.token, i.refreshToken || ""), r.setAuthenticated(!0), r.setMfaRequired(!1), o.onAuthSuccess?.(i.user, i.token, i.refreshToken || void 0)) : i.error && r.setError(i.error), i);
98
+ return i.requiresMFA ? (r.setMfaRequired(!0, i.mfaChallengeId || void 0), i) : (i.success && i.user && i.token ? (r.setUser(i.user), r.setAuthTokens(i.token, i.refreshToken || ""), r.setAuthenticated(!0), r.setMfaRequired(!1), l.onAuthSuccess?.(i.user, i.token, i.refreshToken || void 0)) : i.error && r.setError(i.error), i);
82
99
  } catch (e) {
83
100
  let t = e instanceof Error ? e.message : "OAuth authentication failed";
84
101
  throw r.setError(t), e;
@@ -86,18 +103,18 @@ function o() {
86
103
  r.setLoading(!1);
87
104
  }
88
105
  },
89
- initiateGoogleOAuth: () => l("google"),
90
- initiateGitHubOAuth: () => l("github"),
91
- initiateMicrosoftOAuth: () => l("microsoft"),
106
+ initiateGoogleOAuth: () => f("google"),
107
+ initiateGitHubOAuth: () => f("github"),
108
+ initiateMicrosoftOAuth: () => f("microsoft"),
92
109
  isProviderConfigured: (e) => !!{
93
110
  VITE_GOOGLE_CLIENT_ID: void 0,
94
111
  VITE_GITHUB_CLIENT_ID: void 0,
95
112
  VITE_MICROSOFT_CLIENT_ID: void 0
96
113
  }[i[e].clientIdEnvKey],
97
- isLoading: c
114
+ isLoading: d
98
115
  };
99
116
  }
100
117
  //#endregion
101
- export { o as useOAuthOperations };
118
+ export { l as useOAuthOperations };
102
119
 
103
120
  //# sourceMappingURL=useOAuthOperations.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useOAuthOperations.js","names":[],"sources":["../../../src/auth/hooks/useOAuthOperations.ts"],"sourcesContent":["import { useMutation } from \"@apollo/client/react\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport type { AuthResult, OAuthInput } from \"../types\";\n\nimport { AuthenticateOAuthDocument } from \"../../generated/global-operations\";\n\n// =============================================================================\n// GRAPHQL RESPONSE INTERFACES\n// =============================================================================\n\ninterface AuthenticateOAuthResponse {\n authenticateOAuth: AuthResult;\n}\n\ninterface AuthenticateOAuthVariables {\n input: OAuthInput;\n}\n\n/**\n * Supported OAuth providers\n */\nexport type OAuthProvider = \"google\" | \"github\" | \"microsoft\";\n\n/**\n * OAuth configuration for each provider\n */\ninterface OAuthConfig {\n authorizationUrl: string;\n scopes: string[];\n clientIdEnvKey: string;\n}\n\nconst OAUTH_CONFIGS: Record<OAuthProvider, OAuthConfig> = {\n google: {\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n scopes: [\"openid\", \"email\", \"profile\"],\n clientIdEnvKey: \"VITE_GOOGLE_CLIENT_ID\",\n },\n github: {\n authorizationUrl: \"https://github.com/login/oauth/authorize\",\n scopes: [\"user:email\", \"read:user\"],\n clientIdEnvKey: \"VITE_GITHUB_CLIENT_ID\",\n },\n microsoft: {\n authorizationUrl:\n \"https://login.microsoftonline.com/common/oauth2/v2.0/authorize\",\n scopes: [\"openid\", \"email\", \"profile\"],\n clientIdEnvKey: \"VITE_MICROSOFT_CLIENT_ID\",\n },\n};\n\n/**\n * Generate a random state parameter for CSRF protection\n */\nfunction generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\n/**\n * Hook for OAuth authentication operations\n */\nexport function useOAuthOperations() {\n const context = useAuth();\n const [authenticateOAuthMutation, { loading }] = useMutation<\n AuthenticateOAuthResponse,\n AuthenticateOAuthVariables\n >(AuthenticateOAuthDocument);\n\n /**\n * Initiate OAuth flow by redirecting to the provider\n * @param provider - The OAuth provider to use\n */\n const initiateOAuth = (provider: OAuthProvider) => {\n const config = OAUTH_CONFIGS[provider];\n\n // Get client ID from environment\n // In Vite, environment variables are accessed via import.meta.env\n const envVars: Record<string, string | undefined> = {\n VITE_GOOGLE_CLIENT_ID: import.meta.env.VITE_GOOGLE_CLIENT_ID,\n VITE_GITHUB_CLIENT_ID: import.meta.env.VITE_GITHUB_CLIENT_ID,\n VITE_MICROSOFT_CLIENT_ID: import.meta.env.VITE_MICROSOFT_CLIENT_ID,\n };\n const clientId = envVars[config.clientIdEnvKey];\n\n if (!clientId) {\n console.error(`OAuth client ID not configured for ${provider}`);\n throw new Error(\n `${provider} OAuth is not configured. Please set ${config.clientIdEnvKey} environment variable.`,\n );\n }\n\n // Generate state for CSRF protection and store it\n // Use localStorage instead of sessionStorage for better persistence across redirects\n const state = generateState();\n localStorage.setItem(\"oauth_state\", state);\n localStorage.setItem(\"oauth_provider\", provider);\n\n // Build redirect URI - use current origin + callback path\n const redirectUri = `${window.location.origin}/auth/oauth/callback`;\n localStorage.setItem(\"oauth_redirect_uri\", redirectUri);\n\n // Build authorization URL\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n scope: config.scopes.join(\" \"),\n state: state,\n // Google-specific: force account selection\n ...(provider === \"google\" && { prompt: \"select_account\" }),\n // Google-specific: enable offline access for refresh token\n ...(provider === \"google\" && { access_type: \"offline\" }),\n });\n\n const authUrl = `${config.authorizationUrl}?${params.toString()}`;\n\n // Redirect to OAuth provider\n window.location.href = authUrl;\n };\n\n /**\n * Complete OAuth flow by exchanging authorization code for tokens\n * Called from the callback page after provider redirects back\n * @param code - Authorization code from OAuth provider\n * @param state - State parameter for CSRF validation\n */\n const completeOAuth = async (\n code: string,\n state: string,\n ): Promise<AuthResult> => {\n const store = useAuthStore.getState();\n\n // Validate state parameter\n const storedState = localStorage.getItem(\"oauth_state\");\n if (!storedState || storedState !== state) {\n console.error(\"[OAuth Complete] State mismatch!\", {\n storedState,\n urlState: state,\n });\n throw new Error(\"Invalid OAuth state. Please try again.\");\n }\n\n // Get provider and redirect URI from localStorage\n const provider = localStorage.getItem(\"oauth_provider\") as OAuthProvider;\n const redirectUri = localStorage.getItem(\"oauth_redirect_uri\");\n\n if (!provider || !redirectUri) {\n console.error(\"[OAuth Complete] Missing provider or redirectUri\");\n throw new Error(\"OAuth session data missing. Please try again.\");\n }\n\n // Clear localStorage\n localStorage.removeItem(\"oauth_state\");\n localStorage.removeItem(\"oauth_provider\");\n localStorage.removeItem(\"oauth_redirect_uri\");\n\n try {\n store.setLoading(true);\n store.setError(null);\n\n // Call backend mutation to exchange code for tokens\n const { data, error } = await authenticateOAuthMutation({\n variables: {\n input: {\n provider: provider.toUpperCase(),\n code,\n redirectUri,\n },\n },\n });\n\n if (!data?.authenticateOAuth) {\n const errMsg =\n error?.message ?? \"OAuth authentication failed. Please try again.\";\n throw new Error(errMsg);\n }\n\n const result = data.authenticateOAuth;\n\n if (result.requiresMFA) {\n store.setMfaRequired(true, result.mfaChallengeId || undefined);\n return result;\n }\n\n if (result.success && result.user && result.token) {\n store.setUser(result.user);\n store.setAuthTokens(result.token, result.refreshToken || \"\");\n store.setAuthenticated(true);\n store.setMfaRequired(false);\n\n context.onAuthSuccess?.(\n result.user,\n result.token,\n result.refreshToken || undefined,\n );\n } else if (result.error) {\n store.setError(result.error);\n }\n\n return result;\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"OAuth authentication failed\";\n store.setError(message);\n throw err;\n } finally {\n store.setLoading(false);\n }\n };\n\n /**\n * Convenience method to initiate Google OAuth\n */\n const initiateGoogleOAuth = () => initiateOAuth(\"google\");\n\n /**\n * Convenience method to initiate GitHub OAuth\n */\n const initiateGitHubOAuth = () => initiateOAuth(\"github\");\n\n /**\n * Convenience method to initiate Microsoft OAuth\n */\n const initiateMicrosoftOAuth = () => initiateOAuth(\"microsoft\");\n\n /**\n * Check if a provider is configured (has client ID)\n */\n const isProviderConfigured = (provider: OAuthProvider): boolean => {\n const envVars: Record<string, string | undefined> = {\n VITE_GOOGLE_CLIENT_ID: import.meta.env.VITE_GOOGLE_CLIENT_ID,\n VITE_GITHUB_CLIENT_ID: import.meta.env.VITE_GITHUB_CLIENT_ID,\n VITE_MICROSOFT_CLIENT_ID: import.meta.env.VITE_MICROSOFT_CLIENT_ID,\n };\n const config = OAUTH_CONFIGS[provider];\n const clientId = envVars[config.clientIdEnvKey];\n return !!clientId;\n };\n\n return {\n initiateOAuth,\n completeOAuth,\n initiateGoogleOAuth,\n initiateGitHubOAuth,\n initiateMicrosoftOAuth,\n isProviderConfigured,\n isLoading: loading,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useOAuthOperations.js","names":[],"sources":["../../../src/auth/hooks/useOAuthOperations.ts"],"sourcesContent":["import { useMutation } from \"@apollo/client/react\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { useAuth } from \"../providers/AuthProvider\";\nimport type { AuthResult, OAuthInput } from \"../types\";\n\nimport { AuthenticateOAuthDocument } from \"../../generated/global-operations\";\n\n// =============================================================================\n// GRAPHQL RESPONSE INTERFACES\n// =============================================================================\n\ninterface AuthenticateOAuthResponse {\n authenticateOAuth: AuthResult;\n}\n\ninterface AuthenticateOAuthVariables {\n input: OAuthInput;\n}\n\n/**\n * Supported OAuth providers\n */\nexport type OAuthProvider = \"google\" | \"github\" | \"microsoft\";\n\n/**\n * OAuth configuration for each provider\n */\ninterface OAuthConfig {\n authorizationUrl: string;\n scopes: string[];\n clientIdEnvKey: string;\n}\n\nconst OAUTH_CONFIGS: Record<OAuthProvider, OAuthConfig> = {\n google: {\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n scopes: [\"openid\", \"email\", \"profile\"],\n clientIdEnvKey: \"VITE_GOOGLE_CLIENT_ID\",\n },\n github: {\n authorizationUrl: \"https://github.com/login/oauth/authorize\",\n scopes: [\"user:email\", \"read:user\"],\n clientIdEnvKey: \"VITE_GITHUB_CLIENT_ID\",\n },\n microsoft: {\n authorizationUrl:\n \"https://login.microsoftonline.com/common/oauth2/v2.0/authorize\",\n scopes: [\"openid\", \"email\", \"profile\"],\n clientIdEnvKey: \"VITE_MICROSOFT_CLIENT_ID\",\n },\n};\n\n/**\n * Generate a random state parameter for CSRF protection\n */\nfunction generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return Array.from(array, (byte) => byte.toString(16).padStart(2, \"0\")).join(\n \"\",\n );\n}\n\n/**\n * Detect whether the bundle is running inside a native shell (Capacitor on\n * iOS/Android, or Electron). Mirrors the helper in LoginPage so OAuth\n * initiation can swap to a custom-scheme redirect_uri + system-browser\n * hand-off — the only flow OAuth providers will accept from a single-device\n * install.\n */\nfunction isNativeShell(): boolean {\n if (typeof window === \"undefined\") return false;\n const w = window as typeof window & {\n Capacitor?: { isNativePlatform?: () => boolean };\n };\n if (typeof w.Capacitor?.isNativePlatform === \"function\") {\n try {\n if (w.Capacitor.isNativePlatform()) return true;\n } catch {\n /* fall through */\n }\n }\n if (\n typeof navigator !== \"undefined\" &&\n /Electron/i.test(navigator.userAgent || \"\")\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * Custom-scheme redirect URI used in native shells. The scheme is registered\n * by the host shell (Electron `setAsDefaultProtocolClient`, iOS Info.plist\n * CFBundleURLTypes, Android intent-filter). The OS routes the provider's\n * callback back to the running app, which forwards it to React Router via\n * the host's deep-link handler.\n *\n * IMPORTANT: This redirect URI MUST be registered for the OAuth client in\n * each provider's console:\n * - Google Cloud Console → Credentials → OAuth client → add\n * `vibecontrols://app/auth/oauth/callback` (Installed App).\n * - Microsoft Entra App registration → Authentication → register the\n * same custom-scheme redirect URI as a mobile/desktop redirect.\n * The backend `authenticateOAuth` mutation must also accept this redirectUri\n * verbatim during the code exchange.\n */\nconst NATIVE_OAUTH_REDIRECT_URI = \"vibecontrols://app/auth/oauth/callback\";\n\nasync function openOAuthAuthorizationUrl(authUrl: string): Promise<void> {\n if (typeof window === \"undefined\") return;\n const opener = (\n window as typeof window & {\n __burdenoffOpenExternal?: (url: string) => Promise<boolean>;\n }\n ).__burdenoffOpenExternal;\n if (typeof opener === \"function\") {\n try {\n const ok = await opener(authUrl);\n if (ok) return;\n } catch {\n /* fall through to legacy hand-off */\n }\n }\n // Browser fallback: same-window navigation (current production behavior).\n window.location.href = authUrl;\n}\n\n/**\n * Hook for OAuth authentication operations\n */\nexport function useOAuthOperations() {\n const context = useAuth();\n const [authenticateOAuthMutation, { loading }] = useMutation<\n AuthenticateOAuthResponse,\n AuthenticateOAuthVariables\n >(AuthenticateOAuthDocument);\n\n /**\n * Initiate OAuth flow by redirecting to the provider\n * @param provider - The OAuth provider to use\n */\n const initiateOAuth = (provider: OAuthProvider) => {\n const config = OAUTH_CONFIGS[provider];\n\n // Get client ID from environment\n // In Vite, environment variables are accessed via import.meta.env\n const envVars: Record<string, string | undefined> = {\n VITE_GOOGLE_CLIENT_ID: import.meta.env.VITE_GOOGLE_CLIENT_ID,\n VITE_GITHUB_CLIENT_ID: import.meta.env.VITE_GITHUB_CLIENT_ID,\n VITE_MICROSOFT_CLIENT_ID: import.meta.env.VITE_MICROSOFT_CLIENT_ID,\n };\n const clientId = envVars[config.clientIdEnvKey];\n\n if (!clientId) {\n console.error(`OAuth client ID not configured for ${provider}`);\n throw new Error(\n `${provider} OAuth is not configured. Please set ${config.clientIdEnvKey} environment variable.`,\n );\n }\n\n // Generate state for CSRF protection and store it\n // Use localStorage instead of sessionStorage for better persistence across redirects\n const state = generateState();\n localStorage.setItem(\"oauth_state\", state);\n localStorage.setItem(\"oauth_provider\", provider);\n\n // Native shells (Electron, Capacitor) can't use the current origin as the\n // redirect_uri — `vibecontrols://app` / `https://localhost` aren't valid\n // registered URIs at OAuth providers. Use a custom-scheme URL that the\n // host shell has registered as a deep-link target; the OS will route the\n // provider's callback back into the running app.\n const redirectUri = isNativeShell()\n ? NATIVE_OAUTH_REDIRECT_URI\n : `${window.location.origin}/auth/oauth/callback`;\n localStorage.setItem(\"oauth_redirect_uri\", redirectUri);\n\n // Build authorization URL\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n scope: config.scopes.join(\" \"),\n state: state,\n // Google-specific: force account selection\n ...(provider === \"google\" && { prompt: \"select_account\" }),\n // Google-specific: enable offline access for refresh token\n ...(provider === \"google\" && { access_type: \"offline\" }),\n });\n\n const authUrl = `${config.authorizationUrl}?${params.toString()}`;\n\n // Hand off to the system browser in native shells (keeps the embedded\n // webview in place so the deep-link callback can return cleanly). On the\n // web this falls back to same-window navigation.\n void openOAuthAuthorizationUrl(authUrl);\n };\n\n /**\n * Complete OAuth flow by exchanging authorization code for tokens\n * Called from the callback page after provider redirects back\n * @param code - Authorization code from OAuth provider\n * @param state - State parameter for CSRF validation\n */\n const completeOAuth = async (\n code: string,\n state: string,\n ): Promise<AuthResult> => {\n const store = useAuthStore.getState();\n\n // Validate state parameter\n const storedState = localStorage.getItem(\"oauth_state\");\n if (!storedState || storedState !== state) {\n console.error(\"[OAuth Complete] State mismatch!\", {\n storedState,\n urlState: state,\n });\n throw new Error(\"Invalid OAuth state. Please try again.\");\n }\n\n // Get provider and redirect URI from localStorage\n const provider = localStorage.getItem(\"oauth_provider\") as OAuthProvider;\n const redirectUri = localStorage.getItem(\"oauth_redirect_uri\");\n\n if (!provider || !redirectUri) {\n console.error(\"[OAuth Complete] Missing provider or redirectUri\");\n throw new Error(\"OAuth session data missing. Please try again.\");\n }\n\n // Clear localStorage\n localStorage.removeItem(\"oauth_state\");\n localStorage.removeItem(\"oauth_provider\");\n localStorage.removeItem(\"oauth_redirect_uri\");\n\n try {\n store.setLoading(true);\n store.setError(null);\n\n // Call backend mutation to exchange code for tokens\n const { data, error } = await authenticateOAuthMutation({\n variables: {\n input: {\n provider: provider.toUpperCase(),\n code,\n redirectUri,\n },\n },\n });\n\n if (!data?.authenticateOAuth) {\n const errMsg =\n error?.message ?? \"OAuth authentication failed. Please try again.\";\n throw new Error(errMsg);\n }\n\n const result = data.authenticateOAuth;\n\n if (result.requiresMFA) {\n store.setMfaRequired(true, result.mfaChallengeId || undefined);\n return result;\n }\n\n if (result.success && result.user && result.token) {\n store.setUser(result.user);\n store.setAuthTokens(result.token, result.refreshToken || \"\");\n store.setAuthenticated(true);\n store.setMfaRequired(false);\n\n context.onAuthSuccess?.(\n result.user,\n result.token,\n result.refreshToken || undefined,\n );\n } else if (result.error) {\n store.setError(result.error);\n }\n\n return result;\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"OAuth authentication failed\";\n store.setError(message);\n throw err;\n } finally {\n store.setLoading(false);\n }\n };\n\n /**\n * Convenience method to initiate Google OAuth\n */\n const initiateGoogleOAuth = () => initiateOAuth(\"google\");\n\n /**\n * Convenience method to initiate GitHub OAuth\n */\n const initiateGitHubOAuth = () => initiateOAuth(\"github\");\n\n /**\n * Convenience method to initiate Microsoft OAuth\n */\n const initiateMicrosoftOAuth = () => initiateOAuth(\"microsoft\");\n\n /**\n * Check if a provider is configured (has client ID)\n */\n const isProviderConfigured = (provider: OAuthProvider): boolean => {\n const envVars: Record<string, string | undefined> = {\n VITE_GOOGLE_CLIENT_ID: import.meta.env.VITE_GOOGLE_CLIENT_ID,\n VITE_GITHUB_CLIENT_ID: import.meta.env.VITE_GITHUB_CLIENT_ID,\n VITE_MICROSOFT_CLIENT_ID: import.meta.env.VITE_MICROSOFT_CLIENT_ID,\n };\n const config = OAUTH_CONFIGS[provider];\n const clientId = envVars[config.clientIdEnvKey];\n return !!clientId;\n };\n\n return {\n initiateOAuth,\n completeOAuth,\n initiateGoogleOAuth,\n initiateGitHubOAuth,\n initiateMicrosoftOAuth,\n isProviderConfigured,\n isLoading: loading,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"LoginPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/LoginPage.tsx"],"names":[],"mappings":"AA4DA;;;GAGG;AACH,wBAAgB,SAAS,4CA4kCxB"}
1
+ {"version":3,"file":"LoginPage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/LoginPage.tsx"],"names":[],"mappings":"AAkGA;;;GAGG;AACH,wBAAgB,SAAS,4CAulCxB"}